Skip to content

Commit acd7b00

Browse files
authored
Add SwiftBuild coverage support (#9162)
Ensure the SwiftBuild build system has feature parity with the Native build system as it relates to coverage. Fixes: #9077 Fixes: #9197 Issue: rdar://159461439
1 parent 8b1cfc9 commit acd7b00

File tree

18 files changed

+933
-566
lines changed

18 files changed

+933
-566
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// swift-tools-version: 6.2
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: "Simple",
8+
products: [
9+
// Products define the executables and libraries a package produces, making them visible to other packages.
10+
.library(
11+
name: "Simple",
12+
targets: ["Simple"]
13+
),
14+
],
15+
targets: [
16+
// Targets are the basic building blocks of a package, defining a module or a test suite.
17+
// Targets can depend on other targets in this package and products from dependencies.
18+
.target(
19+
name: "Simple"
20+
),
21+
.testTarget(
22+
name: "SimpleTests",
23+
dependencies: ["Simple"]
24+
),
25+
]
26+
)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// The Swift Programming Language
2+
// https://docs.swift.org/swift-book
3+
4+
public func greet(name: String = "world") -> String {
5+
return "Hello, \(name)!"
6+
}
7+
8+
public func libA() -> String {
9+
return "libA"
10+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import Testing
2+
import XCTest
3+
@testable import Simple
4+
5+
@Test(
6+
arguments: [
7+
"Bob",
8+
"Alice",
9+
"",
10+
]
11+
)
12+
func testGreet(
13+
name: String
14+
) async throws {
15+
let actual = greet(name: name)
16+
17+
#expect(actual == "Hello, \(name)!")
18+
}
19+
20+
final class SimpleTests: XCTestCase {
21+
func testExample() throws {
22+
XCTAssertEqual(libA(), "libA", "Actual is not as expected")
23+
}
24+
}

Sources/Commands/SwiftTestCommand.swift

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import ArgumentParser
1414

1515
@_spi(SwiftPMInternal)
1616
import Basics
17+
import struct Basics.Triple
1718

1819
import _Concurrency
1920

@@ -597,7 +598,11 @@ public struct SwiftTestCommand: AsyncSwiftCommand {
597598
for product in testProducts {
598599
// Export the codecov data as JSON.
599600
let jsonPath = productsBuildParameters.codeCovAsJSONPath(packageName: rootManifest.displayName)
600-
try await exportCodeCovAsJSON(to: jsonPath, testBinary: product.binaryPath, swiftCommandState: swiftCommandState)
601+
try await exportCodeCovAsJSON(
602+
to: jsonPath,
603+
testBinary: product.binaryPath,
604+
swiftCommandState: swiftCommandState,
605+
)
601606
}
602607
}
603608

@@ -619,7 +624,6 @@ public struct SwiftTestCommand: AsyncSwiftCommand {
619624
}
620625
}
621626
args += ["-o", productsBuildParameters.codeCovDataFile.pathString]
622-
623627
try await AsyncProcess.checkNonZeroExit(arguments: args)
624628
}
625629

@@ -632,11 +636,17 @@ public struct SwiftTestCommand: AsyncSwiftCommand {
632636
// Export using the llvm-cov tool.
633637
let llvmCov = try swiftCommandState.getTargetToolchain().getLLVMCov()
634638
let (productsBuildParameters, _) = try swiftCommandState.buildParametersForTest(options: self.options)
639+
let archArgs: [String] = if let arch = productsBuildParameters.triple.llvmCovArchArgument {
640+
["--arch", "\(arch)"]
641+
} else {
642+
[]
643+
}
635644
let args = [
636645
llvmCov.pathString,
637646
"export",
638647
"-instr-profile=\(productsBuildParameters.codeCovDataFile)",
639-
testBinary.pathString
648+
] + archArgs + [
649+
testBinary.pathString,
640650
]
641651
let result = try await AsyncProcess.popen(arguments: args)
642652

@@ -709,6 +719,21 @@ extension SwiftTestCommand {
709719
}
710720
}
711721

