diff --git a/Fixtures/Miscellaneous/EmptyTestsPkg/.gitignore b/Fixtures/Miscellaneous/EmptyTestsPkg/.gitignore new file mode 100644 index 00000000000..02c087533d1 --- /dev/null +++ b/Fixtures/Miscellaneous/EmptyTestsPkg/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj diff --git a/Fixtures/Miscellaneous/EmptyTestsPkg/Package.swift b/Fixtures/Miscellaneous/EmptyTestsPkg/Package.swift new file mode 100644 index 00000000000..6643cad540f --- /dev/null +++ b/Fixtures/Miscellaneous/EmptyTestsPkg/Package.swift @@ -0,0 +1,14 @@ +// swift-tools-version:4.2 +import PackageDescription + +let package = Package( + name: "EmptyTestsPkg", + targets: [ + .target( + name: "EmptyTestsPkg", + dependencies: []), + .testTarget( + name: "EmptyTestsPkgTests", + dependencies: ["EmptyTestsPkg"]), + ] +) diff --git a/Fixtures/Miscellaneous/EmptyTestsPkg/Sources/EmptyTestsPkg/EmptyTestsPkg.swift b/Fixtures/Miscellaneous/EmptyTestsPkg/Sources/EmptyTestsPkg/EmptyTestsPkg.swift new file mode 100644 index 00000000000..d5fe06397ea --- /dev/null +++ b/Fixtures/Miscellaneous/EmptyTestsPkg/Sources/EmptyTestsPkg/EmptyTestsPkg.swift @@ -0,0 +1,5 @@ +struct EmptyTests { + + var text = "Hello, World!" + var bool = false +} diff --git a/Fixtures/Miscellaneous/EmptyTestsPkg/Tests/EmptyTestsPkgTests/EmptyTestsTests.swift b/Fixtures/Miscellaneous/EmptyTestsPkg/Tests/EmptyTestsPkgTests/EmptyTestsTests.swift new file mode 100644 index 00000000000..e1e4e155c57 --- /dev/null +++ b/Fixtures/Miscellaneous/EmptyTestsPkg/Tests/EmptyTestsPkgTests/EmptyTestsTests.swift @@ -0,0 +1,2 @@ +import XCTest +@testable import EmptyTestsPkg diff --git a/Sources/Commands/SwiftTestTool.swift b/Sources/Commands/SwiftTestTool.swift index f2d22349ac6..ea0954c98c8 100644 --- a/Sources/Commands/SwiftTestTool.swift +++ b/Sources/Commands/SwiftTestTool.swift @@ -241,6 +241,7 @@ public struct SwiftTestTool: SwiftCommand { // If there were no matches, emit a warning and exit. if tests.isEmpty { swiftTool.observabilityScope.emit(.noMatchingTests) + try generateXUnitOutputIfRequested(for: [], swiftTool: swiftTool) return } @@ -264,14 +265,7 @@ public struct SwiftTestTool: SwiftCommand { let testResults = try runner.run(tests) - // Generate xUnit file if requested - if let xUnitOutput = options.xUnitOutput { - let generator = XUnitGenerator( - fileSystem: swiftTool.fileSystem, - results: testResults - ) - try generator.generate(at: xUnitOutput) - } + try generateXUnitOutputIfRequested(for: testResults, swiftTool: swiftTool) // process code Coverage if request if self.options.enableCodeCoverage, runner.ranSuccessfully { @@ -325,6 +319,19 @@ public struct SwiftTestTool: SwiftCommand { } } + /// Generate xUnit file if requested. + private func generateXUnitOutputIfRequested(for testResults: [ParallelTestRunner.TestResult], swiftTool: SwiftTool) throws { + guard let xUnitOutput = options.xUnitOutput else { + return + } + + let generator = XUnitGenerator( + fileSystem: swiftTool.fileSystem, + results: testResults + ) + try generator.generate(at: xUnitOutput) + } + // MARK: - swift-testing private func swiftTestingRun(_ swiftTool: SwiftTool) throws { diff --git a/Tests/CommandsTests/TestToolTests.swift b/Tests/CommandsTests/TestToolTests.swift index 61e34eb351a..12976e3d200 100644 --- a/Tests/CommandsTests/TestToolTests.swift +++ b/Tests/CommandsTests/TestToolTests.swift @@ -128,6 +128,22 @@ final class TestToolTests: CommandsTestCase { } } + func testSwiftTestXMLOutputWhenEmpty() throws { + try fixture(name: "Miscellaneous/EmptyTestsPkg") { fixturePath in + let xUnitOutput = fixturePath.appending("result.xml") + // Run tests in parallel with verbose output. + let stdout = try SwiftPM.Test.execute(["--parallel", "--verbose", "--xunit-output", xUnitOutput.pathString], packagePath: fixturePath).stdout + // in "swift test" test output goes to stdout + XCTAssertNoMatch(stdout, .contains("passed")) + XCTAssertNoMatch(stdout, .contains("failed")) + + // Check the xUnit output. + XCTAssertFileExists(xUnitOutput) + let contents: String = try localFileSystem.readFileContents(xUnitOutput) + XCTAssertMatch(contents, .contains("tests=\"0\" failures=\"0\"")) + } + } + func testSwiftTestFilter() throws { try fixture(name: "Miscellaneous/SkipTests") { fixturePath in let (stdout, _) = try SwiftPM.Test.execute(["--filter", ".*1"], packagePath: fixturePath)