Skip to content

Commit b337cd8

Browse files
committed
add an async variant of fixture
1 parent 1b49341 commit b337cd8

File tree

1 file changed

+87
-39
lines changed

1 file changed

+87
-39
lines changed

Sources/SPMTestSupport/misc.swift

Lines changed: 87 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -94,48 +94,51 @@ public func testWithTemporaryDirectory(
9494
try? localFileSystem.removeFileTree(tmpDirPath)
9595
}
9696

97-
// Construct the expected path of the fixture.
98-
// FIXME: This seems quite hacky; we should provide some control over where fixtures are found.
99-
let fixtureDir = AbsolutePath("../../../Fixtures", relativeTo: #file)
100-
.appending(fixtureSubpath)
101-
102-
// Check that the fixture is really there.
103-
guard localFileSystem.isDirectory(fixtureDir) else {
104-
XCTFail("No such fixture: \(fixtureDir)", file: file, line: line)
105-
throw SwiftPMError.packagePathNotFound
106-
}
107-
108-
// The fixture contains either a checkout or just a Git directory.
109-
if localFileSystem.isFile(fixtureDir.appending("Package.swift")) {
110-
// It's a single package, so copy the whole directory as-is.
111-
let dstDir = tmpDirPath.appending(component: copyName)
112-
#if os(Windows)
113-
try localFileSystem.copy(from: fixtureDir, to: dstDir)
114-
#else
115-
try systemQuietly("cp", "-R", "-H", fixtureDir.pathString, dstDir.pathString)
116-
#endif
97+
let fixtureDir = try verifyFixtureExists(at: fixtureSubpath, file: file, line: line)
98+
let preparedFixture = try setup(
99+
fixtureDir: fixtureDir,
100+
in: tmpDirPath,
101+
copyName: copyName,
102+
createGitRepo:createGitRepo
103+
)
104+
return try body(preparedFixture)
105+
}
106+
} catch SwiftPMError.executionFailure(let error, let output, let stderr) {
107+
print("**** FAILURE EXECUTING SUBPROCESS ****")
108+
print("output:", output)
109+
print("stderr:", stderr)
110+
throw error
111+
}
112+
}
113+
@discardableResult public func fixture<T>(
114+
name: String,
115+
createGitRepo: Bool = true,
116+
file: StaticString = #file,
117+
line: UInt = #line,
118+
body: (AbsolutePath) async throws -> T
119+
) async throws -> T {
120+
do {
121+
// Make a suitable test directory name from the fixture subpath.
122+
let fixtureSubpath = try RelativePath(validating: name)
123+
let copyName = fixtureSubpath.components.joined(separator: "_")
117124

118-
// Invoke the block, passing it the path of the copied fixture.
119-
return try body(dstDir)
120-
} else {
121-
// Copy each of the package directories and construct a git repo in it.
122-
for fileName in try localFileSystem.getDirectoryContents(fixtureDir).sorted() {
123-
let srcDir = fixtureDir.appending(component: fileName)
124-
guard localFileSystem.isDirectory(srcDir) else { continue }
125-
let dstDir = tmpDirPath.appending(component: fileName)
126-
#if os(Windows)
127-
try localFileSystem.copy(from: srcDir, to: dstDir)
128-
#else
129-
try systemQuietly("cp", "-R", "-H", srcDir.pathString, dstDir.pathString)
130-
#endif
131-
if createGitRepo {
132-
initGitRepo(dstDir, tag: "1.2.3", addFile: false)
133-
}
134-
}
125+
// Create a temporary directory for the duration of the block.
126+
return try await withTemporaryDirectory(prefix: copyName) { tmpDirPath in
135127

136-
// Invoke the block, passing it the path of the copied fixture.
137-
return try body(tmpDirPath)
128+
defer {
129+
// Unblock and remove the tmp dir on deinit.
130+
try? localFileSystem.chmod(.userWritable, path: tmpDirPath, options: [.recursive])
131+
try? localFileSystem.removeFileTree(tmpDirPath)
138132
}
133+
134+
let fixtureDir = try verifyFixtureExists(at: fixtureSubpath, file: file, line: line)
135+
let preparedFixture = try setup(
136+
fixtureDir: fixtureDir,
137+
in: tmpDirPath,
138+
copyName: copyName,
139+
createGitRepo:createGitRepo
140+
)
141+
return try await body(preparedFixture)
139142
}
140143
} catch SwiftPMError.executionFailure(let error, let output, let stderr) {
141144
print("**** FAILURE EXECUTING SUBPROCESS ****")
@@ -145,6 +148,51 @@ public func testWithTemporaryDirectory(
145148
}
146149
}
147150

151+
fileprivate func verifyFixtureExists(at fixtureSubpath: RelativePath, file: StaticString = #file, line: UInt = #line) throws -> AbsolutePath {
152+
let fixtureDir = AbsolutePath("../../../Fixtures", relativeTo: #file)
153+
.appending(fixtureSubpath)
154+
155+
// Check that the fixture is really there.
156+
guard localFileSystem.isDirectory(fixtureDir) else {
157+
XCTFail("No such fixture: \(fixtureDir)", file: file, line: line)
158+
throw SwiftPMError.packagePathNotFound
159+
}
160+
161+
return fixtureDir
162+
}
163+
164+
fileprivate func setup(fixtureDir: AbsolutePath, in tmpDirPath: AbsolutePath, copyName: String, createGitRepo: Bool = true) throws -> AbsolutePath {
165+
166+
func copy(from srcDir: AbsolutePath, to dstDir: AbsolutePath) throws {
167+
#if os(Windows)
168+
try localFileSystem.copy(from: srcDir, to: dstDir)
169+
#else
170+
try systemQuietly("cp", "-R", "-H", srcDir.pathString, dstDir.pathString)
171+
#endif
172+
}
173+
174+
// The fixture contains either a checkout or just a Git directory.
175+
if localFileSystem.isFile(fixtureDir.appending("Package.swift")) {
176+
// It's a single package, so copy the whole directory as-is.
177+
let dstDir = tmpDirPath.appending(component: copyName)
178+
try copy(from: fixtureDir, to: dstDir)
179+
// Invoke the block, passing it the path of the copied fixture.
180+
return dstDir
181+
}
182+
// Copy each of the package directories and construct a git repo in it.
183+
for fileName in try localFileSystem.getDirectoryContents(fixtureDir).sorted() {
184+
let srcDir = fixtureDir.appending(component: fileName)
185+
guard localFileSystem.isDirectory(srcDir) else { continue }
186+
let dstDir = tmpDirPath.appending(component: fileName)
187+
188+
try copy(from: srcDir, to: dstDir)
189+
if createGitRepo {
190+
initGitRepo(dstDir, tag: "1.2.3", addFile: false)
191+
}
192+
}
193+
return tmpDirPath
194+
}
195+
148196
/// Test-helper function that creates a new Git repository in a directory. The new repository will contain
149197
/// exactly one empty file unless `addFile` is `false`, and if a tag name is provided, a tag with that name will be
150198
/// created.

0 commit comments

Comments
 (0)