Skip to content

Commit 4b724e5

Browse files
committed
Tests: Migrate PluginsBuildPlanTests to SwiftTesting and augment
Migrate the `PluginsBuildPlanTests` suite to Swift Testing and, where applicable, augment the test to run against both the Native and SwiftBuild build system, in addition to the `debug` and `release` build configurations. Depends on: #9013 Relates to: #8997 issue: rdar://157669245
1 parent 4c86ed7 commit 4b724e5

File tree

2 files changed

+185
-65
lines changed

2 files changed

+185
-65
lines changed

Sources/_InternalTestSupport/SwiftTesting+Helpers.swift

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,30 @@ import Testing
1313

1414
public func expectFileExists(
1515
at path: AbsolutePath,
16+
_ comment: Comment? = nil,
1617
sourceLocation: SourceLocation = #_sourceLocation,
1718
) {
18-
19+
let commentPrefix =
20+
if let comment {
21+
"\(comment): "
22+
} else {
23+
""
24+
}
25+
let msgSuffix: String
26+
do {
27+
msgSuffix = try "Directory contents: \(localFileSystem.getDirectoryContents(path.parentDirectory))"
28+
} catch {
29+
msgSuffix = ""
30+
}
1931
#expect(
2032
localFileSystem.exists(path),
21-
"Files '\(path)' does not exist.",
33+
"\(commentPrefix)File '\(path)' does not exist. \(msgSuffix)",
2234
sourceLocation: sourceLocation,
2335
)
2436
}
2537

2638
public func expectFileDoesNotExists(
27-
at fixturePath: AbsolutePath,
39+
at path: AbsolutePath,
2840
_ comment: Comment? = nil,
2941
sourceLocation: SourceLocation = #_sourceLocation,
3042
) {
@@ -34,9 +46,15 @@ public func expectFileDoesNotExists(
3446
} else {
3547
""
3648
}
49+
let msgSuffix: String
50+
do {
51+
msgSuffix = try "Directory contents: \(localFileSystem.getDirectoryContents(path.parentDirectory))"
52+
} catch {
53+
msgSuffix = ""
54+
}
3755
#expect(
38-
!localFileSystem.exists(fixturePath),
39-
"\(commentPrefix)\(fixturePath) does not exist",
56+
!localFileSystem.exists(path),
57+
"\(commentPrefix)File: '\(path)' was not expected to exist, but does.\(msgSuffix))",
4058
sourceLocation: sourceLocation,
4159
)
4260
}
@@ -54,7 +72,7 @@ public func expectFileIsExecutable(
5472
}
5573
#expect(
5674
localFileSystem.isExecutableFile(fixturePath),
57-
"\(commentPrefix)\(fixturePath) does not exist",
75+
"\(commentPrefix)File '\(fixturePath)' expected to be executable, but is not.",
5876
sourceLocation: sourceLocation,
5977
)
6078
}
@@ -63,9 +81,15 @@ public func expectDirectoryExists(
6381
at path: AbsolutePath,
6482
sourceLocation: SourceLocation = #_sourceLocation,
6583
) {
84+
let msgSuffix: String
85+
do {
86+
msgSuffix = try "Directory contents: \(localFileSystem.getDirectoryContents(path))"
87+
} catch {
88+
msgSuffix = ""
89+
}
6690
#expect(
6791
localFileSystem.isDirectory(path),
68-
"Expected directory doesn't exist: \(path)",
92+
"Expected directory doesn't exist: '\(path)'. \(msgSuffix)",
6993
sourceLocation: sourceLocation,
7094
)
7195
}
@@ -74,9 +98,15 @@ public func expectDirectoryDoesNotExist(
7498
at path: AbsolutePath,
7599
sourceLocation: SourceLocation = #_sourceLocation,
76100
) {
101+
let msgSuffix: String
102+
do {
103+
msgSuffix = try "Directory contents: \(localFileSystem.getDirectoryContents(path))"
104+
} catch {
105+
msgSuffix = ""
106+
}
77107
#expect(
78108
!localFileSystem.isDirectory(path),
79-
"Directory exists unexpectedly: \(path)",
109+
"Directory exists unexpectedly: '\(path)'.\(msgSuffix)",
80110
sourceLocation: sourceLocation,
81111
)
82112
}

Tests/BuildTests/PluginsBuildPlanTests.swift

Lines changed: 147 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,91 +2,181 @@
22
//
33
// This source file is part of the Swift open source project
44
//
5-
// Copyright (c) 2014-2024 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014-2025 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See http://swift.org/LICENSE.txt for license information
99
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
12-
12+
import Foundation
1313
import Basics
14-
import _InternalTestSupport
15-
@testable import SPMBuildCore
16-
import XCTest
1714
import PackageModel
15+
import Testing
16+
import _InternalTestSupport
1817

