Skip to content

Commit 0aca575

Browse files
committed
Tests: Do not use mix of XCTest and Swift Testing
The fixture(..) helper function is being used in XCTest and Swift Testing tests. However, there was a code path that could lead to calling XCTFail(), which is a no-op in Swift Testing. This change rename the functio to fixtureXCTest, and marks it as deprecated with a note indicating to migrate the test to Swift Testing. In addition, create a Swift Testing equivalent of the fixture class that calls the relevant APIs.
1 parent 4bc76e0 commit 0aca575

27 files changed

+262
-172
lines changed

Sources/_InternalTestSupport/misc.swift

Lines changed: 95 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import SPMBuildCore
2828
import struct SPMBuildCore.BuildParameters
2929
import TSCTestSupport
3030
import Workspace
31+
import Testing
3132
import func XCTest.XCTFail
3233
import struct XCTest.XCTSkip
3334

@@ -112,7 +113,8 @@ public func testWithTemporaryDirectory<Result>(
112113
/// The temporary copy is deleted after the block returns. The fixture name may
113114
/// contain `/` characters, which are treated as path separators, exactly as if
114115
/// the name were a relative path.
115-
@discardableResult public func fixture<T>(
116+
@available(*, deprecated, message: "Migrate test to Swift Testing and use 'fixture' instead")
117+
@discardableResult public func fixtureXCTest<T>(
116118
name: String,
117119
createGitRepo: Bool = true,
118120
file: StaticString = #file,
@@ -133,7 +135,44 @@ public func testWithTemporaryDirectory<Result>(
133135
try? localFileSystem.removeFileTree(tmpDirPath)
134136
}
135137

136-
let fixtureDir = try verifyFixtureExists(at: fixtureSubpath, file: file, line: line)
138+
let fixtureDir = try verifyFixtureExistsXCTest(at: fixtureSubpath, file: file, line: line)
139+
let preparedFixture = try setup(
140+
fixtureDir: fixtureDir,
141+
in: tmpDirPath,
142+
copyName: copyName,
143+
createGitRepo:createGitRepo
144+
)
145+
return try body(preparedFixture)
146+
}
147+
} catch SwiftPMError.executionFailure(let error, let output, let stderr) {
148+
print("**** FAILURE EXECUTING SUBPROCESS ****")
149+
print("output:", output)
150+
print("stderr:", stderr)
151+
throw error
152+
}
153+
}
154+
155+
@discardableResult public func fixture<T>(
156+
name: String,
157+
createGitRepo: Bool = true,
158+
sourceLocation: SourceLocation = #_sourceLocation,
159+
body: (AbsolutePath) throws -> T
160+
) throws -> T {
161+
do {
162+
// Make a suitable test directory name from the fixture subpath.
163+
let fixtureSubpath = try RelativePath(validating: name)
164+
let copyName = fixtureSubpath.components.joined(separator: "_")
165+
166+
// Create a temporary directory for the duration of the block.
167+
return try withTemporaryDirectory(prefix: copyName) { tmpDirPath in
168+
169+
defer {
170+
// Unblock and remove the tmp dir on deinit.
171+
try? localFileSystem.chmod(.userWritable, path: tmpDirPath, options: [.recursive])
172+
try? localFileSystem.removeFileTree(tmpDirPath)
173+
}
174+
175+
let fixtureDir = try verifyFixtureExists(at: fixtureSubpath, sourceLocation: sourceLocation)
137176
let preparedFixture = try setup(
138177
fixtureDir: fixtureDir,
139178
in: tmpDirPath,
@@ -154,7 +193,8 @@ public enum TestError: Error {
154193
case platformNotSupported
155194
}
156195

157-
@discardableResult public func fixture<T>(
196+
@available(*, deprecated, message: "Migrate test to Swift Testing and use 'fixture' instead")
197+
@discardableResult public func fixtureXCTest<T>(
158198
name: String,
159199
createGitRepo: Bool = true,
160200
file: StaticString = #file,
@@ -175,7 +215,7 @@ public enum TestError: Error {
175215
try? localFileSystem.removeFileTree(tmpDirPath)
176216
}
177217

178-
let fixtureDir = try verifyFixtureExists(at: fixtureSubpath, file: file, line: line)
218+
let fixtureDir = try verifyFixtureExistsXCTest(at: fixtureSubpath, file: file, line: line)
179219
let preparedFixture = try setup(
180220
fixtureDir: fixtureDir,
181221
in: tmpDirPath,
@@ -192,7 +232,44 @@ public enum TestError: Error {
192232
}
193233
}
194234

195-
fileprivate func verifyFixtureExists(at fixtureSubpath: RelativePath, file: StaticString = #file, line: UInt = #line) throws -> AbsolutePath {
235+
@discardableResult public func fixture<T>(
236+
name: String,
237+
createGitRepo: Bool = true,
238+
sourceLocation: SourceLocation = #_sourceLocation,
239+
body: (AbsolutePath) async throws -> T
240+
) async throws -> T {
241+
do {
242+
// Make a suitable test directory name from the fixture subpath.
243+
let fixtureSubpath = try RelativePath(validating: name)
244+
let copyName = fixtureSubpath.components.joined(separator: "_")
245+
246+
// Create a temporary directory for the duration of the block.
247+
return try await withTemporaryDirectory(prefix: copyName) { tmpDirPath in
248+
249+
defer {
250+
// Unblock and remove the tmp dir on deinit.
251+
try? localFileSystem.chmod(.userWritable, path: tmpDirPath, options: [.recursive])
252+
try? localFileSystem.removeFileTree(tmpDirPath)
253+
}
254+
255+
let fixtureDir = try verifyFixtureExists(at: fixtureSubpath, sourceLocation: sourceLocation)
256+
let preparedFixture = try setup(
257+
fixtureDir: fixtureDir,
258+
in: tmpDirPath,
259+
copyName: copyName,
260+
createGitRepo:createGitRepo
261+
)
262+
return try await body(preparedFixture)
263+
}
264+
} catch SwiftPMError.executionFailure(let error, let output, let stderr) {
265+
print("**** FAILURE EXECUTING SUBPROCESS ****")
266+
print("output:", output)
267+
print("stderr:", stderr)
268+
throw error
269+
}
270+
}
271+
272+
fileprivate func verifyFixtureExistsXCTest(at fixtureSubpath: RelativePath, file: StaticString = #file, line: UInt = #line) throws -> AbsolutePath {
196273
let fixtureDir = AbsolutePath("../../../Fixtures", relativeTo: #file)
197274
.appending(fixtureSubpath)
198275

@@ -205,6 +282,19 @@ fileprivate func verifyFixtureExists(at fixtureSubpath: RelativePath, file: Stat
205282
return fixtureDir
206283
}
207284

285+
fileprivate func verifyFixtureExists(at fixtureSubpath: RelativePath, sourceLocation: SourceLocation = #_sourceLocation) throws -> AbsolutePath {
286+
let fixtureDir = AbsolutePath("../../../Fixtures", relativeTo: #file)
287+
.appending(fixtureSubpath)
288+
289+
// Check that the fixture is really there.
290+
guard localFileSystem.isDirectory(fixtureDir) else {
291+
Issue.record("No such fixture: \(fixtureDir)", sourceLocation: sourceLocation)
292+
throw SwiftPMError.packagePathNotFound
293+
}
294+
295+
return fixtureDir
296+
}
297+
208298
fileprivate func setup(
209299
fixtureDir: AbsolutePath,
210300
in tmpDirPath: AbsolutePath,

Tests/BuildTests/BuildPlanTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase {
628628
toolchain: UserToolchain.default,
629629
fileSystem: localFileSystem
630630
)
631-
try await fixture(name: "Miscellaneous/PackageNameFlag") { fixturePath in
631+
try await fixtureXCTest(name: "Miscellaneous/PackageNameFlag") { fixturePath in
632632
let (stdout, stderr) = try await executeSwiftBuild(
633633
fixturePath.appending("appPkg"),
634634
extraArgs: ["--vv"],
@@ -666,7 +666,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase {
666666
toolchain: UserToolchain.default,
667667
fileSystem: localFileSystem
668668
)
669-
try await fixture(name: "Miscellaneous/PackageNameFlag") { fixturePath in
669+
try await fixtureXCTest(name: "Miscellaneous/PackageNameFlag") { fixturePath in
670670
let (stdout, _) = try await executeSwiftBuild(
671671
fixturePath.appending("appPkg"),
672672
extraArgs: ["--vv"],
@@ -697,7 +697,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase {
697697
toolchain: UserToolchain.default,
698698
fileSystem: localFileSystem
699699
)
700-
try await fixture(name: "Miscellaneous/TargetPackageAccess") { fixturePath in
700+
try await fixtureXCTest(name: "Miscellaneous/TargetPackageAccess") { fixturePath in
701701
let (stdout, _) = try await executeSwiftBuild(
702702
fixturePath.appending("libPkg"),
703703
extraArgs: ["-v"],

Tests/BuildTests/BuildSystemDelegateTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import var TSCBasic.localFileSystem
1919
final class BuildSystemDelegateTests: XCTestCase {
2020
func testDoNotFilterLinkerDiagnostics() async throws {
2121
try XCTSkipIf(!UserToolchain.default.supportsSDKDependentTests(), "skipping because test environment doesn't support this test")
22-
try await fixture(name: "Miscellaneous/DoNotFilterLinkerDiagnostics") { fixturePath in
22+
try await fixtureXCTest(name: "Miscellaneous/DoNotFilterLinkerDiagnostics") { fixturePath in
2323
#if !os(macOS)
2424
// These linker diagnostics are only produced on macOS.
2525
try XCTSkipIf(true, "test is only supported on macOS")
@@ -39,7 +39,7 @@ final class BuildSystemDelegateTests: XCTestCase {
3939
#else
4040
let executableExt = ""
4141
#endif
42-
try await fixture(name: "Miscellaneous/TestableExe") { fixturePath in
42+
try await fixtureXCTest(name: "Miscellaneous/TestableExe") { fixturePath in
4343
_ = try await executeSwiftBuild(fixturePath)
4444
let execPath = fixturePath.appending(components: ".build", "debug", "TestableExe1\(executableExt)")
4545
XCTAssertTrue(localFileSystem.exists(execPath), "executable not found at '\(execPath)'")

Tests/BuildTests/IncrementalBuildTests.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ final class IncrementalBuildTests: XCTestCase {
4040

4141
func testIncrementalSingleModuleCLibraryInSources() async throws {
4242
try XCTSkipIf(!UserToolchain.default.supportsSDKDependentTests(), "skipping because test environment doesn't support this test")
43-
try await fixture(name: "CFamilyTargets/CLibrarySources") { fixturePath in
43+
try await fixtureXCTest(name: "CFamilyTargets/CLibrarySources") { fixturePath in
4444
// Build it once and capture the log (this will be a full build).
4545
let (fullLog, _) = try await executeSwiftBuild(fixturePath)
4646

@@ -98,7 +98,7 @@ final class IncrementalBuildTests: XCTestCase {
9898

9999
func testBuildManifestCaching() async throws {
100100
try XCTSkipIf(!UserToolchain.default.supportsSDKDependentTests(), "skipping because test environment doesn't support this test")
101-
try await fixture(name: "ValidLayouts/SingleModule/Library") { fixturePath in
101+
try await fixtureXCTest(name: "ValidLayouts/SingleModule/Library") { fixturePath in
102102
@discardableResult
103103
func build() async throws -> String {
104104
return try await executeSwiftBuild(fixturePath).stdout
@@ -132,7 +132,7 @@ final class IncrementalBuildTests: XCTestCase {
132132

133133
func testDisableBuildManifestCaching() async throws {
134134
try XCTSkipIf(!UserToolchain.default.supportsSDKDependentTests(), "skipping because test environment doesn't support this test")
135-
try await fixture(name: "ValidLayouts/SingleModule/Library") { fixturePath in
135+
try await fixtureXCTest(name: "ValidLayouts/SingleModule/Library") { fixturePath in
136136
@discardableResult
137137
func build() async throws -> String {
138138
return try await executeSwiftBuild(fixturePath, extraArgs: ["--disable-build-manifest-caching"]).stdout
@@ -152,7 +152,7 @@ final class IncrementalBuildTests: XCTestCase {
152152
#if os(macOS)
153153
try XCTSkipIf(!UserToolchain.default.supportsSDKDependentTests(), "skipping because test environment doesn't support this test")
154154

155-
try await fixture(name: "ValidLayouts/SingleModule/Library") { fixturePath in
155+
try await fixtureXCTest(name: "ValidLayouts/SingleModule/Library") { fixturePath in
156156
let dummySwiftcPath = SwiftPM.xctestBinaryPath(for: "dummy-swiftc")
157157
let swiftCompilerPath = try UserToolchain.default.swiftCompilerPath
158158
let environment: Environment = [

Tests/BuildTests/PluginsBuildPlanTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ final class PluginsBuildPlanTests: XCTestCase {
2020
func testBuildToolsDatabasePath() async throws {
2121
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")
2222

23-
try await fixture(name: "Miscellaneous/Plugins/MySourceGenPlugin") { fixturePath in
23+
try await fixtureXCTest(name: "Miscellaneous/Plugins/MySourceGenPlugin") { fixturePath in
2424
let (stdout, _) = try await executeSwiftBuild(fixturePath)
2525
XCTAssertMatch(stdout, .contains("Build complete!"))
2626
// FIXME: This is temporary until build of plugin tools is extracted into its own command.
@@ -48,7 +48,7 @@ final class PluginsBuildPlanTests: XCTestCase {
4848
let targetTriple = hostToolchain.targetTriple.arch == .aarch64 ? x86Triple : armTriple
4949

5050
// By default, plugin dependencies are built for the host platform
51-
try await fixture(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in
51+
try await fixtureXCTest(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in
5252
let (stdout, stderr) = try await executeSwiftPackage(fixturePath, extraArgs: ["-v", "build-plugin-dependency"])
5353
XCTAssertMatch(stdout, .contains("Hello from dependencies-stub"))
5454
XCTAssertMatch(stderr, .contains("Build of product 'plugintool' complete!"))
@@ -65,7 +65,7 @@ final class PluginsBuildPlanTests: XCTestCase {
6565
}
6666

6767
// When cross compiling the final product, plugin dependencies should still be built for the host
68-
try await fixture(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in
68+
try await fixtureXCTest(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in
6969
let (stdout, stderr) = try await executeSwiftPackage(fixturePath, extraArgs: ["--triple", targetTriple, "-v", "build-plugin-dependency"])
7070
XCTAssertMatch(stdout, .contains("Hello from dependencies-stub"))
7171
XCTAssertMatch(stderr, .contains("Build of product 'plugintool' complete!"))

0 commit comments

Comments
 (0)