722+
fileprivate extension Triple {
723+
var llvmCovArchArgument: String? {
724+
guard let arch = self.arch else {
725+
return nil
726+
}
727+
switch arch {
728+
case .aarch64:
729+
// Apple platforms uses arm64
730+
return self.isApple() ? "arm64" : "aarch64"
731+
default:
732+
return "\(arch)"
733+
}
734+
}
735+
}
736+
712737
extension SwiftTestCommand {
713738
struct Last: SwiftCommand {
714739
@OptionGroup(visibility: .hidden)

Sources/SwiftBuildSupport/SwiftBuildSystem.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,8 +1077,9 @@ public final class SwiftBuildSystem: SPMBuildCore.BuildSystem {
10771077

10781078
private static func constructTestingSettingsOverrides(from parameters: BuildParameters.Testing) -> [String: String] {
10791079
var settings: [String: String] = [:]
1080-
// TODO: enableCodeCoverage
1081-
// explicitlyEnabledTestability
1080+
1081+
// Coverage settings
1082+
settings["CLANG_COVERAGE_MAPPING"] = parameters.enableCodeCoverage ? "YES" : "NO"
10821083

10831084
switch parameters.explicitlyEnabledTestability {
10841085
case true:

Sources/_InternalTestSupport/SwiftTesting+TraitsBug.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ extension Trait where Self == Testing.Bug {
5454
)
5555
}
5656

57+
public static var IssueWindowsPathTestsFailures: Self {
58+
.issue(
59+
"https://github.com/swiftlang/swift-package-manager/issues/8511",
60+
relationship: .defect,
61+
)
62+
}
63+
5764
public static var IssueWindowsCannotSaveAttachment: Self {
5865
// error: unable to write file 'C:\Users\ContainerAdministrator\AppData\Local\Temp\CFamilyTargets_CDynamicLookup.hNxGHC\CFamilyTargets_CDynamicLookup\.build\x86_64-unknown-windows-msvc\Intermediates.noindex\CDynamicLookup.build\Release-windows\CDynamicLookup.build\Objects-normal\x86_64\CDynamicLookup.LinkFileList': No such file or directory (2)
5966
.issue(

Tests/BasicsTests/FileSystem/PathTests.swift

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ struct PathTests {
4343
}
4444

4545
@Test(
46+
.IssueWindowsPathTestsFailures,
4647
arguments: [
4748
(path: "/ab/cd/ef/", expected: (windows ? #"\ab\cd\ef"# : "/ab/cd/ef"), label: "Trailing path seperator"),
4849
(path: "/ab/cd/ef//", expected: (windows ? #"\ab\cd\ef"# : "/ab/cd/ef"), label: "Trailing path seperator"),
@@ -110,6 +111,7 @@ struct PathTests {
110111
}
111112

112113
@Test(
114+
.IssueWindowsPathTestsFailures,
113115
arguments: [
114116
(path: "/./a", expected: (windows ? #"\"# : "/")),
115117
(path: "/../..", expected: (windows ? #"\"# : "/")),
@@ -143,6 +145,7 @@ struct PathTests {
143145
}
144146

145147
@Test(
148+
.IssueWindowsPathTestsFailures,
146149
arguments: [
147150
(path: "/../..", expected: "/"),
148151
]
@@ -178,6 +181,7 @@ struct PathTests {
178181
}
179182

180183
@Test(
184+
.IssueWindowsPathTestsFailures,
181185
arguments: [
182186
(path: "/../..", expected: "/"),
183187
]
@@ -204,6 +208,7 @@ struct PathTests {
204208
#expect(actual == expectedPath)
205209
}
206210
@Test(
211+
.IssueWindowsPathTestsFailures,
207212
arguments: [
208213
(path: "/", numParentDirectoryCalls: 1, expected: "/"),
209214
(path: "/", numParentDirectoryCalls: 2, expected: "/"),
@@ -215,6 +220,7 @@ struct PathTests {
215220
}
216221

217222
@Test(
223+
.IssueWindowsPathTestsFailures,
218224
arguments: [
219225
(path: "/bar/../foo/..//", numParentDirectoryCalls: 2, expected: "/"),
220226
(path: "/bar/../foo/..//yabba/a/b", numParentDirectoryCalls: 2, expected: "/yabba")
@@ -231,6 +237,7 @@ struct PathTests {
231237
}
232238

233239
@Test(
240+
.IssueWindowsPathTestsFailures,
234241
arguments: [
235242
(path: "/", expected: ["/"]),
236243
(path: "/.", expected: ["/"]),
@@ -368,6 +375,7 @@ struct PathTests {
368375
}
369376

370377
@Test(
378+
.IssueWindowsPathTestsFailures,
371379
arguments: [
372380
(path: "ab//cd//ef", expected: (windows ? #"ab\cd\ef"# : "ab/cd/ef"), label: "repeated path seperators"),
373381
(path: "ab//cd///ef", expected: (windows ? #"ab\cd\ef"# : "ab/cd/ef"), label: "repeated path seperators"),
@@ -440,7 +448,8 @@ struct PathTests {
440448
}
441449

442450
@Test(
443-
arguments: [
451+
.IssueWindowsPathTestsFailures,
452+
arguments: [
444453
(path: "../a/..", expected: "."),
445454
(path: "a/..", expected: "."),
446455
(path: "a/../////../////./////", expected: "."),
@@ -481,6 +490,7 @@ struct PathTests {
481490
}
482491

483492
@Test(
493+
.IssueWindowsPathTestsFailures,
484494
arguments: [
485495
(path: "a/..", expected: "."),
486496
(path: "a/../////../////./////", expected: ".."),
@@ -519,6 +529,7 @@ struct PathTests {
519529
}
520530

521531
@Test(
532+
.IssueWindowsPathTestsFailures,
522533
arguments: [
523534
(path: "../..", expected: ".."),
524535
(path: "../a/..", expected: ".."),
@@ -560,7 +571,8 @@ struct PathTests {
560571
}
561572

562573
@Test(
563-
arguments:[
574+
.IssueWindowsPathTestsFailures,
575+
arguments:[
564576
"a.",
565577
".a",
566578
"",
@@ -601,6 +613,7 @@ struct PathTests {
601613
}
602614

603615
@Test(
616+
.IssueWindowsPathTestsFailures,
604617
arguments: [
605618
(path: "foo/bar/..", expected: ["foo"]),
606619
(path: "bar/../foo", expected: ["foo"]),
@@ -622,21 +635,22 @@ struct PathTests {
622635
}
623636
}
624637

625-
@Test
638+
@Test(
639+
.IssueWindowsPathTestsFailures,
640+
)
626641
func relativePathValidation() throws {
627642
#expect(throws: Never.self) {
628643
try RelativePath(validating: "a/b/c/d")
629644
}
630645

631-
withKnownIssue {
646+
withKnownIssue("https://github.com/swiftlang/swift-package-manager/issues/8511: \\") {
632647
#expect {try RelativePath(validating: "/a/b/d")} throws: { error in
633648
("\(error)" == "invalid relative path '/a/b/d'; relative path should not begin with '/'")
634649
}
635650
} when: {
636651
ProcessInfo.hostOperatingSystem == .windows
637652
}
638653
}
639-
640654
}
641655

642656
@Test

Tests/BasicsTests/HTTPClientTests.swift

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -259,11 +259,8 @@ struct HTTPClientTests {
259259
var request = HTTPClient.Request(method: .get, url: "http://test")
260260
request.options.validResponseCodes = [200]
261261

262-
do {
263-
let response = try await httpClient.execute(request)
264-
Issue.record("unexpected success \(response)")
265-
} catch {
266-
#expect(error as? HTTPClientError == .badResponseStatusCode(statusCode))
262+
await #expect(throws: HTTPClientError.badResponseStatusCode(statusCode)) {
263+
try await httpClient.execute(request)
267264
}
268265
}
269266

@@ -407,11 +404,8 @@ struct HTTPClientTests {
407404
var request = HTTPClient.Request(url: "http://test")
408405
request.options.maximumResponseSizeInBytes = 10
409406

410-
do {
411-
let response = try await httpClient.execute(request)
412-
Issue.record("unexpected success \(response)")
413-
} catch {
414-
#expect(error as? HTTPClientError == .responseTooLarge(maxSize * 2))
407+
await #expect(throws: HTTPClientError.responseTooLarge(maxSize * 2)) {
408+
try await httpClient.execute(request)
415409
}
416410
}
417411

Tests/BuildTests/PluginsBuildPlanTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ struct PluginsBuildPlanTests {
2828
.tags(
2929
.Feature.Command.Build,
3030
),
31-
.issue("https://github.com/swiftlang/swift-package-manager/issues/8511", relationship: .defect), // Fails to build the project to due to incorrect Path handling
31+
.IssueWindowsPathTestsFailures, // Fails to build the project to due to incorrect Path handling
3232
arguments: BuildConfiguration.allCases,
3333
)
3434
func buildToolsDatabasePath(

0 commit comments

Comments
 (0)