19-
final class PluginsBuildPlanTests: XCTestCase {
20-
func testBuildToolsDatabasePath() async throws {
21-
try XCTSkipOnWindows(because: "Fails to build the project to due to incorrect Path handling. Possibly related to https://github.com/swiftlang/swift-package-manager/issues/8511")
18+
@testable import SPMBuildCore
2219

23-
try await fixtureXCTest(name: "Miscellaneous/Plugins/MySourceGenPlugin") { fixturePath in
24-
let (stdout, _) = try await executeSwiftBuild(fixturePath, buildSystem: .native)
25-
XCTAssertMatch(stdout, .contains("Build complete!"))
20+
@Suite(
21+
.serialized,
22+
.tags(
23+
.TestSize.large,
24+
),
25+
)
26+
struct PluginsBuildPlanTests {
27+
@Test(
28+
.tags(
29+
.Feature.Command.Build,
30+
),
31+
.issue("https://github.com/swiftlang/swift-package-manager/issues/8511", relationship: .defect), // Fails to build the project to due to incorrect Path handling
32+
arguments: BuildConfiguration.allCases,
33+
)
34+
func buildToolsDatabasePath(
35+
config: BuildConfiguration,
36+
) async throws {
37+
try await withKnownIssue(isIntermittent: true) {
38+
try await fixture(name: "Miscellaneous/Plugins/MySourceGenPlugin") { fixturePath in
39+
let (stdout, _) = try await executeSwiftBuild(
40+
fixturePath,
41+
configuration: config,
42+
buildSystem: .native
43+
)
44+
#expect(stdout.contains("Build complete!"))
2645
// FIXME: This is temporary until build of plugin tools is extracted into its own command.
27-
XCTAssertTrue(localFileSystem.exists(fixturePath.appending(RelativePath(".build/plugin-tools.db"))))
28-
XCTAssertTrue(localFileSystem.exists(fixturePath.appending(RelativePath(".build/build.db"))))
46+
#expect(localFileSystem.exists(fixturePath.appending(RelativePath(".build/plugin-tools.db"))))
47+
#expect(localFileSystem.exists(fixturePath.appending(RelativePath(".build/build.db"))))
48+
}
49+
} when: {
50+
ProcessInfo.hostOperatingSystem == .windows
2951
}
3052
}
3153

32-
func testCommandPluginDependenciesWhenCrossCompiling() async throws {
33-
// Command Plugin dependencies must be built for the host.
34-
// This test is only supported on macOS because that is the only
35-
// platform on which we can currently be sure of having a viable
36-
// cross-compilation environment (arm64->x86_64 or vice versa).
37-
// On Linux it is typically only possible to build for the host
38-
// environment unless cross-compilation SDKs are being used.
39-
#if !os(macOS)
40-
try XCTSkipIf(true, "test is only supported on macOS")
41-
#endif
42-
43-
let hostToolchain = try UserToolchain(swiftSDK: .hostSwiftSDK(environment: [:]), environment: [:])
54+
@Test(
55+
.serialized,
56+
.tags(
57+
.Feature.Command.Package.CommandPlugin,
58+
),
59+
.requireHostOS(.macOS),
60+
arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms),
61+
)
62+
func commandPluginDependenciesWhenNotCrossCompiling(
63+
buildData: BuildData,
64+
) async throws {
65+
let hostToolchain = try UserToolchain(
66+
swiftSDK: .hostSwiftSDK(environment: [:]),
67+
environment: [:]
68+
)
4469
let hostTriple = try! hostToolchain.targetTriple.withoutVersion().tripleString
4570

46-
let x86Triple = "x86_64-apple-macosx"
47-
let armTriple = "arm64-apple-macosx"
48-
let targetTriple = hostToolchain.targetTriple.arch == .aarch64 ? x86Triple : armTriple
49-
71+
let hostBinPathSegments = try buildData.buildSystem.binPath(
72+
for: buildData.config,
73+
triple: hostTriple,
74+
)
75+
let hostDebugBinPathSegments = try buildData.buildSystem.binPath(
76+
for: .debug,
77+
triple: hostTriple,
78+
)
5079
// By default, plugin dependencies are built for the host platform
51-
try await fixtureXCTest(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in
80+
try await fixture(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in
81+
let hostBinPath: AbsolutePath = fixturePath.appending(components: hostBinPathSegments)
82+
let hostDebugBinPath: AbsolutePath = fixturePath.appending(components: hostDebugBinPathSegments)
5283
let (stdout, stderr) = try await executeSwiftPackage(
5384
fixturePath,
85+
configuration: buildData.config,
5486
extraArgs: ["-v", "build-plugin-dependency"],
55-
buildSystem: .native,
56-
)
57-
XCTAssertMatch(stdout, .contains("Hello from dependencies-stub"))
58-
XCTAssertMatch(stderr, .contains("Build of product 'plugintool' complete!"))
59-
XCTAssertTrue(
60-
localFileSystem.exists(
61-
fixturePath.appending(RelativePath(".build/\(hostTriple)/debug/plugintool-tool"))
62-
)
63-
)
64-
XCTAssertTrue(
65-
localFileSystem.exists(
66-
fixturePath.appending(RelativePath(".build/\(hostTriple)/debug/placeholder"))
67-
)
87+
buildSystem: buildData.buildSystem,
6888
)
89+
#expect(stdout.contains("Hello from dependencies-stub"))
90+
if buildData.buildSystem == .native {
91+
#expect(stderr.contains("Build of product 'plugintool' complete!"))
92+
}
93+
let pluginToolName: String
94+
switch buildData.buildSystem {
95+
case .native:
96+
pluginToolName = "plugintool-tool"
97+
case .swiftbuild:
98+
pluginToolName = "plugintool"
99+
case .xcode:
100+
pluginToolName = ""
101+
Issue.record("Test has not been updated for this build system")
102+
}
103+
expectFileExists(at: hostBinPath.appending(pluginToolName))
104+
expectFileExists(at: hostDebugBinPath.appending("placeholder"))
69105
}
106+
}
107+
108+
@Test(
109+
.serialized,
110+
.tags(
111+
.Feature.Command.Package.CommandPlugin,
112+
),
113+
.requireHostOS(.macOS),
114+
arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms),
115+
)
116+
func commandPluginDependenciesWhenCrossCompiling(
117+
buildData: BuildData,
118+
) async throws {
119+
let hostToolchain = try UserToolchain(
120+
swiftSDK: .hostSwiftSDK(environment: [:]),
121+
environment: [:]
122+
)
123+
// let hostTriple = try! hostToolchain.targetTriple.withoutVersion().tripleString
124+
125+
let x86Triple = "x86_64-apple-macosx"
126+
let armTriple = "arm64-apple-macosx"
127+
let targetTriple = hostToolchain.targetTriple.arch == .aarch64 ? x86Triple : armTriple
128+
129+
let hostBinPathSegments = try buildData.buildSystem.binPath(
130+
for: buildData.config,
131+
)
132+
let targetDebugBinPathSegments = try buildData.buildSystem.binPath(
133+
for: .debug,
134+
triple: targetTriple,
135+
)
70136

71137
// When cross compiling the final product, plugin dependencies should still be built for the host
72-
try await fixtureXCTest(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in
73-
let (stdout, stderr) = try await executeSwiftPackage(
74-
fixturePath,
75-
extraArgs: ["--triple", targetTriple, "-v", "build-plugin-dependency"],
76-
buildSystem: .native,
77-
)
78-
XCTAssertMatch(stdout, .contains("Hello from dependencies-stub"))
79-
XCTAssertMatch(stderr, .contains("Build of product 'plugintool' complete!"))
80-
XCTAssertTrue(
81-
localFileSystem.exists(
82-
fixturePath.appending(RelativePath(".build/\(hostTriple)/debug/plugintool-tool"))
138+
try await fixture(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in
139+
// let hostBinPath: AbsolutePath = fixturePath.appending(components: hostBinPathSegments)
140+
let targetDebugBinPath: AbsolutePath = fixturePath.appending(components: targetDebugBinPathSegments)
141+
let hostBinPath = try fixturePath.appending(
142+
components: buildData.buildSystem.binPath(
143+
for: buildData.config,
83144
)
84145
)
85-
XCTAssertTrue(
86-
localFileSystem.exists(
87-
fixturePath.appending(RelativePath(".build/\(targetTriple)/debug/placeholder"))
146+
let targetBinPath = try fixturePath.appending(
147+
components: buildData.buildSystem.binPath(
148+
for: buildData.config,
149+
triple: targetTriple,
88150
)
89151
)
152+
let (stdout, stderr) = try await executeSwiftPackage(
153+
fixturePath,
154+
configuration: buildData.config,
155+
extraArgs: ["-v", "--triple", targetTriple, "build-plugin-dependency"],
156+
buildSystem: buildData.buildSystem,
157+
)
158+
#expect(stdout.contains("Hello from dependencies-stub"))
159+
if buildData.buildSystem == .native {
160+
#expect(stderr.contains("Build of product 'plugintool' complete!"))
161+
}
162+
let pluginToolName: String
163+
let pluginToolBinPath: AbsolutePath
164+
switch buildData.buildSystem {
165+
case .native:
166+
pluginToolName = "plugintool-tool"
167+
pluginToolBinPath = hostBinPath
168+
case .swiftbuild:
169+
pluginToolName = "plugintool"
170+
pluginToolBinPath = targetBinPath
171+
case .xcode:
172+
pluginToolName = ""
173+
pluginToolBinPath = AbsolutePath("/")
174+
Issue.record("Test has not been updated for this build system")
175+
}
176+
177+
expectFileExists(at: targetDebugBinPath.appending("placeholder"))
178+
expectFileExists(at: pluginToolBinPath.appending(pluginToolName))
90179
}
91180
}
181+
92182
}

0 commit comments

Comments
 (0)