Skip to content

Commit cdcf0e0

Browse files
authored
[SR-12912] Fix crash in test targets when accessing Bundle.module (#2817)
* SR-12912 Setting the path for Bundle.module fails in the case where the bundle is accessed during tests. This uses the already derived bundlePath instead. * Only use bundlePath when building a testTarget * Updating this for discussion in PR. This hardcodes the test path as expected, however, when the target under test accesses Bundle.module, it fails for the same reason as before * This prefers Bundle.main, but if it is inaccessible it falls back to the build output directory path. * Cleaned up changes in BuildPlan.swift Added passing integration test into TestToolTests.swift Added failing integration test into BasicTests.swift * Remove integration test from TestToolTests.swift * Only instantiate Bundle for buildPath if main bundle is not found
1 parent b579726 commit cdcf0e0

File tree

2 files changed

+84
-6
lines changed

2 files changed

+84
-6
lines changed

IntegrationTests/Tests/IntegrationTests/BasicTests.swift

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,4 +232,80 @@ final class BasicTests: XCTestCase {
232232
}
233233
}
234234
}
235+
236+
func testSwiftTestWithResources() throws {
237+
try withTemporaryDirectory { dir in
238+
let toolDir = dir.appending(component: "swiftTestResources")
239+
try localFileSystem.createDirectory(toolDir)
240+
try localFileSystem.writeFileContents(
241+
toolDir.appending(component: "Package.swift"),
242+
bytes: ByteString(encodingAsUTF8: """
243+
// swift-tools-version:5.3
244+
import PackageDescription
245+
246+
let package = Package(
247+
name: "AwesomeResources",
248+
targets: [
249+
.target(name: "AwesomeResources", resources: [.copy("hello.txt")]),
250+
.testTarget(name: "AwesomeResourcesTest", dependencies: ["AwesomeResources"], resources: [.copy("world.txt")])
251+
]
252+
)
253+
""")
254+
)
255+
try localFileSystem.createDirectory(toolDir.appending(component: "Sources"))
256+
try localFileSystem.createDirectory(toolDir.appending(components: "Sources", "AwesomeResources"))
257+
try localFileSystem.writeFileContents(
258+
toolDir.appending(components: "Sources", "AwesomeResources", "AwesomeResource.swift"),
259+
bytes: ByteString(encodingAsUTF8: """
260+
import Foundation
261+
262+
public struct AwesomeResource {
263+
public init() {}
264+
public let hello = try! String(contentsOf: Bundle.module.url(forResource: "hello", withExtension: "txt")!)
265+
}
266+
267+
""")
268+
)
269+
270+
try localFileSystem.writeFileContents(
271+
toolDir.appending(components: "Sources", "AwesomeResources", "hello.txt"),
272+
bytes: ByteString(encodingAsUTF8: "hello")
273+
)
274+
275+
try localFileSystem.createDirectory(toolDir.appending(component: "Tests"))
276+
try localFileSystem.createDirectory(toolDir.appending(components: "Tests", "AwesomeResourcesTest"))
277+
278+
try localFileSystem.writeFileContents(
279+
toolDir.appending(components: "Tests", "AwesomeResourcesTest", "world.txt"),
280+
bytes: ByteString(encodingAsUTF8: "world")
281+
)
282+
283+
try localFileSystem.writeFileContents(
284+
toolDir.appending(components: "Tests", "AwesomeResourcesTest", "MyTests.swift"),
285+
bytes: ByteString(encodingAsUTF8: """
286+
import XCTest
287+
import Foundation
288+
import AwesomeResources
289+
290+
final class MyTests: XCTestCase {
291+
func testFoo() {
292+
XCTAssertTrue(AwesomeResource().hello == "hello")
293+
}
294+
func testBar() {
295+
let world = try! String(contentsOf: Bundle.module.url(forResource: "world", withExtension: "txt")!)
296+
XCTAssertTrue(world == "world")
297+
}
298+
}
299+
"""))
300+
301+
let testOutput = try sh(swiftTest, "--package-path", toolDir, "--filter", "MyTests.*").stderr
302+
303+
// Check the test log.
304+
XCTAssertContents(testOutput) { checker in
305+
checker.check(.contains("Test Suite 'MyTests' started"))
306+
checker.check(.contains("Test Suite 'MyTests' passed"))
307+
checker.check(.contains("Executed 2 tests, with 0 failures"))
308+
}
309+
}
310+
}
235311
}

Sources/Build/BuildPlan.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -582,19 +582,21 @@ public final class SwiftTargetBuildDescription {
582582
// Do nothing if we're not generating a bundle.
583583
guard let bundlePath = self.bundlePath else { return }
584584

585-
// Compute the basename of the bundle.
586-
let bundleBasename = bundlePath.basename
587-
588585
let stream = BufferedOutputByteStream()
589586
stream <<< """
590587
import class Foundation.Bundle
591588
592589
extension Foundation.Bundle {
593590
static var module: Bundle = {
594-
let bundlePath = Bundle.main.bundlePath + "/" + "\(bundleBasename)"
595-
guard let bundle = Bundle(path: bundlePath) else {
596-
fatalError("could not load resource bundle: \\(bundlePath)")
591+
let mainPath = Bundle.main.bundlePath + "/" + "\(bundlePath.basename)"
592+
let buildPath = "\(bundlePath.pathString)"
593+
594+
let preferredBundle = Bundle(path: mainPath)
595+
596+
guard let bundle = preferredBundle != nil ? preferredBundle : Bundle(path: buildPath) else {
597+
fatalError("could not load resource bundle: from \\(mainPath) or \\(buildPath)")
597598
}
599+
598600
return bundle
599601
}()
600602
}

0 commit comments

Comments
 (0)