Skip to content

Commit 20c2b2d

Browse files
committed
Update xUnit to display output on failures
The generated xUnit XML file is not helpful when tests fail as it contains the message "failure", which is redundant with the test results. Update the XML output to dipslay the result output instead of static "failure" message.
1 parent dca0cc2 commit 20c2b2d

File tree

11 files changed

+168
-5
lines changed

11 files changed

+168
-5
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.DS_Store
2+
/.build
3+
/.index-build
4+
/Packages
5+
xcuserdata/
6+
DerivedData/
7+
.swiftpm/configuration/registries.json
8+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
9+
.netrc
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// swift-tools-version: 5.9
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "TestFailuresSwiftTesting",
8+
products: [
9+
// Products define the executables and libraries a package produces, making them visible to other packages.
10+
.library(
11+
name: "TestFailuresSwiftTesting",
12+
targets: ["TestFailuresSwiftTesting"])
13+
],
14+
targets: [
15+
// Targets are the basic building blocks of a package, defining a module or a test suite.
16+
// Targets can depend on other targets in this package and products from dependencies.
17+
.target(
18+
name: "TestFailuresSwiftTesting"),
19+
.testTarget(
20+
name: "TestFailuresSwiftTestingTests",
21+
dependencies: ["TestFailuresSwiftTesting"]
22+
)
23+
]
24+
)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// The Swift Programming Language
2+
// https://docs.swift.org/swift-book
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import Testing
2+
@testable import TestFailuresSwiftTesting
3+
4+
@Test func example() async throws {
5+
#expect(Bool(false), "Purposely failing & validating XML espace \"'<>")
6+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.DS_Store
2+
/.build
3+
/.index-build
4+
/Packages
5+
xcuserdata/
6+
DerivedData/
7+
.swiftpm/configuration/registries.json
8+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
9+
.netrc
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// swift-tools-version: 5.9
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "TestFailures",
8+
products: [
9+
// Products define the executables and libraries a package produces, making them visible to other packages.
10+
.library(
11+
name: "TestFailures",
12+
targets: ["TestFailures"])
13+
],
14+
targets: [
15+
// Targets are the basic building blocks of a package, defining a module or a test suite.
16+
// Targets can depend on other targets in this package and products from dependencies.
17+
.target(
18+
name: "TestFailures"),
19+
.testTarget(
20+
name: "TestFailuresTests",
21+
dependencies: ["TestFailures"]
22+
)
23+
]
24+
)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// The Swift Programming Language
2+
// https://docs.swift.org/swift-book
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import XCTest
2+
@testable import TestFailures
3+
4+
final class TestFailuresTests: XCTestCase {
5+
func testExample() throws {
6+
XCTAssertFalse(true, "Purposely failing & validating XML espace \"'<>")
7+
}
8+
}
9+

Sources/Commands/SwiftTestCommand.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1399,7 +1399,12 @@ final class XUnitGenerator {
13991399
"""
14001400

14011401
if !result.success {
1402-
content += "<failure message=\"failed\"></failure>\n"
1402+
var failureMessage = result.output
1403+
failureMessage.replace("&", with: "&amp;")
1404+
failureMessage.replace("\"", with:"&quot;")
1405+
failureMessage.replace(">", with: "&gt;")
1406+
failureMessage.replace("<", with: "&lt;")
1407+
content += "<failure message=\"\(failureMessage)\"></failure>\n"
14031408
}
14041409

14051410
content += "</testcase>\n"

Sources/_InternalTestSupport/SwiftPMProduct.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ extension SwiftPM {
8282
public func execute(
8383
_ args: [String] = [],
8484
packagePath: AbsolutePath? = nil,
85-
env: Environment? = nil
85+
env: Environment? = nil,
86+
errorIfCommandUnsuccessful: Bool = true
8687
) async throws -> (stdout: String, stderr: String) {
8788
let result = try await executeProcess(
8889
args,
@@ -93,8 +94,11 @@ extension SwiftPM {
9394
let stdout = try result.utf8Output()
9495
let stderr = try result.utf8stderrOutput()
9596

97+
let returnValue = (stdout: stdout, stderr: stderr)
98+
if (!errorIfCommandUnsuccessful) { return returnValue }
99+
96100
if result.exitStatus == .terminated(code: 0) {
97-
return (stdout: stdout, stderr: stderr)
101+
return returnValue
98102
}
99103
throw SwiftPMError.executionFailure(
100104
underlying: AsyncProcessResult.Error.nonZeroExit(result),

0 commit comments

Comments
 (0)