Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Fixtures/Miscellaneous/EchoExecutable/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ let package = Package(
.executable(name: "secho", targets: ["secho"])
],
targets: [
.target(name: "secho", dependencies: [])
])
.target(name: "secho", dependencies: []),
.testTarget(name: "TestSuite")
])
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import XCTest

final class TestCase: XCTestCase {
func testFoo() {
XCTAssertTrue(true)
}
}
4 changes: 4 additions & 0 deletions Fixtures/Miscellaneous/EchoExecutable/echo.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh

echo sentinel
echo "$@"
6 changes: 6 additions & 0 deletions Fixtures/Miscellaneous/EchoExecutable/toolset.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"debugger": { "path": "echo.sh" },
"testRunner": { "path": "echo.sh" },
"schemaVersion" : "1.0",
"rootPath" : "."
}
43 changes: 35 additions & 8 deletions Sources/Commands/SwiftRunCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,17 +169,28 @@ public struct SwiftRunCommand: AsyncSwiftCommand {
try await buildSystem.build(subset: .product(productName))
}

let executablePath = try swiftCommandState.productsBuildParameters.buildPath.appending(component: productName)
let productRelativePath = try swiftCommandState.productsBuildParameters.executablePath(for: productName)
let productAbsolutePath = try swiftCommandState.productsBuildParameters.buildPath.appending(productRelativePath)

// Make sure we are running from the original working directory.
let cwd: AbsolutePath? = swiftCommandState.fileSystem.currentWorkingDirectory
if cwd == nil || swiftCommandState.originalWorkingDirectory != cwd {
try ProcessEnv.chdir(swiftCommandState.originalWorkingDirectory)
}

