diff --git a/IntegrationTests/Tests/IntegrationTests/BasicTests.swift b/IntegrationTests/Tests/IntegrationTests/BasicTests.swift index 68064a3e64f..17ae7b0e329 100644 --- a/IntegrationTests/Tests/IntegrationTests/BasicTests.swift +++ b/IntegrationTests/Tests/IntegrationTests/BasicTests.swift @@ -232,4 +232,80 @@ final class BasicTests: XCTestCase { } } } + + func testSwiftTestWithResources() throws { + try withTemporaryDirectory { dir in + let toolDir = dir.appending(component: "swiftTestResources") + try localFileSystem.createDirectory(toolDir) + try localFileSystem.writeFileContents( + toolDir.appending(component: "Package.swift"), + bytes: ByteString(encodingAsUTF8: """ + // swift-tools-version:5.3 + import PackageDescription + + let package = Package( + name: "AwesomeResources", + targets: [ + .target(name: "AwesomeResources", resources: [.copy("hello.txt")]), + .testTarget(name: "AwesomeResourcesTest", dependencies: ["AwesomeResources"], resources: [.copy("world.txt")]) + ] + ) + """) + ) + try localFileSystem.createDirectory(toolDir.appending(component: "Sources")) + try localFileSystem.createDirectory(toolDir.appending(components: "Sources", "AwesomeResources")) + try localFileSystem.writeFileContents( + toolDir.appending(components: "Sources", "AwesomeResources", "AwesomeResource.swift"), + bytes: ByteString(encodingAsUTF8: """ + import Foundation + + public struct AwesomeResource { + public init() {} + public let hello = try! String(contentsOf: Bundle.module.url(forResource: "hello", withExtension: "txt")!) + } + + """) + ) + + try localFileSystem.writeFileContents( + toolDir.appending(components: "Sources", "AwesomeResources", "hello.txt"), + bytes: ByteString(encodingAsUTF8: "hello") + ) + + try localFileSystem.createDirectory(toolDir.appending(component: "Tests")) + try localFileSystem.createDirectory(toolDir.appending(components: "Tests", "AwesomeResourcesTest")) + + try localFileSystem.writeFileContents( + toolDir.appending(components: "Tests", "AwesomeResourcesTest", "world.txt"), + bytes: ByteString(encodingAsUTF8: "world") + ) + + try localFileSystem.writeFileContents( + toolDir.appending(components: "Tests", "AwesomeResourcesTest", "MyTests.swift"), + bytes: ByteString(encodingAsUTF8: """ + import XCTest + import Foundation + import AwesomeResources + + final class MyTests: XCTestCase { + func testFoo() { + XCTAssertTrue(AwesomeResource().hello == "hello") + } + func testBar() { + let world = try! String(contentsOf: Bundle.module.url(forResource: "world", withExtension: "txt")!) + XCTAssertTrue(world == "world") + } + } + """)) + + let testOutput = try sh(swiftTest, "--package-path", toolDir, "--filter", "MyTests.*").stderr + +// Check the test log. + XCTAssertContents(testOutput) { checker in + checker.check(.contains("Test Suite 'MyTests' started")) + checker.check(.contains("Test Suite 'MyTests' passed")) + checker.check(.contains("Executed 2 tests, with 0 failures")) + } + } + } } diff --git a/Sources/Build/BuildPlan.swift b/Sources/Build/BuildPlan.swift index 01e9a23787a..9a8d21877de 100644 --- a/Sources/Build/BuildPlan.swift +++ b/Sources/Build/BuildPlan.swift @@ -578,19 +578,21 @@ public final class SwiftTargetBuildDescription { // Do nothing if we're not generating a bundle. guard let bundlePath = self.bundlePath else { return } - // Compute the basename of the bundle. - let bundleBasename = bundlePath.basename - let stream = BufferedOutputByteStream() stream <<< """ import class Foundation.Bundle extension Foundation.Bundle { static var module: Bundle = { - let bundlePath = Bundle.main.bundlePath + "/" + "\(bundleBasename)" - guard let bundle = Bundle(path: bundlePath) else { - fatalError("could not load resource bundle: \\(bundlePath)") + let mainPath = Bundle.main.bundlePath + "/" + "\(bundlePath.basename)" + let buildPath = "\(bundlePath.pathString)" + + let preferredBundle = Bundle(path: mainPath) + + guard let bundle = preferredBundle != nil ? preferredBundle : Bundle(path: buildPath) else { + fatalError("could not load resource bundle: from \\(mainPath) or \\(buildPath)") } + return bundle }() }