From 340f29c2d37edfad5dd9abf1343f6e621df83972 Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Thu, 18 Jul 2024 15:10:26 -0400 Subject: [PATCH 1/3] Don't stomp on xUnit output from XCTest when running Swift Testing. This PR forces Swift Testing to write its xUnit output to a different path from what the user specifies. In the future, we should have the two testing libraries collate their XML output into a single file, but that requires the ability to parse and reformat XML output and that's a little beyond the capabilities of this feature right now. Since we expect most uses of xUnit output right now are existing ones with existing XCTest-based tests, moving Swift Testing aside seems like the right call. (If XCTest is explicitly disabled, the exact specified path is used.) --- Sources/Commands/SwiftTestCommand.swift | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Sources/Commands/SwiftTestCommand.swift b/Sources/Commands/SwiftTestCommand.swift index a441a31f9c0..ea8aab006c9 100644 --- a/Sources/Commands/SwiftTestCommand.swift +++ b/Sources/Commands/SwiftTestCommand.swift @@ -453,8 +453,25 @@ public struct SwiftTestCommand: AsyncSwiftCommand { ) async throws -> TestRunner.Result { // Pass through all arguments from the command line to Swift Testing. var additionalArguments = additionalArguments - if library == .swiftTesting { - additionalArguments += CommandLine.arguments.dropFirst() + if library == .swiftTesting && options.testLibraryOptions.isEnabled(.xctest) { + // We are running Swift Testing, and XCTest is also running in this session. Make sure + // we don't stomp on XCTest's XML output by having Swift Testing write to a different path. + var commandLineArguments = Array(CommandLine.arguments.dropFirst()) + if let xunitArgIndex = commandLineArguments.firstIndex(of: "--xunit-output"), + case let xunitPathIndex = commandLineArguments.index(after: xunitArgIndex), + xunitPathIndex < commandLineArguments.endIndex { + // Don't know if the path is relative or absolute, so use URL instead. + var xunitPath = URL(fileURLWithPath: commandLineArguments[xunitPathIndex], isDirectory: false) + let basename = xunitPath.deletingPathExtension().lastPathComponent + let ext = xunitPath.pathExtension + xunitPath.deleteLastPathComponent() + xunitPath.append(component: "\(basename)-swift-testing", directoryHint: .notDirectory) + if !ext.isEmpty { + xunitPath.appendPathExtension(ext) + } + commandLineArguments[xunitPathIndex] = xunitPath.path() + } + additionalArguments += commandLineArguments } let toolchain = try swiftCommandState.getTargetToolchain() From c450d36eb0fd5f50e8b91d7527790e759ca763a2 Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Thu, 18 Jul 2024 16:16:10 -0400 Subject: [PATCH 2/3] Rethink the algorithm --- Sources/Commands/SwiftTestCommand.swift | 37 ++++++++++++++----------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/Sources/Commands/SwiftTestCommand.swift b/Sources/Commands/SwiftTestCommand.swift index ea8aab006c9..0ceeae955ec 100644 --- a/Sources/Commands/SwiftTestCommand.swift +++ b/Sources/Commands/SwiftTestCommand.swift @@ -453,25 +453,30 @@ public struct SwiftTestCommand: AsyncSwiftCommand { ) async throws -> TestRunner.Result { // Pass through all arguments from the command line to Swift Testing. var additionalArguments = additionalArguments - if library == .swiftTesting && options.testLibraryOptions.isEnabled(.xctest) { - // We are running Swift Testing, and XCTest is also running in this session. Make sure - // we don't stomp on XCTest's XML output by having Swift Testing write to a different path. - var commandLineArguments = Array(CommandLine.arguments.dropFirst()) - if let xunitArgIndex = commandLineArguments.firstIndex(of: "--xunit-output"), - case let xunitPathIndex = commandLineArguments.index(after: xunitArgIndex), - xunitPathIndex < commandLineArguments.endIndex { - // Don't know if the path is relative or absolute, so use URL instead. - var xunitPath = URL(fileURLWithPath: commandLineArguments[xunitPathIndex], isDirectory: false) - let basename = xunitPath.deletingPathExtension().lastPathComponent - let ext = xunitPath.pathExtension - xunitPath.deleteLastPathComponent() - xunitPath.append(component: "\(basename)-swift-testing", directoryHint: .notDirectory) - if !ext.isEmpty { - xunitPath.appendPathExtension(ext) + if library == .swiftTesting { + // Reconstruct the arguments list. If an xUnit path was specified, remove it. + var commandLineArguments = [String]() + var originalCommandLineArguments = CommandLine.arguments.dropFirst().makeIterator() + while let arg = originalCommandLineArguments.next() { + if arg == "--xunit-output" { + _ = originalCommandLineArguments.next() + } else { + commandLineArguments.append(arg) } - commandLineArguments[xunitPathIndex] = xunitPath.path() } additionalArguments += commandLineArguments + + if var xunitPath, options.testLibraryOptions.isEnabled(.xctest) { + // We are running Swift Testing, XCTest is also running in this session, and an xUnit path + // was specified. Make sure we don't stomp on XCTest's XML output by having Swift Testing + // write to a different path. + var xunitFileName = "\(xunitPath.basenameWithoutExt)-swift-testing" + if let ext = xunitPath.extension { + xunitFileName = "\(xunitFileName).\(ext)" + } + xunitPath = xunitPath.parentDirectory.appending(xunitFileName) + additionalArguments += ["--xunit-output", xunitPath.pathString] + } } let toolchain = try swiftCommandState.getTargetToolchain() From 539d886b4593b0de50ee64829232a8f533542cd3 Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Thu, 18 Jul 2024 16:27:08 -0400 Subject: [PATCH 3/3] Fix typo --- Sources/Commands/SwiftTestCommand.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Commands/SwiftTestCommand.swift b/Sources/Commands/SwiftTestCommand.swift index 0ceeae955ec..f585ecc738d 100644 --- a/Sources/Commands/SwiftTestCommand.swift +++ b/Sources/Commands/SwiftTestCommand.swift @@ -466,7 +466,7 @@ public struct SwiftTestCommand: AsyncSwiftCommand { } additionalArguments += commandLineArguments - if var xunitPath, options.testLibraryOptions.isEnabled(.xctest) { + if var xunitPath = options.xUnitOutput, options.testLibraryOptions.isEnabled(.xctest) { // We are running Swift Testing, XCTest is also running in this session, and an xUnit path // was specified. Make sure we don't stomp on XCTest's XML output by having Swift Testing // write to a different path.