From d8197b43b251338069f4f2097a3db80d905587b3 Mon Sep 17 00:00:00 2001 From: Boris Buegling Date: Wed, 15 Jan 2025 14:11:02 -0800 Subject: [PATCH] `_InternalTestSupport` should not depend on `Build` Looks like something I caused a while ago in d457fa46b3 which was later further entrenched in `PluginInvocationTests`, but we should keep the "data model" and "build" parts of SwiftPM separate, so this PR cleans that up again. --- Package.swift | 15 +- .../MockBuildTestHelper.swift | 229 ++++++++++++++++++ .../MockBuildTestHelper.swift | 207 ---------------- Tests/BuildTests/BuildPlanTests.swift | 1 + .../CrossCompilationBuildPlanTests.swift | 4 +- .../LLBuildManifestBuilderTests.swift | 1 + .../BuildTests/ModuleAliasingBuildTests.swift | 1 + .../PluginInvocationTests.swift | 1 + 8 files changed, 248 insertions(+), 211 deletions(-) create mode 100644 Sources/_InternalBuildTestSupport/MockBuildTestHelper.swift rename Tests/{SPMBuildCoreTests => BuildTests}/PluginInvocationTests.swift (99%) diff --git a/Package.swift b/Package.swift index 2a68dc5cc5f..7560820f2fc 100644 --- a/Package.swift +++ b/Package.swift @@ -682,12 +682,23 @@ let package = Package( // MARK: Additional Test Dependencies + .target( + /** SwiftPM internal build test suite support library */ + name: "_InternalBuildTestSupport", + dependencies: [ + "Build", + "_InternalTestSupport" + ], + swiftSettings: [ + .unsafeFlags(["-static"]), + ] + ), + .target( /** SwiftPM internal test suite support library */ name: "_InternalTestSupport", dependencies: [ "Basics", - "Build", "PackageFingerprint", "PackageGraph", "PackageLoading", @@ -748,7 +759,7 @@ let package = Package( ), .testTarget( name: "BuildTests", - dependencies: ["Build", "PackageModel", "Commands", "_InternalTestSupport"] + dependencies: ["Build", "PackageModel", "Commands", "_InternalTestSupport", "_InternalBuildTestSupport"] ), .testTarget( name: "LLBuildManifestTests", diff --git a/Sources/_InternalBuildTestSupport/MockBuildTestHelper.swift b/Sources/_InternalBuildTestSupport/MockBuildTestHelper.swift new file mode 100644 index 00000000000..bcdc42a519a --- /dev/null +++ b/Sources/_InternalBuildTestSupport/MockBuildTestHelper.swift @@ -0,0 +1,229 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import Basics + +@_spi(SwiftPMInternal) +import Build + +import _InternalTestSupport +import struct PackageGraph.ModulesGraph +import struct PackageGraph.ResolvedModule +import struct PackageGraph.ResolvedProduct +import PackageModel +import SPMBuildCore +import TSCUtility +import XCTest + +public func mockBuildPlan( + buildPath: AbsolutePath? = nil, + environment: BuildEnvironment, + toolchain: PackageModel.Toolchain = MockToolchain(), + graph: ModulesGraph, + commonFlags: PackageModel.BuildFlags = .init(), + indexStoreMode: BuildParameters.IndexStoreMode = .off, + omitFramePointers: Bool? = nil, + driverParameters: BuildParameters.Driver = .init(), + linkingParameters: BuildParameters.Linking = .init(), + targetSanitizers: EnabledSanitizers = .init(), + fileSystem fs: any FileSystem, + observabilityScope: ObservabilityScope +) async throws -> Build.BuildPlan { + try await mockBuildPlan( + buildPath: buildPath, + config: environment.configuration ?? .debug, + platform: environment.platform, + toolchain: toolchain, + graph: graph, + commonFlags: commonFlags, + indexStoreMode: indexStoreMode, + omitFramePointers: omitFramePointers, + driverParameters: driverParameters, + linkingParameters: linkingParameters, + targetSanitizers: targetSanitizers, + fileSystem: fs, + observabilityScope: observabilityScope + ) +} + +public func mockBuildPlan( + buildPath: AbsolutePath? = nil, + config: BuildConfiguration = .debug, + triple: Basics.Triple? = nil, + platform: PackageModel.Platform? = nil, + toolchain: PackageModel.Toolchain = MockToolchain(), + graph: ModulesGraph, + commonFlags: PackageModel.BuildFlags = .init(), + indexStoreMode: BuildParameters.IndexStoreMode = .off, + omitFramePointers: Bool? = nil, + driverParameters: BuildParameters.Driver = .init(), + linkingParameters: BuildParameters.Linking = .init(), + targetSanitizers: EnabledSanitizers = .init(), + fileSystem fs: any FileSystem, + observabilityScope: ObservabilityScope +) async throws -> Build.BuildPlan { + let inferredTriple: Basics.Triple + if let platform { + precondition(triple == nil) + + inferredTriple = switch platform { + case .macOS: + Triple.x86_64MacOS + case .linux: + Triple.arm64Linux + case .android: + Triple.arm64Android + case .windows: + Triple.windows + default: + fatalError("unsupported platform in tests") + } + } else { + inferredTriple = triple ?? hostTriple + } + + let commonDebuggingParameters = BuildParameters.Debugging( + triple: inferredTriple, + shouldEnableDebuggingEntitlement: config == .debug, + omitFramePointers: omitFramePointers + ) + + var destinationParameters = mockBuildParameters( + destination: .target, + buildPath: buildPath, + config: config, + toolchain: toolchain, + flags: commonFlags, + triple: inferredTriple, + indexStoreMode: indexStoreMode + ) + destinationParameters.debuggingParameters = commonDebuggingParameters + destinationParameters.driverParameters = driverParameters + destinationParameters.linkingParameters = linkingParameters + destinationParameters.sanitizers = targetSanitizers + + var hostParameters = mockBuildParameters( + destination: .host, + buildPath: buildPath, + config: config, + toolchain: toolchain, + flags: commonFlags, + triple: inferredTriple, + indexStoreMode: indexStoreMode + ) + hostParameters.debuggingParameters = commonDebuggingParameters + hostParameters.driverParameters = driverParameters + hostParameters.linkingParameters = linkingParameters + + return try await BuildPlan( + destinationBuildParameters: destinationParameters, + toolsBuildParameters: hostParameters, + graph: graph, + fileSystem: fs, + observabilityScope: observabilityScope + ) +} + +package func mockPluginTools( + plugins: IdentifiableSet, + fileSystem: any FileSystem, + buildParameters: BuildParameters, + hostTriple: Basics.Triple +) async throws -> [ResolvedModule.ID: [String: PluginTool]] { + var accessibleToolsPerPlugin: [ResolvedModule.ID: [String: PluginTool]] = [:] + for plugin in plugins where accessibleToolsPerPlugin[plugin.id] == nil { + let accessibleTools = try await plugin.preparePluginTools( + fileSystem: fileSystem, + environment: buildParameters.buildEnvironment, + for: hostTriple + ) { name, path in + buildParameters.buildPath.appending(path) + } + + accessibleToolsPerPlugin[plugin.id] = accessibleTools + } + + return accessibleToolsPerPlugin +} + +enum BuildError: Swift.Error { + case error(String) +} + +public struct BuildPlanResult { + public let plan: Build.BuildPlan + + public var productMap: IdentifiableSet { + self.plan.productMap + } + + public var targetMap: IdentifiableSet { + self.plan.targetMap + } + + public init(plan: Build.BuildPlan) throws { + self.plan = plan + } + + public func checkTargetsCount(_ count: Int, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(self.targetMap.count, count, file: file, line: line) + } + + public func checkProductsCount(_ count: Int, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(self.productMap.count, count, file: file, line: line) + } + + public func moduleBuildDescription(for name: String) throws -> Build.ModuleBuildDescription { + let matches = self.targetMap.filter({ $0.module.name == name }) + guard matches.count == 1 else { + if matches.isEmpty { + throw BuildError.error("Target \(name) not found.") + } else { + throw BuildError.error("More than one target \(name) found.") + } + } + return matches.first! + } + + public func buildProduct(for name: String) throws -> Build.ProductBuildDescription { + let matches = self.productMap.filter({ $0.product.name == name }) + guard matches.count == 1 else { + if matches.isEmpty { + // Display the thrown error on macOS + throw BuildError.error("Product \(name) not found.") + } else { + throw BuildError.error("More than one target \(name) found.") + } + } + return matches.first! + } +} + +extension Build.ModuleBuildDescription { + public func swift() throws -> SwiftModuleBuildDescription { + switch self { + case .swift(let description): + return description + default: + throw BuildError.error("Unexpected \(self) type found") + } + } + + public func clang() throws -> ClangModuleBuildDescription { + switch self { + case .clang(let description): + return description + default: + throw BuildError.error("Unexpected \(self) type") + } + } +} diff --git a/Sources/_InternalTestSupport/MockBuildTestHelper.swift b/Sources/_InternalTestSupport/MockBuildTestHelper.swift index 339d56a502d..97d9514482b 100644 --- a/Sources/_InternalTestSupport/MockBuildTestHelper.swift +++ b/Sources/_InternalTestSupport/MockBuildTestHelper.swift @@ -12,9 +12,6 @@ import Basics -@_spi(SwiftPMInternal) -import Build - import struct PackageGraph.ModulesGraph import struct PackageGraph.ResolvedModule import struct PackageGraph.ResolvedProduct @@ -149,207 +146,3 @@ public func mockBuildParameters( triple: triple ) } - -public func mockBuildPlan( - buildPath: AbsolutePath? = nil, - environment: BuildEnvironment, - toolchain: PackageModel.Toolchain = MockToolchain(), - graph: ModulesGraph, - commonFlags: PackageModel.BuildFlags = .init(), - indexStoreMode: BuildParameters.IndexStoreMode = .off, - omitFramePointers: Bool? = nil, - driverParameters: BuildParameters.Driver = .init(), - linkingParameters: BuildParameters.Linking = .init(), - targetSanitizers: EnabledSanitizers = .init(), - fileSystem fs: any FileSystem, - observabilityScope: ObservabilityScope -) async throws -> Build.BuildPlan { - try await mockBuildPlan( - buildPath: buildPath, - config: environment.configuration ?? .debug, - platform: environment.platform, - toolchain: toolchain, - graph: graph, - commonFlags: commonFlags, - indexStoreMode: indexStoreMode, - omitFramePointers: omitFramePointers, - driverParameters: driverParameters, - linkingParameters: linkingParameters, - targetSanitizers: targetSanitizers, - fileSystem: fs, - observabilityScope: observabilityScope - ) -} - -public func mockBuildPlan( - buildPath: AbsolutePath? = nil, - config: BuildConfiguration = .debug, - triple: Basics.Triple? = nil, - platform: PackageModel.Platform? = nil, - toolchain: PackageModel.Toolchain = MockToolchain(), - graph: ModulesGraph, - commonFlags: PackageModel.BuildFlags = .init(), - indexStoreMode: BuildParameters.IndexStoreMode = .off, - omitFramePointers: Bool? = nil, - driverParameters: BuildParameters.Driver = .init(), - linkingParameters: BuildParameters.Linking = .init(), - targetSanitizers: EnabledSanitizers = .init(), - fileSystem fs: any FileSystem, - observabilityScope: ObservabilityScope -) async throws -> Build.BuildPlan { - let inferredTriple: Basics.Triple - if let platform { - precondition(triple == nil) - - inferredTriple = switch platform { - case .macOS: - Triple.x86_64MacOS - case .linux: - Triple.arm64Linux - case .android: - Triple.arm64Android - case .windows: - Triple.windows - default: - fatalError("unsupported platform in tests") - } - } else { - inferredTriple = triple ?? hostTriple - } - - let commonDebuggingParameters = BuildParameters.Debugging( - triple: inferredTriple, - shouldEnableDebuggingEntitlement: config == .debug, - omitFramePointers: omitFramePointers - ) - - var destinationParameters = mockBuildParameters( - destination: .target, - buildPath: buildPath, - config: config, - toolchain: toolchain, - flags: commonFlags, - triple: inferredTriple, - indexStoreMode: indexStoreMode - ) - destinationParameters.debuggingParameters = commonDebuggingParameters - destinationParameters.driverParameters = driverParameters - destinationParameters.linkingParameters = linkingParameters - destinationParameters.sanitizers = targetSanitizers - - var hostParameters = mockBuildParameters( - destination: .host, - buildPath: buildPath, - config: config, - toolchain: toolchain, - flags: commonFlags, - triple: inferredTriple, - indexStoreMode: indexStoreMode - ) - hostParameters.debuggingParameters = commonDebuggingParameters - hostParameters.driverParameters = driverParameters - hostParameters.linkingParameters = linkingParameters - - return try await BuildPlan( - destinationBuildParameters: destinationParameters, - toolsBuildParameters: hostParameters, - graph: graph, - fileSystem: fs, - observabilityScope: observabilityScope - ) -} - -package func mockPluginTools( - plugins: IdentifiableSet, - fileSystem: any FileSystem, - buildParameters: BuildParameters, - hostTriple: Basics.Triple -) async throws -> [ResolvedModule.ID: [String: PluginTool]] { - var accessibleToolsPerPlugin: [ResolvedModule.ID: [String: PluginTool]] = [:] - for plugin in plugins where accessibleToolsPerPlugin[plugin.id] == nil { - let accessibleTools = try await plugin.preparePluginTools( - fileSystem: fileSystem, - environment: buildParameters.buildEnvironment, - for: hostTriple - ) { name, path in - buildParameters.buildPath.appending(path) - } - - accessibleToolsPerPlugin[plugin.id] = accessibleTools - } - - return accessibleToolsPerPlugin -} - -enum BuildError: Swift.Error { - case error(String) -} - -public struct BuildPlanResult { - public let plan: Build.BuildPlan - - public var productMap: IdentifiableSet { - self.plan.productMap - } - - public var targetMap: IdentifiableSet { - self.plan.targetMap - } - - public init(plan: Build.BuildPlan) throws { - self.plan = plan - } - - public func checkTargetsCount(_ count: Int, file: StaticString = #file, line: UInt = #line) { - XCTAssertEqual(self.targetMap.count, count, file: file, line: line) - } - - public func checkProductsCount(_ count: Int, file: StaticString = #file, line: UInt = #line) { - XCTAssertEqual(self.productMap.count, count, file: file, line: line) - } - - public func moduleBuildDescription(for name: String) throws -> Build.ModuleBuildDescription { - let matches = self.targetMap.filter({ $0.module.name == name }) - guard matches.count == 1 else { - if matches.isEmpty { - throw BuildError.error("Target \(name) not found.") - } else { - throw BuildError.error("More than one target \(name) found.") - } - } - return matches.first! - } - - public func buildProduct(for name: String) throws -> Build.ProductBuildDescription { - let matches = self.productMap.filter({ $0.product.name == name }) - guard matches.count == 1 else { - if matches.isEmpty { - // Display the thrown error on macOS - throw BuildError.error("Product \(name) not found.") - } else { - throw BuildError.error("More than one target \(name) found.") - } - } - return matches.first! - } -} - -extension Build.ModuleBuildDescription { - public func swift() throws -> SwiftModuleBuildDescription { - switch self { - case .swift(let description): - return description - default: - throw BuildError.error("Unexpected \(self) type found") - } - } - - public func clang() throws -> ClangModuleBuildDescription { - switch self { - case .clang(let description): - return description - default: - throw BuildError.error("Unexpected \(self) type") - } - } -} diff --git a/Tests/BuildTests/BuildPlanTests.swift b/Tests/BuildTests/BuildPlanTests.swift index c5d1814c8de..5ce7b2c3dd5 100644 --- a/Tests/BuildTests/BuildPlanTests.swift +++ b/Tests/BuildTests/BuildPlanTests.swift @@ -26,6 +26,7 @@ import PackageLoading @testable import PackageModel import SPMBuildCore +import _InternalBuildTestSupport import _InternalTestSupport import SwiftDriver import Workspace diff --git a/Tests/BuildTests/CrossCompilationBuildPlanTests.swift b/Tests/BuildTests/CrossCompilationBuildPlanTests.swift index 76e37ccc907..4b006cd7af9 100644 --- a/Tests/BuildTests/CrossCompilationBuildPlanTests.swift +++ b/Tests/BuildTests/CrossCompilationBuildPlanTests.swift @@ -28,11 +28,11 @@ import func _InternalTestSupport.embeddedCxxInteropPackageGraph import func _InternalTestSupport.macrosPackageGraph import func _InternalTestSupport.macrosTestsPackageGraph import func _InternalTestSupport.mockBuildParameters -import func _InternalTestSupport.mockBuildPlan +import func _InternalBuildTestSupport.mockBuildPlan import func _InternalTestSupport.toolsExplicitLibrariesGraph import func _InternalTestSupport.trivialPackageGraph -import struct _InternalTestSupport.BuildPlanResult +import struct _InternalBuildTestSupport.BuildPlanResult import func _InternalTestSupport.XCTAssertMatch import func _InternalTestSupport.XCTAssertNoDiagnostics diff --git a/Tests/BuildTests/LLBuildManifestBuilderTests.swift b/Tests/BuildTests/LLBuildManifestBuilderTests.swift index 1ac28956ab6..c4a0b787bb9 100644 --- a/Tests/BuildTests/LLBuildManifestBuilderTests.swift +++ b/Tests/BuildTests/LLBuildManifestBuilderTests.swift @@ -20,6 +20,7 @@ import PackageGraph import PackageModel import struct SPMBuildCore.BuildParameters +import _InternalBuildTestSupport @_spi(SwiftPMInternal) import _InternalTestSupport diff --git a/Tests/BuildTests/ModuleAliasingBuildTests.swift b/Tests/BuildTests/ModuleAliasingBuildTests.swift index 5cc0db97c4b..1678f7f2f1d 100644 --- a/Tests/BuildTests/ModuleAliasingBuildTests.swift +++ b/Tests/BuildTests/ModuleAliasingBuildTests.swift @@ -19,6 +19,7 @@ import Basics import PackageLoading @testable import PackageModel import SPMBuildCore +import _InternalBuildTestSupport import _InternalTestSupport import SwiftDriver import Workspace diff --git a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift b/Tests/BuildTests/PluginInvocationTests.swift similarity index 99% rename from Tests/SPMBuildCoreTests/PluginInvocationTests.swift rename to Tests/BuildTests/PluginInvocationTests.swift index b262e28eb7c..2601571748e 100644 --- a/Tests/SPMBuildCoreTests/PluginInvocationTests.swift +++ b/Tests/BuildTests/PluginInvocationTests.swift @@ -22,6 +22,7 @@ import PackageLoading import PackageModel @testable import SPMBuildCore +import _InternalBuildTestSupport import _InternalTestSupport import Workspace import XCTest