Skip to content

Commit 94b19a7

Browse files
committed
Add SwiftBuild coverage support
Ensure the SwiftBuild build systam has feature parity with the Native build system as it relates to coverage. Fixes: #9077 Issue: rdar://159461439
1 parent e118398 commit 94b19a7

File tree

14 files changed

+993
-515
lines changed

14 files changed

+993
-515
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
xcuserdata/
5+
DerivedData/
6+
.swiftpm/configuration/registries.json
7+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8+
.netrc
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/Basics/FileSystem/AbsolutePath.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,19 @@ public struct AbsolutePath: Hashable, Sendable {
5353
/// The input string will be normalized if needed, as described in the
5454
/// documentation for AbsolutePath.
5555
public init(validating pathString: String) throws {
56-
self.underlying = try .init(validating: pathString)
56+
self.underlying = try .init(
57+
validating: pathString.trimmingCharacters(in: .whitespacesAndNewlines),
58+
)
5759
}
5860

5961
/// Initializes an AbsolutePath from a string that may be either absolute
6062
/// or relative; if relative, `basePath` is used as the anchor; if absolute,
6163
/// it is used as is, and in this case `basePath` is ignored.
6264
public init(validating pathString: String, relativeTo basePath: AbsolutePath) throws {
63-
self.underlying = try .init(validating: pathString, relativeTo: basePath.underlying)
65+
self.underlying = try .init(
66+
validating: pathString.trimmingCharacters(in: .whitespacesAndNewlines),
67+
relativeTo: basePath.underlying,
68+
)
6469
}
6570

6671
/// Initializes the AbsolutePath by concatenating a relative path to an

Sources/Basics/FileSystem/RelativePath.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
12-
12+
import Foundation
1313
import struct TSCBasic.RelativePath
1414

1515
// public for transition
@@ -40,7 +40,9 @@ public struct RelativePath: Hashable, Sendable {
4040

4141
/// Convenience initializer that verifies that the path is relative.
4242
public init(validating pathString: String) throws {
43-
self.underlying = try .init(validating: pathString)
43+
self.underlying = try .init(
44+
validating: pathString.trimmingCharacters(in: .whitespacesAndNewlines),
45+
)
4446
}
4547

4648
/// Directory component. For a relative path without any path separators,

Sources/Commands/SwiftTestCommand.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,6 @@ public struct SwiftTestCommand: AsyncSwiftCommand {
619619
}
620620
}
621621
args += ["-o", productsBuildParameters.codeCovDataFile.pathString]
622-
623622
try await AsyncProcess.checkNonZeroExit(arguments: args)
624623
}
625624

Sources/SwiftBuildSupport/SwiftBuildSystem.swift

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