let pathRelativeToWorkingDirectory = executablePath.relative(to: swiftCommandState.originalWorkingDirectory)
let lldbPath = try swiftCommandState.getTargetToolchain().getLLDB()
try exec(path: lldbPath.pathString, args: ["--", pathRelativeToWorkingDirectory.pathString] + options.arguments)
if let debugger = try swiftCommandState.getTargetToolchain().swiftSDK.toolset.knownTools[.debugger],
let debuggerPath = debugger.path {
try self.run(
fileSystem: swiftCommandState.fileSystem,
executablePath: debuggerPath,
originalWorkingDirectory: swiftCommandState.originalWorkingDirectory,
arguments: debugger.extraCLIOptions + [productAbsolutePath.pathString] + options.arguments
)
} else {
let pathRelativeToWorkingDirectory = productAbsolutePath.relative(to: swiftCommandState.originalWorkingDirectory)
let lldbPath = try swiftCommandState.getTargetToolchain().getLLDB()
try exec(path: lldbPath.pathString, args: ["--", pathRelativeToWorkingDirectory.pathString] + options.arguments)
}
} catch let error as RunError {
swiftCommandState.observabilityScope.emit(error)
throw ExitCode.failure
Expand Down Expand Up @@ -215,11 +226,27 @@ public struct SwiftRunCommand: AsyncSwiftCommand {
}

let executablePath = try swiftCommandState.productsBuildParameters.buildPath.appending(component: productName)

let productRelativePath = try swiftCommandState.productsBuildParameters.executablePath(for: productName)
let productAbsolutePath = try swiftCommandState.productsBuildParameters.buildPath.appending(productRelativePath)

let runnerPath: AbsolutePath
let arguments: [String]

if let debugger = try swiftCommandState.getTargetToolchain().swiftSDK.toolset.knownTools[.debugger],
let debuggerPath = debugger.path {
runnerPath = debuggerPath
arguments = debugger.extraCLIOptions + [productAbsolutePath.pathString] + options.arguments
} else {
runnerPath = executablePath
arguments = options.arguments
}

try self.run(
fileSystem: swiftCommandState.fileSystem,
executablePath: executablePath,
executablePath: runnerPath,
originalWorkingDirectory: swiftCommandState.originalWorkingDirectory,
arguments: options.arguments
arguments: arguments
)
} catch Diagnostics.fatalError {
throw ExitCode.failure
Expand Down Expand Up @@ -267,8 +294,8 @@ public struct SwiftRunCommand: AsyncSwiftCommand {
fileSystem: FileSystem,
executablePath: AbsolutePath,
originalWorkingDirectory: AbsolutePath,
arguments: [String]) throws
{
arguments: [String]
) throws {
// Make sure we are running from the original working directory.
let cwd: AbsolutePath? = fileSystem.currentWorkingDirectory
if cwd == nil || originalWorkingDirectory != cwd {
Expand Down
36 changes: 22 additions & 14 deletions Sources/Commands/SwiftTestCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -948,23 +948,31 @@ final class TestRunner {
/// Constructs arguments to execute XCTest.
private func args(forTestAt testPath: AbsolutePath) throws -> [String] {
var args: [String] = []

if let runner = self.toolchain.swiftSDK.toolset.knownTools[.testRunner], let runnerPath = runner.path {
args.append(runnerPath.pathString)
args.append(contentsOf: runner.extraCLIOptions)
args.append(testPath.relative(to: localFileSystem.currentWorkingDirectory!).pathString)
args.append(contentsOf: self.additionalArguments)
} else {
#if os(macOS)
switch library {
case .xctest:
guard let xctestPath = self.toolchain.xctestPath else {
throw TestError.xcodeNotInstalled
switch library {
case .xctest:
guard let xctestPath = self.toolchain.xctestPath else {
throw TestError.xcodeNotInstalled
}
args += [xctestPath.pathString]
case .swiftTesting:
let helper = try self.toolchain.getSwiftTestingHelper()
args += [helper.pathString, "--test-bundle-path", testPath.pathString]
}
args += [xctestPath.pathString]
case .swiftTesting:
let helper = try self.toolchain.getSwiftTestingHelper()
args += [helper.pathString, "--test-bundle-path", testPath.pathString]
args += self.additionalArguments
args += [testPath.pathString]
#else
args += [testPath.pathString]
args += self.additionalArguments
#endif
}
args += additionalArguments
args += [testPath.pathString]
#else
args += [testPath.pathString]
args += additionalArguments
#endif

if library == .swiftTesting {
// HACK: tell the test bundle/executable that we want to run Swift Testing, not XCTest.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ public struct BuildParameters: Encodable {
}

/// Returns the path to the executable of a product for the current build parameters.
private func executablePath(for name: String) throws -> RelativePath {
package func executablePath(for name: String) throws -> RelativePath {
try RelativePath(validating: "\(name)\(self.suffix)\(self.triple.executableExtension)")
}

Expand All @@ -302,9 +302,6 @@ public struct BuildParameters: Encodable {
case .library(.automatic), .plugin:
fatalError()
case .test:
guard !self.triple.isWasm else {
return try RelativePath(validating: "\(product.name).wasm")
}
let base = "\(product.name).xctest"
if self.triple.isDarwin() {
return try RelativePath(validating: "\(base)/Contents/MacOS/\(product.name)")
Expand Down
4 changes: 2 additions & 2 deletions Tests/BuildTests/CrossCompilationBuildPlanTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ final class CrossCompilationBuildPlanTests: XCTestCase {
[
result.plan.destinationBuildParameters.toolchain.swiftCompilerPath.pathString,
"-L", buildPath.pathString,
"-o", buildPath.appending(components: "PkgPackageTests.wasm").pathString,
"-o", buildPath.appending(components: "PkgPackageTests.xctest").pathString,
"-module-name", "PkgPackageTests",
"-emit-executable",
"@\(buildPath.appending(components: "PkgPackageTests.product", "Objects.LinkFileList"))",
Expand All @@ -220,7 +220,7 @@ final class CrossCompilationBuildPlanTests: XCTestCase {
)

let testPathExtension = try testBuildDescription.binaryPath.extension
XCTAssertEqual(testPathExtension, "wasm")
XCTAssertEqual(testPathExtension, "xctest")
}

func testMacros() async throws {
Expand Down
18 changes: 18 additions & 0 deletions Tests/CommandsTests/RunCommandTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,24 @@ final class RunCommandTests: CommandsTestCase {
XCTAssert(stdout.contains("Swift Package Manager"), "got stdout:\n" + stdout)
}

// echo.sh script from the toolset won't work on Windows
#if !os(Windows)
func testToolsetDebugger() async throws {
try await fixture(name: "Miscellaneous/EchoExecutable") { fixturePath in
let (stdout, stderr) = try await SwiftPM.Run.execute(
["--toolset", "\(fixturePath)/toolset.json"], packagePath: fixturePath)

// We only expect tool's output on the stdout stream.
XCTAssertMatch(stdout, .contains("\(fixturePath)/.build"))
XCTAssertMatch(stdout, .contains("sentinel"))

// swift-build-tool output should go to stderr.
XCTAssertMatch(stderr, .regex("Compiling"))
XCTAssertMatch(stderr, .contains("Linking"))
}
}
#endif

func testUnknownProductAndArgumentPassing() async throws {
try await fixture(name: "Miscellaneous/EchoExecutable") { fixturePath in
let (stdout, stderr) = try await SwiftPM.Run.execute(
Expand Down
18 changes: 18 additions & 0 deletions Tests/CommandsTests/TestCommandTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,24 @@ final class TestCommandTests: CommandsTestCase {
XCTAssert(stdout.contains("Swift Package Manager"), "got stdout:\n" + stdout)
}

// `runner.sh` script from the toolset won't work on Windows
#if !os(Windows)
func testToolsetRunner() async throws {
try await fixture(name: "Miscellaneous/EchoExecutable") { fixturePath in
let (stdout, stderr) = try await SwiftPM.Run.execute(
["--toolset", "\(fixturePath)/toolset.json"], packagePath: fixturePath)

// We only expect tool's output on the stdout stream.
XCTAssertMatch(stdout, .contains("\(fixturePath)/.build"))
XCTAssertMatch(stdout, .contains("sentinel"))

// swift-build-tool output should go to stderr.
XCTAssertMatch(stderr, .regex("Compiling"))
XCTAssertMatch(stderr, .contains("Linking"))
}
}
#endif

func testNumWorkersParallelRequirement() async throws {
#if !os(macOS)
// Running swift-test fixtures on linux is not yet possible.
Expand Down