924924
private static func constructTestingSettingsOverrides(from parameters: BuildParameters.Testing) -> [String: String] {
925925
var settings: [String: String] = [:]
926-
// TODO: enableCodeCoverage
927-
// explicitlyEnabledTestability
926+
927+
settings["CLANG_COVERAGE_MAPPING"] = parameters.enableCodeCoverage ? "YES" : "NO"
928928

929929
switch parameters.explicitlyEnabledTestability {
930930
case true:

Sources/_InternalTestSupport/SwiftTesting+TraitsBug.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,16 @@ extension Trait where Self == Testing.Bug {
6969
)
7070
}
7171

72+
public static var IssueSwiftBuildCoverageWithReleaseBuildConfig: Self {
73+
// error: Unable to export code coverage:
74+
// error: failed to load coverage: '/Users/bkhouri/Documents/git/public/swiftlang/swift-package-manager/Fixtures/Miscellaneous/TestDiscovery/Simple/.build/arm64-apple-macosx/Products/Release/SimpleTests.xctest/Contents/MacOS/SimpleTests': `-arch` specifier is invalid or missing for universal binary
75+
// error: could not load coverage information
76+
.issue(
77+
"https://github.com/swiftlang/swift-package-manager/issues/9197",
78+
relationship: .defect,
79+
)
80+
}
81+
7282
public static var IssueSwiftBuildLinuxRunnable: Self {
7383
.issue(
7484
"https://github.com/swiftlang/swift-package-manager/issues/8416",

Tests/BasicsTests/FileSystem/PathTests.swift

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,50 @@ struct PathTests {
329329
}
330330
}
331331

332+
@Test(
333+
arguments: [
334+
(path: "/", expected: (windows ? #"\"# : "/")),
335+
(path: "/.", expected: (windows ? #"\"# : "/")),
336+
(path: "/..", expected: (windows ? #"\"# : "/")),
337+
(path: "/bar/", expected: (windows ? #"\bar"# : "/bar")),
338+
], [
339+
" ",
340+
" ",
341+
"\t",
342+
"\t\t",
343+
"\n",
344+
"\n\n",
345+
"\t ",
346+
" \t",
347+
" \n\t",
348+
"\n \t",
349+
],
350+
)
351+
func absolutePathValidationWithPathContainsLeadingAndTrailingWhitespaces(
352+
data: (String, String),
353+
whitespaces: String,
354+
) throws {
355+
let path = data.0
356+
let expected = data.1
357+
do {
358+
// Leading whitespaces
359+
let actual = try AbsolutePath(validating: "\(whitespaces)\(path)").pathString
360+
#expect(actual == expected, "Actual is not as expected. Path is: '\(path)'")
361+
}
362+
363+
do {
364+
// Training whitespaces
365+
let actual = try AbsolutePath(validating: "\(path)\(whitespaces)").pathString
366+
#expect(actual == expected, "Actual is not as expected. Path is: '\(path)'")
367+
}
368+
369+
do {
370+
// Leading and trailing whitespaces
371+
let actual = try AbsolutePath(validating: "\(whitespaces)\(path)\(whitespaces)").pathString
372+
#expect(actual == expected, "Actual is not as expected. Path is: '\(path)'")
373+
}
374+
}
375+
332376
@Test
333377
func comparison() {
334378
#expect(AbsolutePath("/") <= AbsolutePath("/"));
@@ -628,7 +672,7 @@ struct PathTests {
628672
try RelativePath(validating: "a/b/c/d")
629673
}
630674

631-
withKnownIssue {
675+
withKnownIssue("https://github.com/swiftlang/swift-package-manager/issues/8511: \\") {
632676
#expect {try RelativePath(validating: "/a/b/d")} throws: { error in
633677
("\(error)" == "invalid relative path '/a/b/d'; relative path should not begin with '/'")
634678
}
@@ -637,6 +681,86 @@ struct PathTests {
637681
}
638682
}
639683

684+
struct relativePathValidationWithPathContainsLeadingAndTrailingWhitespacesReturnsExpectedValue {
685+
func testImplementation(
686+
data: (String, String),
687+
whitespaces: String,
688+
) async throws {
689+
let path = data.0
690+
let expected = data.1
691+
do {
692+
// Leading whitespaces
693+
let actual = try RelativePath(validating: "\(whitespaces)\(path)").pathString
694+
#expect(actual == expected, "Actual is not as expected. Path is: '\(path)'")
695+
}
696+
697+
do {
698+
// Training whitespaces
699+
let actual = try RelativePath(validating: "\(path)\(whitespaces)").pathString
700+
#expect(actual == expected, "Actual is not as expected. Path is: '\(path)'")
701+
}
702+
703+
do {
704+
// Leading and trailing whitespaces
705+
let actual = try RelativePath(validating: "\(whitespaces)\(path)\(whitespaces)").pathString
706+
#expect(actual == expected, "Actual is not as expected. Path is: '\(path)'")
707+
}
708+
}
709+
710+
@Test(
711+
arguments: [
712+
(path: ".", expected: "."),
713+
(path: "bar/", expected: (windows ? #"bar\"# : "bar")),
714+
(path: "bar/baz", expected: (windows ? #"bar\baz"# :"bar/baz")),
715+
], [
716+
" ",
717+
" ",
718+
"\t",
719+
"\t\t",
720+
"\n",
721+
"\n\n",
722+
"\t ",
723+
" \t",
724+
" \n\t",
725+
"\n \t",
726+
],
727+
)
728+
func relativePathValidationWithPathContainsLeadingAndTrailingWhitespaces(
729+
data: (String, String),
730+
whitespaces: String,
731+
) async throws {
732+
try await testImplementation(data: data, whitespaces: whitespaces)
733+
}
734+
735+
736+
@Test(
737+
arguments: [
738+
(path: "bar/", expected: "bar"),
739+
] as [(String, String)], [
740+
" ",
741+
" ",
742+
"\t",
743+
"\t\t",
744+
"\n",
745+
"\n\n",
746+
"\t ",
747+
" \t",
748+
" \n\t",
749+
"\n \t",
750+
],
751+
)
752+
func relativePathValidationWithPathContainsLeadingAndTrailingWhitespacesFailsOnWindows(
753+
data: (String, String),
754+
whitespaces: String,
755+
) async throws {
756+
try await withKnownIssue("https://github.com/swiftlang/swift-package-manager/issues/8511: Path \(data.0) is not properly") {
757+
try await testImplementation(data: data, whitespaces: whitespaces)
758+
} when: {
759+
ProcessInfo.hostOperatingSystem == .windows
760+
}
761+
}
762+
}
763+
640764
}
641765

642766
@Test

0 commit comments

Comments
 (0)