From c1f1cf351b4770956e70fd7a051d7b897d37b275 Mon Sep 17 00:00:00 2001 From: Owen Voorhees Date: Wed, 4 Jun 2025 13:17:38 -0700 Subject: [PATCH] Revert "XCTest discovery support for non-Darwin platforms" --- .../Specs/DarwinProductTypes.xcspec | 13 - Sources/SWBCSupport/IndexStore.h | 194 ------ Sources/SWBCSupport/SWBCSupport.h | 1 - Sources/SWBCore/Settings/BuiltinMacros.swift | 2 - .../SpecImplementations/ProductTypes.swift | 10 +- .../Tools/SwiftCompiler.swift | 3 - .../SWBGenericUnixPlatform/Specs/Unix.xcspec | 35 +- .../SWBProjectModel/PIFGenerationModel.swift | 2 - Sources/SWBQNXPlatform/Specs/QNX.xcspec | 33 +- .../ProductPlanning/ProductPlan.swift | 2 +- .../InfoPlistTaskProducer.swift | 2 +- .../SwiftStandardLibrariesTaskProducer.swift | 2 +- Sources/SWBTestSupport/TestWorkspaces.swift | 6 +- .../Specs/ProductTypes.xcspec | 15 - .../TestEntryPointGenerationTaskAction.swift | 603 +----------------- .../TestEntryPointGenerationTool.swift | 52 -- .../TestEntryPointTaskProducer.swift | 51 +- Sources/SWBUtil/CMakeLists.txt | 1 - Sources/SWBUtil/IndexStore.swift | 389 ----------- .../SWBWindowsPlatform/Specs/Windows.xcspec | 25 - .../ProjectModel/BuildSettings.swift | 2 - Sources/SwiftBuild/ProjectModel/Targets.swift | 1 - .../BuildOperationTests.swift | 52 +- .../UnitTestTaskConstructionTests.swift | 35 +- 24 files changed, 89 insertions(+), 1442 deletions(-) delete mode 100644 Sources/SWBCSupport/IndexStore.h delete mode 100644 Sources/SWBUtil/IndexStore.swift diff --git a/Sources/SWBApplePlatform/Specs/DarwinProductTypes.xcspec b/Sources/SWBApplePlatform/Specs/DarwinProductTypes.xcspec index d6e43e3f..e1bc5a17 100644 --- a/Sources/SWBApplePlatform/Specs/DarwinProductTypes.xcspec +++ b/Sources/SWBApplePlatform/Specs/DarwinProductTypes.xcspec @@ -461,17 +461,4 @@ ); Platforms = (driverkit); }, - { - _Domain = darwin; - Type = ProductType; - Identifier = com.apple.product-type.tool.swiftpm-test-runner; - Name = "SwiftPM Unit Test Runner"; - Description = "SwiftPM Unit Test Runner"; - DefaultBuildProperties = { - __SKIP_BUILD = YES; - }; - PackageTypes = ( - com.apple.package-type.mach-o-executable - ); - }, ) diff --git a/Sources/SWBCSupport/IndexStore.h b/Sources/SWBCSupport/IndexStore.h deleted file mode 100644 index 7d4b77b8..00000000 --- a/Sources/SWBCSupport/IndexStore.h +++ /dev/null @@ -1,194 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -#ifndef INDEXSTORE_H -#define INDEXSTORE_H - -#include -#include -#include -#include - -typedef void *indexstore_error_t; - -typedef struct { - const char *data; - size_t length; -} indexstore_string_ref_t; - -typedef void *indexstore_t; -typedef void *indexstore_symbol_t; - -typedef enum { - INDEXSTORE_SYMBOL_KIND_UNKNOWN = 0, - INDEXSTORE_SYMBOL_KIND_MODULE = 1, - INDEXSTORE_SYMBOL_KIND_NAMESPACE = 2, - INDEXSTORE_SYMBOL_KIND_NAMESPACEALIAS = 3, - INDEXSTORE_SYMBOL_KIND_MACRO = 4, - INDEXSTORE_SYMBOL_KIND_ENUM = 5, - INDEXSTORE_SYMBOL_KIND_STRUCT = 6, - INDEXSTORE_SYMBOL_KIND_CLASS = 7, - INDEXSTORE_SYMBOL_KIND_PROTOCOL = 8, - INDEXSTORE_SYMBOL_KIND_EXTENSION = 9, - INDEXSTORE_SYMBOL_KIND_UNION = 10, - INDEXSTORE_SYMBOL_KIND_TYPEALIAS = 11, - INDEXSTORE_SYMBOL_KIND_FUNCTION = 12, - INDEXSTORE_SYMBOL_KIND_VARIABLE = 13, - INDEXSTORE_SYMBOL_KIND_FIELD = 14, - INDEXSTORE_SYMBOL_KIND_ENUMCONSTANT = 15, - INDEXSTORE_SYMBOL_KIND_INSTANCEMETHOD = 16, - INDEXSTORE_SYMBOL_KIND_CLASSMETHOD = 17, - INDEXSTORE_SYMBOL_KIND_STATICMETHOD = 18, - INDEXSTORE_SYMBOL_KIND_INSTANCEPROPERTY = 19, - INDEXSTORE_SYMBOL_KIND_CLASSPROPERTY = 20, - INDEXSTORE_SYMBOL_KIND_STATICPROPERTY = 21, - INDEXSTORE_SYMBOL_KIND_CONSTRUCTOR = 22, - INDEXSTORE_SYMBOL_KIND_DESTRUCTOR = 23, - INDEXSTORE_SYMBOL_KIND_CONVERSIONFUNCTION = 24, - INDEXSTORE_SYMBOL_KIND_PARAMETER = 25, - INDEXSTORE_SYMBOL_KIND_USING = 26, - - INDEXSTORE_SYMBOL_KIND_COMMENTTAG = 1000, -} indexstore_symbol_kind_t; - -typedef enum { - INDEXSTORE_SYMBOL_PROPERTY_GENERIC = 1 << 0, - INDEXSTORE_SYMBOL_PROPERTY_TEMPLATE_PARTIAL_SPECIALIZATION = 1 << 1, - INDEXSTORE_SYMBOL_PROPERTY_TEMPLATE_SPECIALIZATION = 1 << 2, - INDEXSTORE_SYMBOL_PROPERTY_UNITTEST = 1 << 3, - INDEXSTORE_SYMBOL_PROPERTY_IBANNOTATED = 1 << 4, - INDEXSTORE_SYMBOL_PROPERTY_IBOUTLETCOLLECTION = 1 << 5, - INDEXSTORE_SYMBOL_PROPERTY_GKINSPECTABLE = 1 << 6, - INDEXSTORE_SYMBOL_PROPERTY_LOCAL = 1 << 7, - INDEXSTORE_SYMBOL_PROPERTY_PROTOCOL_INTERFACE = 1 << 8, - INDEXSTORE_SYMBOL_PROPERTY_SWIFT_ASYNC = 1 << 16, -} indexstore_symbol_property_t; - -typedef enum { - INDEXSTORE_SYMBOL_ROLE_DECLARATION = 1 << 0, - INDEXSTORE_SYMBOL_ROLE_DEFINITION = 1 << 1, - INDEXSTORE_SYMBOL_ROLE_REFERENCE = 1 << 2, - INDEXSTORE_SYMBOL_ROLE_READ = 1 << 3, - INDEXSTORE_SYMBOL_ROLE_WRITE = 1 << 4, - INDEXSTORE_SYMBOL_ROLE_CALL = 1 << 5, - INDEXSTORE_SYMBOL_ROLE_DYNAMIC = 1 << 6, - INDEXSTORE_SYMBOL_ROLE_ADDRESSOF = 1 << 7, - INDEXSTORE_SYMBOL_ROLE_IMPLICIT = 1 << 8, - INDEXSTORE_SYMBOL_ROLE_UNDEFINITION = 1 << 19, - - // Relation roles. - INDEXSTORE_SYMBOL_ROLE_REL_CHILDOF = 1 << 9, - INDEXSTORE_SYMBOL_ROLE_REL_BASEOF = 1 << 10, - INDEXSTORE_SYMBOL_ROLE_REL_OVERRIDEOF = 1 << 11, - INDEXSTORE_SYMBOL_ROLE_REL_RECEIVEDBY = 1 << 12, - INDEXSTORE_SYMBOL_ROLE_REL_CALLEDBY = 1 << 13, - INDEXSTORE_SYMBOL_ROLE_REL_EXTENDEDBY = 1 << 14, - INDEXSTORE_SYMBOL_ROLE_REL_ACCESSOROF = 1 << 15, - INDEXSTORE_SYMBOL_ROLE_REL_CONTAINEDBY = 1 << 16, - INDEXSTORE_SYMBOL_ROLE_REL_IBTYPEOF = 1 << 17, - INDEXSTORE_SYMBOL_ROLE_REL_SPECIALIZATIONOF = 1 << 18, -} indexstore_symbol_role_t; - -typedef void *indexstore_unit_dependency_t; - -typedef enum { - INDEXSTORE_UNIT_DEPENDENCY_UNIT = 1, - INDEXSTORE_UNIT_DEPENDENCY_RECORD = 2, - INDEXSTORE_UNIT_DEPENDENCY_FILE = 3, -} indexstore_unit_dependency_kind_t; - -typedef void *indexstore_symbol_relation_t; -typedef void *indexstore_occurrence_t; -typedef void *indexstore_record_reader_t; -typedef void *indexstore_unit_reader_t; - -typedef struct { - const char * - (*error_get_description)(indexstore_error_t); - - void - (*error_dispose)(indexstore_error_t); - - indexstore_t - (*store_create)(const char *store_path, indexstore_error_t *error); - - void - (*store_dispose)(indexstore_t); - - size_t - (*store_get_unit_name_from_output_path)(indexstore_t store, - const char *output_path, - char *name_buf, - size_t buf_size); - - indexstore_symbol_kind_t - (*symbol_get_kind)(indexstore_symbol_t); - - uint64_t - (*symbol_get_properties)(indexstore_symbol_t); - - indexstore_string_ref_t - (*symbol_get_name)(indexstore_symbol_t); - - uint64_t - (*symbol_relation_get_roles)(indexstore_symbol_relation_t); - - indexstore_symbol_t - (*symbol_relation_get_symbol)(indexstore_symbol_relation_t); - - indexstore_symbol_t - (*occurrence_get_symbol)(indexstore_occurrence_t); - - bool - (*occurrence_relations_apply_f)(indexstore_occurrence_t, - void *context, - bool(*applier)(void *context, indexstore_symbol_relation_t symbol_rel)); - - indexstore_record_reader_t - (*record_reader_create)(indexstore_t store, const char *record_name, - indexstore_error_t *error); - - void - (*record_reader_dispose)(indexstore_record_reader_t); - - bool - (*record_reader_occurrences_apply_f)(indexstore_record_reader_t, - void *context, - bool(*applier)(void *context, indexstore_occurrence_t occur)); - - indexstore_unit_reader_t - (*unit_reader_create)(indexstore_t store, const char *unit_name, - indexstore_error_t *error); - - void - (*unit_reader_dispose)(indexstore_unit_reader_t); - - indexstore_string_ref_t - (*unit_reader_get_module_name)(indexstore_unit_reader_t); - - indexstore_unit_dependency_kind_t - (*unit_dependency_get_kind)(indexstore_unit_dependency_t); - - indexstore_string_ref_t - (*unit_dependency_get_name)(indexstore_unit_dependency_t); - - bool - (*unit_reader_dependencies_apply)(indexstore_unit_reader_t, - bool(^applier)(indexstore_unit_dependency_t)); - - bool - (*unit_reader_dependencies_apply_f)(indexstore_unit_reader_t, - void *context, - bool(*applier)(void *context, indexstore_unit_dependency_t)); -} indexstore_functions_t; - -#endif diff --git a/Sources/SWBCSupport/SWBCSupport.h b/Sources/SWBCSupport/SWBCSupport.h index 18591c94..c020472c 100644 --- a/Sources/SWBCSupport/SWBCSupport.h +++ b/Sources/SWBCSupport/SWBCSupport.h @@ -21,7 +21,6 @@ #include "CLibclang.h" #include "CLibRemarksHelper.h" -#include "IndexStore.h" #include "PluginAPI.h" #include "PluginAPI_functions.h" #include "PluginAPI_types.h" diff --git a/Sources/SWBCore/Settings/BuiltinMacros.swift b/Sources/SWBCore/Settings/BuiltinMacros.swift index 52beb989..0ac934ff 100644 --- a/Sources/SWBCore/Settings/BuiltinMacros.swift +++ b/Sources/SWBCore/Settings/BuiltinMacros.swift @@ -750,7 +750,6 @@ public final class BuiltinMacros { public static let INDEX_PREPARED_TARGET_MARKER_PATH = BuiltinMacros.declareStringMacro("INDEX_PREPARED_TARGET_MARKER_PATH") public static let INDEX_REGULAR_BUILD_PRODUCTS_DIR = BuiltinMacros.declareStringMacro("INDEX_REGULAR_BUILD_PRODUCTS_DIR") public static let INDEX_REGULAR_BUILD_INTERMEDIATES_DIR = BuiltinMacros.declareStringMacro("INDEX_REGULAR_BUILD_INTERMEDIATES_DIR") - public static let INDEX_STORE_LIBRARY_PATH = BuiltinMacros.declarePathMacro("INDEX_STORE_LIBRARY_PATH") public static let INFOPLIST_ENFORCE_MINIMUM_OS = BuiltinMacros.declareBooleanMacro("INFOPLIST_ENFORCE_MINIMUM_OS") public static let INFOPLIST_EXPAND_BUILD_SETTINGS = BuiltinMacros.declareBooleanMacro("INFOPLIST_EXPAND_BUILD_SETTINGS") public static let INFOPLIST_FILE = BuiltinMacros.declarePathMacro("INFOPLIST_FILE") @@ -1797,7 +1796,6 @@ public final class BuiltinMacros { INDEX_PREPARED_TARGET_MARKER_PATH, INDEX_REGULAR_BUILD_PRODUCTS_DIR, INDEX_REGULAR_BUILD_INTERMEDIATES_DIR, - INDEX_STORE_LIBRARY_PATH, INDEX_ENABLE_DATA_STORE, INDEX_PRECOMPS_DIR, INFOPLIST_ENFORCE_MINIMUM_OS, diff --git a/Sources/SWBCore/SpecImplementations/ProductTypes.swift b/Sources/SWBCore/SpecImplementations/ProductTypes.swift index 28415e4b..7cb6a1d5 100644 --- a/Sources/SWBCore/SpecImplementations/ProductTypes.swift +++ b/Sources/SWBCore/SpecImplementations/ProductTypes.swift @@ -321,7 +321,7 @@ public class ProductTypeSpec : Spec, SpecType, @unchecked Sendable { } /// Returns whether the product type supports embedding Swift standard libraries inside it. - public func supportsEmbeddingSwiftStandardLibraries(producer: CommandProducer) -> Bool { + public var supportsEmbeddingSwiftStandardLibraries: Bool { // Most product types don't support having the Swift libraries embedded in them. return false } @@ -381,7 +381,7 @@ public final class ApplicationProductTypeSpec : BundleProductTypeSpec, @unchecke return "PBXApplicationProductType" } - public override func supportsEmbeddingSwiftStandardLibraries(producer: CommandProducer) -> Bool { + public override var supportsEmbeddingSwiftStandardLibraries: Bool { return true } @@ -602,8 +602,8 @@ public final class XCTestBundleProductTypeSpec : BundleProductTypeSpec, @uncheck super.init(parser, basedOnSpec) } - public override func supportsEmbeddingSwiftStandardLibraries(producer: CommandProducer) -> Bool { - return producer.isApplePlatform + public override var supportsEmbeddingSwiftStandardLibraries: Bool { + return true } public class func usesXCTRunner(_ scope: MacroEvaluationScope) -> Bool { @@ -649,7 +649,7 @@ public final class XCTestBundleProductTypeSpec : BundleProductTypeSpec, @uncheck var (tableOpt, warnings, errors) = super.overridingBuildSettings(scope, platform: platform) var table = tableOpt ?? MacroValueAssignmentTable(namespace: scope.namespace) - let isDeviceBuild = platform?.isDeploymentPlatform == true && platform?.name != scope.evaluate(BuiltinMacros.HOST_PLATFORM) + let isDeviceBuild = platform?.isDeploymentPlatform == true && platform?.identifier != "com.apple.platform.macosx" if isDeviceBuild { // For tests running on devices (not simulators) we always want to generate dSYMs so that symbolication can give file and line information about test failures. table.push(BuiltinMacros.DEBUG_INFORMATION_FORMAT, literal: "dwarf-with-dsym") diff --git a/Sources/SWBCore/SpecImplementations/Tools/SwiftCompiler.swift b/Sources/SWBCore/SpecImplementations/Tools/SwiftCompiler.swift index 687820ec..70e9ad3a 100644 --- a/Sources/SWBCore/SpecImplementations/Tools/SwiftCompiler.swift +++ b/Sources/SWBCore/SpecImplementations/Tools/SwiftCompiler.swift @@ -3763,9 +3763,6 @@ public extension BuildPhaseWithBuildFiles { /// - Returns: If the build phase contains any Swift source files that are not filtered out via the platform filter or excluded source file name patterns. func containsSwiftSources(_ referenceLookupContext: any ReferenceLookupContext, _ specLookupContext: any SpecLookupContext, _ scope: MacroEvaluationScope, _ filePathResolver: FilePathResolver) -> Bool { guard let swiftFileType = specLookupContext.lookupFileType(identifier: "sourcecode.swift") else { return false } - if scope.evaluate(BuiltinMacros.GENERATE_TEST_ENTRY_POINT) { - return true - } return containsFiles(ofType: swiftFileType, referenceLookupContext, specLookupContext, scope, filePathResolver) } } diff --git a/Sources/SWBGenericUnixPlatform/Specs/Unix.xcspec b/Sources/SWBGenericUnixPlatform/Specs/Unix.xcspec index 00bc75d5..eb72ba9c 100644 --- a/Sources/SWBGenericUnixPlatform/Specs/Unix.xcspec +++ b/Sources/SWBGenericUnixPlatform/Specs/Unix.xcspec @@ -24,18 +24,41 @@ SortNumber = 0; }, + // Test type bundle (bodged to be a tool) { Domain = generic-unix; Type = ProductType; Identifier = com.apple.product-type.bundle.unit-test; - BasedOn = com.apple.product-type.library.dynamic; + Class = PBXToolProductType; + Name = "Command-line Tool"; + Description = "Standalone command-line tool"; + DefaultTargetName = "Command-line Tool"; DefaultBuildProperties = { - // Index store data is required to discover XCTest tests - COMPILER_INDEX_STORE_ENABLE = YES; - SWIFT_INDEX_STORE_ENABLE = YES; - // Testability is needed to generate code to invoke discovered XCTest tests - SWIFT_ENABLE_TESTABILITY = YES; + FULL_PRODUCT_NAME = "$(EXECUTABLE_NAME)"; + EXECUTABLE_PREFIX = ""; + EXECUTABLE_SUFFIX = ".xctest"; + REZ_EXECUTABLE = YES; + INSTALL_PATH = "/usr/local/bin"; + FRAMEWORK_FLAG_PREFIX = "-framework"; + LIBRARY_FLAG_PREFIX = "-l"; + LIBRARY_FLAG_NOSPACE = YES; + GCC_DYNAMIC_NO_PIC = NO; + LD_NO_PIE = NO; + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_INLINES_ARE_PRIVATE_EXTERN = YES; + STRIP_STYLE = "all"; + CODE_SIGNING_ALLOWED = NO; + IsUnitTest = YES; + SWIFT_FORCE_DYNAMIC_LINK_STDLIB = YES; + SWIFT_FORCE_STATIC_LINK_STDLIB = NO; + // Avoid warning for executable types + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + GENERATE_TEST_ENTRY_POINT = YES; + GENERATED_TEST_ENTRY_POINT_PATH = "$(DERIVED_SOURCES_DIR)/test_entry_point.swift"; }; + PackageTypes = ( + com.apple.package-type.mach-o-executable // default + ); }, // Dynamic library (masquerading as a framework to placate Swift's project structure) diff --git a/Sources/SWBProjectModel/PIFGenerationModel.swift b/Sources/SWBProjectModel/PIFGenerationModel.swift index f3db2bce..698a7343 100644 --- a/Sources/SWBProjectModel/PIFGenerationModel.swift +++ b/Sources/SWBProjectModel/PIFGenerationModel.swift @@ -295,7 +295,6 @@ public enum PIF { case executable = "com.apple.product-type.tool" case hostBuildTool = "com.apple.product-type.tool.host-build" case unitTest = "com.apple.product-type.bundle.unit-test" - case swiftpmTestRunner = "com.apple.product-type.tool.swiftpm-test-runner" case bundle = "com.apple.product-type.bundle" case packageProduct = "packageProduct" public var asString: String { return rawValue } @@ -1023,7 +1022,6 @@ public enum PIF { public var SWIFT_ADD_TOOLCHAIN_SWIFTSYNTAX_SEARCH_PATHS: String? public var SWIFT_FORCE_STATIC_LINK_STDLIB: String? public var SWIFT_FORCE_DYNAMIC_LINK_STDLIB: String? - public var SWIFT_INDEX_STORE_ENABLE: String? public var SWIFT_INSTALL_OBJC_HEADER: String? public var SWIFT_LOAD_BINARY_MACROS: [String]? public var SWIFT_MODULE_ALIASES: [String]? diff --git a/Sources/SWBQNXPlatform/Specs/QNX.xcspec b/Sources/SWBQNXPlatform/Specs/QNX.xcspec index aea12e3b..3c72c620 100644 --- a/Sources/SWBQNXPlatform/Specs/QNX.xcspec +++ b/Sources/SWBQNXPlatform/Specs/QNX.xcspec @@ -24,18 +24,39 @@ SortNumber = 0; }, + // Test type bundle (bodged to be a tool) { Domain = qnx; Type = ProductType; Identifier = com.apple.product-type.bundle.unit-test; - BasedOn = com.apple.product-type.library.dynamic; + Class = PBXToolProductType; + Name = "Command-line Tool"; + Description = "Standalone command-line tool"; + DefaultTargetName = "Command-line Tool"; DefaultBuildProperties = { - // Index store data is required to discover XCTest tests - COMPILER_INDEX_STORE_ENABLE = YES; - SWIFT_INDEX_STORE_ENABLE = YES; - // Testability is needed to generate code to invoke discovered XCTest tests - SWIFT_ENABLE_TESTABILITY = YES; + FULL_PRODUCT_NAME = "$(EXECUTABLE_NAME)"; + EXECUTABLE_PREFIX = ""; + EXECUTABLE_SUFFIX = ".xctest"; + REZ_EXECUTABLE = YES; + INSTALL_PATH = "/usr/local/bin"; + FRAMEWORK_FLAG_PREFIX = "-framework"; + LIBRARY_FLAG_PREFIX = "-l"; + LIBRARY_FLAG_NOSPACE = YES; + GCC_DYNAMIC_NO_PIC = NO; + LD_NO_PIE = NO; + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_INLINES_ARE_PRIVATE_EXTERN = YES; + STRIP_STYLE = "all"; + CODE_SIGNING_ALLOWED = NO; + IsUnitTest = YES; + SWIFT_FORCE_DYNAMIC_LINK_STDLIB = YES; + SWIFT_FORCE_STATIC_LINK_STDLIB = NO; + // Avoid warning for executable types + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; }; + PackageTypes = ( + com.apple.package-type.mach-o-executable // default + ); }, // Dynamic library (masquerading as a framework to placate Swift's project structure) diff --git a/Sources/SWBTaskConstruction/ProductPlanning/ProductPlan.swift b/Sources/SWBTaskConstruction/ProductPlanning/ProductPlan.swift index 883073b0..88d2edfe 100644 --- a/Sources/SWBTaskConstruction/ProductPlanning/ProductPlan.swift +++ b/Sources/SWBTaskConstruction/ProductPlanning/ProductPlan.swift @@ -31,7 +31,7 @@ package protocol GlobalProductPlanDelegate: CoreClientTargetDiagnosticProducingD package final class GlobalProductPlan: GlobalTargetInfoProvider { /// The build plan request. - package let planRequest: BuildPlanRequest + let planRequest: BuildPlanRequest /// The target task info for each configured target. private(set) var targetTaskInfos: [ConfiguredTarget: TargetTaskInfo] diff --git a/Sources/SWBTaskConstruction/TaskProducers/OtherTaskProducers/InfoPlistTaskProducer.swift b/Sources/SWBTaskConstruction/TaskProducers/OtherTaskProducers/InfoPlistTaskProducer.swift index 820a55f5..1f740497 100644 --- a/Sources/SWBTaskConstruction/TaskProducers/OtherTaskProducers/InfoPlistTaskProducer.swift +++ b/Sources/SWBTaskConstruction/TaskProducers/OtherTaskProducers/InfoPlistTaskProducer.swift @@ -57,7 +57,7 @@ private extension ProductTypeSpec break } - fatalError("unknown product type \(type(of: self))") + fatalError("unknown product type") } } diff --git a/Sources/SWBTaskConstruction/TaskProducers/OtherTaskProducers/SwiftStandardLibrariesTaskProducer.swift b/Sources/SWBTaskConstruction/TaskProducers/OtherTaskProducers/SwiftStandardLibrariesTaskProducer.swift index c74e1843..bba8b051 100644 --- a/Sources/SWBTaskConstruction/TaskProducers/OtherTaskProducers/SwiftStandardLibrariesTaskProducer.swift +++ b/Sources/SWBTaskConstruction/TaskProducers/OtherTaskProducers/SwiftStandardLibrariesTaskProducer.swift @@ -41,7 +41,7 @@ final class SwiftStandardLibrariesTaskProducer: PhasedTaskProducer, TaskProducer let buildingAnySwiftSourceFiles = (context.configuredTarget?.target as? BuildPhaseTarget)?.sourcesBuildPhase?.containsSwiftSources(context.workspaceContext.workspace, context, scope, context.filePathResolver) ?? false // Determine whether we want to embed swift libraries. - var shouldEmbedSwiftLibraries = (buildingAnySwiftSourceFiles && productType.supportsEmbeddingSwiftStandardLibraries(producer: context)) + var shouldEmbedSwiftLibraries = (buildingAnySwiftSourceFiles && productType.supportsEmbeddingSwiftStandardLibraries) // If ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES then we will override our earlier reasoning if the product is a wrapper. if !shouldEmbedSwiftLibraries && scope.evaluate(BuiltinMacros.ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES) { diff --git a/Sources/SWBTestSupport/TestWorkspaces.swift b/Sources/SWBTestSupport/TestWorkspaces.swift index 6837bcf7..c225eb2c 100644 --- a/Sources/SWBTestSupport/TestWorkspaces.swift +++ b/Sources/SWBTestSupport/TestWorkspaces.swift @@ -924,7 +924,6 @@ package final class TestStandardTarget: TestInternalTarget, Sendable { case extensionKitExtension case xcodeExtension case unitTest - case swiftpmTestRunner case uiTest case multiDeviceUITest case systemExtension @@ -973,8 +972,6 @@ package final class TestStandardTarget: TestInternalTarget, Sendable { return "com.apple.product-type.xcode-extension" case .unitTest: return "com.apple.product-type.bundle.unit-test" - case .swiftpmTestRunner: - return "com.apple.product-type.tool.swiftpm-test-runner" case .uiTest: return "com.apple.product-type.bundle.ui-testing" case .multiDeviceUITest: @@ -1018,8 +1015,7 @@ package final class TestStandardTarget: TestInternalTarget, Sendable { .appClip: return "\(name).app" case .commandLineTool, - .hostBuildTool, - .swiftpmTestRunner: + .hostBuildTool: return "\(name)" case .framework, .staticFramework: diff --git a/Sources/SWBUniversalPlatform/Specs/ProductTypes.xcspec b/Sources/SWBUniversalPlatform/Specs/ProductTypes.xcspec index bd6cf9c8..0067050f 100644 --- a/Sources/SWBUniversalPlatform/Specs/ProductTypes.xcspec +++ b/Sources/SWBUniversalPlatform/Specs/ProductTypes.xcspec @@ -312,19 +312,4 @@ IsUnitTest = YES; WantsBundleIdentifierEditing = NO; }, - // SwiftPM test runner - { Type = ProductType; - Identifier = com.apple.product-type.tool.swiftpm-test-runner; - BasedOn = com.apple.product-type.tool; - Name = "SwiftPM Unit Test Runner"; - Description = "SwiftPM Unit Test Runner"; - DefaultBuildProperties = { - ENABLE_TESTING_SEARCH_PATHS = YES; - GENERATE_TEST_ENTRY_POINT = YES; - GENERATED_TEST_ENTRY_POINT_PATH = "$(DERIVED_SOURCES_DIR)/test_entry_point.swift"; - }; - PackageTypes = ( - com.apple.package-type.mach-o-executable - ); - }, ) diff --git a/Sources/SWBUniversalPlatform/TestEntryPointGenerationTaskAction.swift b/Sources/SWBUniversalPlatform/TestEntryPointGenerationTaskAction.swift index 9765719a..57dff473 100644 --- a/Sources/SWBUniversalPlatform/TestEntryPointGenerationTaskAction.swift +++ b/Sources/SWBUniversalPlatform/TestEntryPointGenerationTaskAction.swift @@ -23,37 +23,10 @@ class TestEntryPointGenerationTaskAction: TaskAction { override func performTaskAction(_ task: any ExecutableTask, dynamicExecutionDelegate: any DynamicTaskExecutionDelegate, executionDelegate: any TaskExecutionDelegate, clientDelegate: any TaskExecutionClientDelegate, outputDelegate: any TaskOutputDelegate) async -> CommandResult { do { let options = try Options.parse(Array(task.commandLineAsStrings.dropFirst())) - - var tests: [IndexStore.TestCaseClass] = [] - var objects: [Path] = [] - for linkerFilelist in options.linkerFilelist { - let filelistContents = String(String(decoding: try executionDelegate.fs.read(linkerFilelist), as: UTF8.self)) - let entries = filelistContents.split(separator: "\n", omittingEmptySubsequences: true).map { Path($0) }.map { - for indexUnitBasePath in options.indexUnitBasePath { - if let remappedPath = generateIndexOutputPath(from: $0, basePath: indexUnitBasePath) { - return remappedPath - } - } - return $0 - } - objects.append(contentsOf: entries) - } - let indexStoreAPI = try IndexStoreAPI(dylib: options.indexStoreLibraryPath) - for indexStore in options.indexStore { - let store = try IndexStore.open(store: indexStore, api: indexStoreAPI) - let testInfo = try store.listTests(in: objects) - tests.append(contentsOf: testInfo) - } - - try executionDelegate.fs.write(options.output, contents: ByteString(encodingAsUTF8: """ + try executionDelegate.fs.write(options.output, contents: #""" #if canImport(Testing) import Testing #endif - - \(testObservationFragment) - - import XCTest - \(discoveredTestsFragment(tests: tests)) @main @available(macOS 10.15, iOS 11, watchOS 4, tvOS 11, visionOS 1, *) @@ -71,16 +44,6 @@ class TestEntryPointGenerationTaskAction: TaskAction { return "xctest" } - private static func testOutputPath() -> String? { - var iterator = CommandLine.arguments.makeIterator() - while let argument = iterator.next() { - if argument == "--testing-output-path", let outputPath = iterator.next() { - return outputPath - } - } - return nil - } - #if os(Linux) @_silgen_name("$ss13_runAsyncMainyyyyYaKcF") private static func _runAsyncMain(_ asyncFun: @Sendable @escaping () async throws -> ()) @@ -94,16 +57,6 @@ class TestEntryPointGenerationTaskAction: TaskAction { } } #endif - if testingLibrary == "xctest" { - #if !os(Windows) && \(options.enableExperimentalTestOutput) - _ = Self.testOutputPath().map { SwiftPMXCTestObserver(testOutputPath: testOutputPath) } - #endif - #if os(WASI) - await XCTMain(__allDiscoveredTests()) as Never - #else - XCTMain(__allDiscoveredTests()) as Never - #endif - } } #else static func main() async { @@ -113,564 +66,18 @@ class TestEntryPointGenerationTaskAction: TaskAction { await Testing.__swiftPMEntryPoint() as Never } #endif - if testingLibrary == "xctest" { - #if !os(Windows) && \(options.enableExperimentalTestOutput) - _ = Self.testOutputPath().map { SwiftPMXCTestObserver(testOutputPath: testOutputPath) } - #endif - #if os(WASI) - await XCTMain(__allDiscoveredTests()) as Never - #else - XCTMain(__allDiscoveredTests()) as Never - #endif - } } #endif } - """)) - + """#) return .succeeded } catch { outputDelegate.emitError("\(error)") return .failed } } +} - private struct Options: ParsableArguments { - @Option var output: Path - @Option var indexStoreLibraryPath: Path - @Option var linkerFilelist: [Path] - @Option var indexStore: [Path] - @Option var indexUnitBasePath: [Path] - @Flag var enableExperimentalTestOutput: Bool = false - } - - private func discoveredTestsFragment(tests: [IndexStore.TestCaseClass]) -> String { - var fragment = "" - for moduleName in Set(tests.map { $0.module }).sorted() { - fragment += "@testable import \(moduleName)\n" - } - fragment += """ - @available(*, deprecated, message: "Not actually deprecated. Marked as deprecated to allow inclusion of deprecated tests (which test deprecated functionality) without warnings") - public func __allDiscoveredTests() -> [XCTestCaseEntry] { - return [ - - """ - for testClass in tests { - - let testTuples = testClass.testMethods.map { method in - let basename = method.name.hasSuffix("()") ? String(method.name.dropLast(2)) : method.name - if method.isAsync { - return " (\"\(basename)\", asyncTest(\(testClass.name).\(basename)))" - } else { - return " (\"\(basename)\", \(testClass.name).\(basename))" - } - } - fragment += " testCase([\(testTuples.joined(separator: ",\n"))]),\n" - } - fragment += """ - ] - } - """ - return fragment - } - - private var testObservationFragment: String = - """ - #if !os(Windows) // Test observation is not supported on Windows - import Foundation - import XCTest - - public final class SwiftPMXCTestObserver: NSObject { - let testOutputPath: String - - public init(testOutputPath: String) { - self.testOutputPath = testOutputPath - super.init() - XCTestObservationCenter.shared.addTestObserver(self) - } - } - - extension SwiftPMXCTestObserver: XCTestObservation { - private func write(record: any Encodable) { - let lock = FileLock(at: URL(fileURLWithPath: self.testOutputPath + ".lock")) - _ = try? lock.withLock { - self._write(record: record) - } - } - - private func _write(record: any Encodable) { - if let data = try? JSONEncoder().encode(record) { - if let fileHandle = FileHandle(forWritingAtPath: self.testOutputPath) { - defer { fileHandle.closeFile() } - fileHandle.seekToEndOfFile() - fileHandle.write("\\n".data(using: .utf8)!) - fileHandle.write(data) - } else { - _ = try? data.write(to: URL(fileURLWithPath: self.testOutputPath)) - } - } - } - - public func testBundleWillStart(_ testBundle: Bundle) { - let record = TestBundleEventRecord(bundle: .init(testBundle), event: .start) - write(record: TestEventRecord(bundleEvent: record)) - } - - public func testSuiteWillStart(_ testSuite: XCTestSuite) { - let record = TestSuiteEventRecord(suite: .init(testSuite), event: .start) - write(record: TestEventRecord(suiteEvent: record)) - } - - public func testCaseWillStart(_ testCase: XCTestCase) { - let record = TestCaseEventRecord(testCase: .init(testCase), event: .start) - write(record: TestEventRecord(caseEvent: record)) - } - - #if canImport(Darwin) - public func testCase(_ testCase: XCTestCase, didRecord issue: XCTIssue) { - let record = TestCaseFailureRecord(testCase: .init(testCase), issue: .init(issue), failureKind: .unexpected) - write(record: TestEventRecord(caseFailure: record)) - } - - public func testCase(_ testCase: XCTestCase, didRecord expectedFailure: XCTExpectedFailure) { - let record = TestCaseFailureRecord(testCase: .init(testCase), issue: .init(expectedFailure.issue), failureKind: .expected(failureReason: expectedFailure.failureReason)) - write(record: TestEventRecord(caseFailure: record)) - } - #else - public func testCase(_ testCase: XCTestCase, didFailWithDescription description: String, inFile filePath: String?, atLine lineNumber: Int) { - let issue = TestIssue(description: description, inFile: filePath, atLine: lineNumber) - let record = TestCaseFailureRecord(testCase: .init(testCase), issue: issue, failureKind: .unexpected) - write(record: TestEventRecord(caseFailure: record)) - } - #endif - - public func testCaseDidFinish(_ testCase: XCTestCase) { - let record = TestCaseEventRecord(testCase: .init(testCase), event: .finish) - write(record: TestEventRecord(caseEvent: record)) - } - - #if canImport(Darwin) - public func testSuite(_ testSuite: XCTestSuite, didRecord issue: XCTIssue) { - let record = TestSuiteFailureRecord(suite: .init(testSuite), issue: .init(issue), failureKind: .unexpected) - write(record: TestEventRecord(suiteFailure: record)) - } - - public func testSuite(_ testSuite: XCTestSuite, didRecord expectedFailure: XCTExpectedFailure) { - let record = TestSuiteFailureRecord(suite: .init(testSuite), issue: .init(expectedFailure.issue), failureKind: .expected(failureReason: expectedFailure.failureReason)) - write(record: TestEventRecord(suiteFailure: record)) - } - #else - public func testSuite(_ testSuite: XCTestSuite, didFailWithDescription description: String, inFile filePath: String?, atLine lineNumber: Int) { - let issue = TestIssue(description: description, inFile: filePath, atLine: lineNumber) - let record = TestSuiteFailureRecord(suite: .init(testSuite), issue: issue, failureKind: .unexpected) - write(record: TestEventRecord(suiteFailure: record)) - } - #endif - - public func testSuiteDidFinish(_ testSuite: XCTestSuite) { - let record = TestSuiteEventRecord(suite: .init(testSuite), event: .finish) - write(record: TestEventRecord(suiteEvent: record)) - } - - public func testBundleDidFinish(_ testBundle: Bundle) { - let record = TestBundleEventRecord(bundle: .init(testBundle), event: .finish) - write(record: TestEventRecord(bundleEvent: record)) - } - } - - // FIXME: Copied from `Lock.swift` in TSCBasic, would be nice if we had a better way - - #if canImport(Glibc) - @_exported import Glibc - #elseif canImport(Musl) - @_exported import Musl - #elseif os(Windows) - @_exported import CRT - @_exported import WinSDK - #elseif os(WASI) - @_exported import WASILibc - #elseif canImport(Android) - @_exported import Android - #else - @_exported import Darwin.C - #endif - - import Foundation - - public final class FileLock { - #if os(Windows) - private var handle: HANDLE? - #else - private var fileDescriptor: CInt? - #endif - - private let lockFile: URL - - public init(at lockFile: URL) { - self.lockFile = lockFile - } - - public func lock() throws { - #if os(Windows) - if handle == nil { - let h: HANDLE = lockFile.path.withCString(encodedAs: UTF16.self, { - CreateFileW( - $0, - UInt32(GENERIC_READ) | UInt32(GENERIC_WRITE), - UInt32(FILE_SHARE_READ) | UInt32(FILE_SHARE_WRITE), - nil, - DWORD(OPEN_ALWAYS), - DWORD(FILE_ATTRIBUTE_NORMAL), - nil - ) - }) - if h == INVALID_HANDLE_VALUE { - throw FileSystemError(errno: Int32(GetLastError()), lockFile) - } - self.handle = h - } - var overlapped = OVERLAPPED() - overlapped.Offset = 0 - overlapped.OffsetHigh = 0 - overlapped.hEvent = nil - if !LockFileEx(handle, DWORD(LOCKFILE_EXCLUSIVE_LOCK), 0, - UInt32.max, UInt32.max, &overlapped) { - throw ProcessLockError.unableToAquireLock(errno: Int32(GetLastError())) - } - #elseif os(WASI) - // WASI doesn't support flock - #else - if fileDescriptor == nil { - let fd = open(lockFile.path, O_WRONLY | O_CREAT | O_CLOEXEC, 0o666) - if fd == -1 { - fatalError("errno: \\(errno), lockFile: \\(lockFile)") - } - self.fileDescriptor = fd - } - while true { - if flock(fileDescriptor!, LOCK_EX) == 0 { - break - } - if errno == EINTR { continue } - fatalError("unable to acquire lock, errno: \\(errno)") - } - #endif - } - - public func unlock() { - #if os(Windows) - var overlapped = OVERLAPPED() - overlapped.Offset = 0 - overlapped.OffsetHigh = 0 - overlapped.hEvent = nil - UnlockFileEx(handle, 0, UInt32.max, UInt32.max, &overlapped) - #elseif os(WASI) - // WASI doesn't support flock - #else - guard let fd = fileDescriptor else { return } - flock(fd, LOCK_UN) - #endif - } - - deinit { - #if os(Windows) - guard let handle = handle else { return } - CloseHandle(handle) - #elseif os(WASI) - // WASI doesn't support flock - #else - guard let fd = fileDescriptor else { return } - close(fd) - #endif - } - - public func withLock(_ body: () throws -> T) throws -> T { - try lock() - defer { unlock() } - return try body() - } - - public func withLock(_ body: () async throws -> T) async throws -> T { - try lock() - defer { unlock() } - return try await body() - } - } - - // FIXME: Copied from `XCTEvents.swift`, would be nice if we had a better way - - struct TestEventRecord: Codable { - let caseFailure: TestCaseFailureRecord? - let suiteFailure: TestSuiteFailureRecord? - - let bundleEvent: TestBundleEventRecord? - let suiteEvent: TestSuiteEventRecord? - let caseEvent: TestCaseEventRecord? - - init( - caseFailure: TestCaseFailureRecord? = nil, - suiteFailure: TestSuiteFailureRecord? = nil, - bundleEvent: TestBundleEventRecord? = nil, - suiteEvent: TestSuiteEventRecord? = nil, - caseEvent: TestCaseEventRecord? = nil - ) { - self.caseFailure = caseFailure - self.suiteFailure = suiteFailure - self.bundleEvent = bundleEvent - self.suiteEvent = suiteEvent - self.caseEvent = caseEvent - } - } - - // MARK: - Records - - struct TestAttachment: Codable { - let name: String? - // TODO: Handle `userInfo: [AnyHashable : Any]?` - let uniformTypeIdentifier: String - let payload: Data? - } - - struct TestBundleEventRecord: Codable { - let bundle: TestBundle - let event: TestEvent - } - - struct TestCaseEventRecord: Codable { - let testCase: TestCase - let event: TestEvent - } - - struct TestCaseFailureRecord: Codable, CustomStringConvertible { - let testCase: TestCase - let issue: TestIssue - let failureKind: TestFailureKind - - var description: String { - return "\\(issue.sourceCodeContext.description)\\(testCase) \\(issue.compactDescription)" - } - } - - struct TestSuiteEventRecord: Codable { - let suite: TestSuiteRecord - let event: TestEvent - } - - struct TestSuiteFailureRecord: Codable { - let suite: TestSuiteRecord - let issue: TestIssue - let failureKind: TestFailureKind - } - - // MARK: Primitives - - struct TestBundle: Codable { - let bundleIdentifier: String? - let bundlePath: String - } - - struct TestCase: Codable { - let name: String - } - - struct TestErrorInfo: Codable { - let description: String - let type: String - } - - enum TestEvent: Codable { - case start - case finish - } - - enum TestFailureKind: Codable, Equatable { - case unexpected - case expected(failureReason: String?) - - var isExpected: Bool { - switch self { - case .expected: return true - case .unexpected: return false - } - } - } - - struct TestIssue: Codable { - let type: TestIssueType - let compactDescription: String - let detailedDescription: String? - let associatedError: TestErrorInfo? - let sourceCodeContext: TestSourceCodeContext - let attachments: [TestAttachment] - } - - enum TestIssueType: Codable { - case assertionFailure - case performanceRegression - case system - case thrownError - case uncaughtException - case unmatchedExpectedFailure - case unknown - } - - struct TestLocation: Codable, CustomStringConvertible { - let file: String - let line: Int - - var description: String { - return "\\(file):\\(line) " - } - } - - struct TestSourceCodeContext: Codable, CustomStringConvertible { - let callStack: [TestSourceCodeFrame] - let location: TestLocation? - - var description: String { - return location?.description ?? "" - } - } - - struct TestSourceCodeFrame: Codable { - let address: UInt64 - let symbolInfo: TestSourceCodeSymbolInfo? - let symbolicationError: TestErrorInfo? - } - - struct TestSourceCodeSymbolInfo: Codable { - let imageName: String - let symbolName: String - let location: TestLocation? - } - - struct TestSuiteRecord: Codable { - let name: String - } - - // MARK: XCTest compatibility - - extension TestIssue { - init(description: String, inFile filePath: String?, atLine lineNumber: Int) { - let location: TestLocation? - if let filePath = filePath { - location = .init(file: filePath, line: lineNumber) - } else { - location = nil - } - self.init(type: .assertionFailure, compactDescription: description, detailedDescription: description, associatedError: nil, sourceCodeContext: .init(callStack: [], location: location), attachments: []) - } - } - - import XCTest - - #if canImport(Darwin) // XCTAttachment is unavailable in swift-corelibs-xctest. - extension TestAttachment { - init(_ attachment: XCTAttachment) { - self.init( - name: attachment.name, - uniformTypeIdentifier: attachment.uniformTypeIdentifier, - payload: attachment.value(forKey: "payload") as? Data - ) - } - } - #endif - - extension TestBundle { - init(_ testBundle: Bundle) { - self.init( - bundleIdentifier: testBundle.bundleIdentifier, - bundlePath: testBundle.bundlePath - ) - } - } - - extension TestCase { - init(_ testCase: XCTestCase) { - self.init(name: testCase.name) - } - } - - extension TestErrorInfo { - init(_ error: any Swift.Error) { - self.init(description: "\\(error)", type: "\\(Swift.type(of: error))") - } - } - - #if canImport(Darwin) // XCTIssue is unavailable in swift-corelibs-xctest. - extension TestIssue { - init(_ issue: XCTIssue) { - self.init( - type: .init(issue.type), - compactDescription: issue.compactDescription, - detailedDescription: issue.detailedDescription, - associatedError: issue.associatedError.map { .init($0) }, - sourceCodeContext: .init(issue.sourceCodeContext), - attachments: issue.attachments.map { .init($0) } - ) - } - } - - extension TestIssueType { - init(_ type: XCTIssue.IssueType) { - switch type { - case .assertionFailure: self = .assertionFailure - case .thrownError: self = .thrownError - case .uncaughtException: self = .uncaughtException - case .performanceRegression: self = .performanceRegression - case .system: self = .system - case .unmatchedExpectedFailure: self = .unmatchedExpectedFailure - @unknown default: self = .unknown - } - } - } - #endif - - #if canImport(Darwin) // XCTSourceCodeLocation/XCTSourceCodeContext/XCTSourceCodeFrame/XCTSourceCodeSymbolInfo is unavailable in swift-corelibs-xctest. - extension TestLocation { - init(_ location: XCTSourceCodeLocation) { - self.init( - file: location.fileURL.absoluteString, - line: location.lineNumber - ) - } - } - - extension TestSourceCodeContext { - init(_ context: XCTSourceCodeContext) { - self.init( - callStack: context.callStack.map { .init($0) }, - location: context.location.map { .init($0) } - ) - } - } - - extension TestSourceCodeFrame { - init(_ frame: XCTSourceCodeFrame) { - self.init( - address: frame.address, - symbolInfo: (try? frame.symbolInfo()).map { .init($0) }, - symbolicationError: frame.symbolicationError.map { .init($0) } - ) - } - } - - extension TestSourceCodeSymbolInfo { - init(_ symbolInfo: XCTSourceCodeSymbolInfo) { - self.init( - imageName: symbolInfo.imageName, - symbolName: symbolInfo.symbolName, - location: symbolInfo.location.map { .init($0) } - ) - } - } - #endif - - extension TestSuiteRecord { - init(_ testSuite: XCTestSuite) { - self.init(name: testSuite.name) - } - } - #endif - """ +private struct Options: ParsableArguments { + @Option var output: Path } diff --git a/Sources/SWBUniversalPlatform/TestEntryPointGenerationTool.swift b/Sources/SWBUniversalPlatform/TestEntryPointGenerationTool.swift index 5ee78857..007611ad 100644 --- a/Sources/SWBUniversalPlatform/TestEntryPointGenerationTool.swift +++ b/Sources/SWBUniversalPlatform/TestEntryPointGenerationTool.swift @@ -17,59 +17,7 @@ import SWBCore final class TestEntryPointGenerationToolSpec: GenericCommandLineToolSpec, SpecIdentifierType, @unchecked Sendable { static let identifier = "org.swift.test-entry-point-generator" - override func commandLineFromTemplate(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate, optionContext: (any DiscoveredCommandLineToolSpecInfo)?, specialArgs: [String] = [], lookup: ((MacroDeclaration) -> MacroExpression?)? = nil) -> [CommandLineArgument] { - var args = super.commandLineFromTemplate(cbc, delegate, optionContext: optionContext, specialArgs: specialArgs, lookup: lookup) - for (toolchainPath, toolchainLibrarySearchPath) in cbc.producer.toolchains.map({ ($0.path, $0.librarySearchPaths) }) { - if let path = toolchainLibrarySearchPath.findLibrary(operatingSystem: cbc.producer.hostOperatingSystem, basename: "IndexStore") { - args.append(contentsOf: ["--index-store-library-path", .path(path)]) - } - for input in cbc.inputs { - if input.fileType.conformsTo(identifier: "text") { - args.append(contentsOf: ["--linker-filelist", .path(input.absolutePath)]) - } else if input.fileType.conformsTo(identifier: "compiled.mach-o") { - // Do nothing - } else { - delegate.error("Unexpected input of type '\(input.fileType)' to test entry point generation") - } - } - } - return args - } - override func createTaskAction(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate) -> (any PlannedTaskAction)? { TestEntryPointGenerationTaskAction() } - - public func constructTasks(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate, indexStorePaths: [Path], indexUnitBasePaths: [Path]) async { - var commandLine = commandLineFromTemplate(cbc, delegate, optionContext: nil) - - for indexStorePath in indexStorePaths { - commandLine.append(contentsOf: ["--index-store", .path(indexStorePath)]) - } - - for basePath in indexUnitBasePaths { - commandLine.append(contentsOf: ["--index-unit-base-path", .path(basePath)]) - } - - delegate.createTask( - type: self, - dependencyData: nil, - payload: nil, - ruleInfo: defaultRuleInfo(cbc, delegate), - additionalSignatureData: "", - commandLine: commandLine, - additionalOutput: [], - environment: environmentFromSpec(cbc, delegate), - workingDirectory: cbc.producer.defaultWorkingDirectory, - inputs: cbc.inputs.map { delegate.createNode($0.absolutePath) }, - outputs: cbc.outputs.map { delegate.createNode($0) }, - mustPrecede: [], - action: createTaskAction(cbc, delegate), - execDescription: resolveExecutionDescription(cbc, delegate), - preparesForIndexing: true, - enableSandboxing: enableSandboxing, - llbuildControlDisabled: true, - additionalTaskOrderingOptions: [] - ) - } } diff --git a/Sources/SWBUniversalPlatform/TestEntryPointTaskProducer.swift b/Sources/SWBUniversalPlatform/TestEntryPointTaskProducer.swift index 23ec56f0..fe4b56ef 100644 --- a/Sources/SWBUniversalPlatform/TestEntryPointTaskProducer.swift +++ b/Sources/SWBUniversalPlatform/TestEntryPointTaskProducer.swift @@ -13,7 +13,6 @@ import SWBCore import SWBTaskConstruction import SWBMacro -import SWBUtil class TestEntryPointTaskProducer: PhasedTaskProducer, TaskProducer { func generateTasks() async -> [any PlannedTask] { @@ -22,54 +21,8 @@ class TestEntryPointTaskProducer: PhasedTaskProducer, TaskProducer { await self.appendGeneratedTasks(&tasks) { delegate in let scope = context.settings.globalScope let outputPath = scope.evaluate(BuiltinMacros.GENERATED_TEST_ENTRY_POINT_PATH) - - guard let configuredTarget = context.configuredTarget else { - context.error("Cannot generate a test entry point without a target") - return - } - var indexStoreDirectories: OrderedSet = [] - var linkerFileLists: OrderedSet = [] - var indexUnitBasePaths: OrderedSet = [] - var binaryPaths: OrderedSet = [] - for directDependency in context.globalProductPlan.dependencies(of: configuredTarget) { - let settings = context.globalProductPlan.planRequest.buildRequestContext.getCachedSettings(directDependency.parameters, target: directDependency.target) - guard settings.productType?.conformsTo(identifier: "com.apple.product-type.bundle.unit-test") == true else { - continue - } - guard settings.globalScope.evaluate(BuiltinMacros.SWIFT_INDEX_STORE_ENABLE) else { - context.error("Cannot perform test discovery for '\(directDependency.target.name)' because index while building is disabled") - continue - } - let path = settings.globalScope.evaluate(BuiltinMacros.SWIFT_INDEX_STORE_PATH) - guard !path.isEmpty else { - continue - } - indexStoreDirectories.append(path) - - for arch in settings.globalScope.evaluate(BuiltinMacros.ARCHS) { - for variant in settings.globalScope.evaluate(BuiltinMacros.BUILD_VARIANTS) { - let innerScope = settings.globalScope - .subscope(binding: BuiltinMacros.archCondition, to: arch) - .subscope(binding: BuiltinMacros.variantCondition, to: variant) - let linkerFileListPath = innerScope.evaluate(BuiltinMacros.__INPUT_FILE_LIST_PATH__) - if !linkerFileListPath.isEmpty { - linkerFileLists.append(linkerFileListPath) - } - let objroot = innerScope.evaluate(BuiltinMacros.OBJROOT) - if !objroot.isEmpty { - indexUnitBasePaths.append(objroot) - } - - let binaryPath = innerScope.evaluate(BuiltinMacros.TARGET_BUILD_DIR).join(innerScope.evaluate(BuiltinMacros.EXECUTABLE_PATH)).normalize() - binaryPaths.append(binaryPath) - } - } - } - - let inputs: [FileToBuild] = linkerFileLists.map { FileToBuild(absolutePath: $0, fileType: self.context.workspaceContext.core.specRegistry.getSpec("text") as! FileTypeSpec) } + binaryPaths.map { FileToBuild(absolutePath: $0, fileType: self.context.workspaceContext.core.specRegistry.getSpec("compiled.mach-o") as! FileTypeSpec) } - - let cbc = CommandBuildContext(producer: context, scope: scope, inputs: inputs, outputs: [outputPath]) - await context.testEntryPointGenerationToolSpec.constructTasks(cbc, delegate, indexStorePaths: indexStoreDirectories.elements, indexUnitBasePaths: indexUnitBasePaths.elements) + let cbc = CommandBuildContext(producer: context, scope: scope, inputs: [], outputs: [outputPath]) + await context.testEntryPointGenerationToolSpec.constructTasks(cbc, delegate) } } return tasks diff --git a/Sources/SWBUtil/CMakeLists.txt b/Sources/SWBUtil/CMakeLists.txt index 9d2d611d..91348fd9 100644 --- a/Sources/SWBUtil/CMakeLists.txt +++ b/Sources/SWBUtil/CMakeLists.txt @@ -46,7 +46,6 @@ add_library(SWBUtil HashContext.swift Headermap.swift HeavyCache.swift - IndexStore.swift Int.swift InterningArena.swift IO.swift diff --git a/Sources/SWBUtil/IndexStore.swift b/Sources/SWBUtil/IndexStore.swift deleted file mode 100644 index 46cbd8bc..00000000 --- a/Sources/SWBUtil/IndexStore.swift +++ /dev/null @@ -1,389 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 SWBCSupport -import Foundation - -public final class IndexStore { - - public struct TestCaseClass { - public struct TestMethod: Hashable, Comparable { - public let name: String - public let isAsync: Bool - - public static func < (lhs: IndexStore.TestCaseClass.TestMethod, rhs: IndexStore.TestCaseClass.TestMethod) -> Bool { - return (lhs.name, (lhs.isAsync ? 1 : 0)) < (rhs.name, (rhs.isAsync ? 1 : 0)) - } - } - - public var name: String - public var module: String - public var testMethods: [TestMethod] - @available(*, deprecated, message: "use testMethods instead") public var methods: [String] - } - - fileprivate var impl: IndexStoreImpl { _impl as! IndexStoreImpl } - private let _impl: Any - - fileprivate init(_ impl: IndexStoreImpl) { - self._impl = impl - } - - static public func open(store path: Path, api: IndexStoreAPI) throws -> IndexStore { - let impl = try IndexStoreImpl.open(store: path, api: api.impl) - return IndexStore(impl) - } - - public func listTests(in objectFiles: [Path]) throws -> [TestCaseClass] { - return try impl.listTests(in: objectFiles) - } - - @available(*, deprecated, message: "use listTests(in:) instead") - public func listTests(inObjectFile object: Path) throws -> [TestCaseClass] { - return try impl.listTests(inObjectFile: object) - } -} - -public final class IndexStoreAPI { - fileprivate var impl: IndexStoreAPIImpl { - _impl as! IndexStoreAPIImpl - } - private let _impl: Any - - public init(dylib path: Path) throws { - self._impl = try IndexStoreAPIImpl(dylib: path) - } -} - -private final class IndexStoreImpl { - typealias TestCaseClass = IndexStore.TestCaseClass - - let api: IndexStoreAPIImpl - - let store: indexstore_t - - private init(store: indexstore_t, api: IndexStoreAPIImpl) { - self.store = store - self.api = api - } - - static public func open(store path: Path, api: IndexStoreAPIImpl) throws -> IndexStoreImpl { - if let store = try api.call({ api.fn.store_create(path.str, &$0) }) { - return IndexStoreImpl(store: store, api: api) - } - throw StubError.error("Unable to open store at \(path.str)") - } - - public func listTests(in objectFiles: [Path]) throws -> [TestCaseClass] { - var inheritance = [String: [String: String]]() - var testMethods = [String: [String: [(name: String, async: Bool)]]]() - - for objectFile in objectFiles { - // Get the records of this object file. - guard let unitReader = try? self.api.call ({ self.api.fn.unit_reader_create(store, unitName(object: objectFile), &$0) }) else { - continue - } - let records = try getRecords(unitReader: unitReader) - let moduleName = self.api.fn.unit_reader_get_module_name(unitReader).str - for record in records { - // get tests info - let testsInfo = try self.getTestsInfo(record: record) - // merge results across module - for (className, parentClassName) in testsInfo.inheritance { - inheritance[moduleName, default: [:]][className] = parentClassName - } - for (className, classTestMethods) in testsInfo.testMethods { - testMethods[moduleName, default: [:]][className, default: []].append(contentsOf: classTestMethods) - } - } - } - - // merge across inheritance in module boundries - func flatten(moduleName: String, className: String) -> [String: (name: String, async: Bool)] { - var allMethods = [String: (name: String, async: Bool)]() - - if let parentClassName = inheritance[moduleName]?[className] { - let parentMethods = flatten(moduleName: moduleName, className: parentClassName) - allMethods.merge(parentMethods, uniquingKeysWith: { (lhs, _) in lhs }) - } - - for method in testMethods[moduleName]?[className] ?? [] { - allMethods[method.name] = (name: method.name, async: method.async) - } - - return allMethods - } - - var testCaseClasses = [TestCaseClass]() - for (moduleName, classMethods) in testMethods { - for className in classMethods.keys { - let methods = flatten(moduleName: moduleName, className: className) - .map { (name, info) in TestCaseClass.TestMethod(name: name, isAsync: info.async) } - .sorted() - testCaseClasses.append(TestCaseClass(name: className, module: moduleName, testMethods: methods, methods: methods.map(\.name))) - } - } - - return testCaseClasses - } - - - @available(*, deprecated, message: "use listTests(in:) instead") - public func listTests(inObjectFile object: Path) throws -> [TestCaseClass] { - // Get the records of this object file. - let unitReader = try api.call{ self.api.fn.unit_reader_create(store, unitName(object: object), &$0) } - let records = try getRecords(unitReader: unitReader) - - // Get the test classes. - var inheritance = [String: String]() - var testMethods = [String: [(name: String, async: Bool)]]() - - for record in records { - let testsInfo = try self.getTestsInfo(record: record) - inheritance.merge(testsInfo.inheritance, uniquingKeysWith: { (lhs, _) in lhs }) - testMethods.merge(testsInfo.testMethods, uniquingKeysWith: { (lhs, _) in lhs }) - } - - func flatten(className: String) -> [(method: String, async: Bool)] { - var results = [(String, Bool)]() - if let parentClassName = inheritance[className] { - let parentMethods = flatten(className: parentClassName) - results.append(contentsOf: parentMethods) - } - if let methods = testMethods[className] { - results.append(contentsOf: methods) - } - return results - } - - let moduleName = self.api.fn.unit_reader_get_module_name(unitReader).str - - var testCaseClasses = [TestCaseClass]() - for className in testMethods.keys { - let methods = flatten(className: className) - .map { TestCaseClass.TestMethod(name: $0.method, isAsync: $0.async) } - .sorted() - testCaseClasses.append(TestCaseClass(name: className, module: moduleName, testMethods: methods, methods: methods.map(\.name))) - } - - return testCaseClasses - } - - private func getTestsInfo(record: String) throws -> (inheritance: [String: String], testMethods: [String: [(name: String, async: Bool)]] ) { - let recordReader = try api.call{ self.api.fn.record_reader_create(store, record, &$0) } - - // scan for inheritance - - let inheritanceStoreRef = StoreRef([String: String](), api: self.api) - let inheritancePointer = unsafeBitCast(Unmanaged.passUnretained(inheritanceStoreRef), to: UnsafeMutableRawPointer.self) - - _ = self.api.fn.record_reader_occurrences_apply_f(recordReader, inheritancePointer) { inheritancePointer , occ -> Bool in - let inheritanceStoreRef = Unmanaged>.fromOpaque(inheritancePointer!).takeUnretainedValue() - let fn = inheritanceStoreRef.api.fn - - // Get the symbol. - let sym = fn.occurrence_get_symbol(occ) - let symbolProperties = fn.symbol_get_properties(sym) - // We only care about symbols that are marked unit tests and are instance methods. - if symbolProperties & UInt64(INDEXSTORE_SYMBOL_PROPERTY_UNITTEST.rawValue) == 0 { - return true - } - if fn.symbol_get_kind(sym) != INDEXSTORE_SYMBOL_KIND_CLASS{ - return true - } - - let parentClassName = fn.symbol_get_name(sym).str - - let childClassNameStoreRef = StoreRef("", api: inheritanceStoreRef.api) - let childClassNamePointer = unsafeBitCast(Unmanaged.passUnretained(childClassNameStoreRef), to: UnsafeMutableRawPointer.self) - _ = fn.occurrence_relations_apply_f(occ!, childClassNamePointer) { childClassNamePointer, relation in - guard let relation = relation else { return true } - let childClassNameStoreRef = Unmanaged>.fromOpaque(childClassNamePointer!).takeUnretainedValue() - let fn = childClassNameStoreRef.api.fn - - // Look for the base class. - if fn.symbol_relation_get_roles(relation) != UInt64(INDEXSTORE_SYMBOL_ROLE_REL_BASEOF.rawValue) { - return true - } - - let childClassNameSym = fn.symbol_relation_get_symbol(relation) - childClassNameStoreRef.instance = fn.symbol_get_name(childClassNameSym).str - return true - } - - if !childClassNameStoreRef.instance.isEmpty { - inheritanceStoreRef.instance[childClassNameStoreRef.instance] = parentClassName - } - - return true - } - - // scan for methods - - let testMethodsStoreRef = StoreRef([String: [(name: String, async: Bool)]](), api: api) - let testMethodsPointer = unsafeBitCast(Unmanaged.passUnretained(testMethodsStoreRef), to: UnsafeMutableRawPointer.self) - - _ = self.api.fn.record_reader_occurrences_apply_f(recordReader, testMethodsPointer) { testMethodsPointer , occ -> Bool in - let testMethodsStoreRef = Unmanaged>.fromOpaque(testMethodsPointer!).takeUnretainedValue() - let fn = testMethodsStoreRef.api.fn - - // Get the symbol. - let sym = fn.occurrence_get_symbol(occ) - let symbolProperties = fn.symbol_get_properties(sym) - // We only care about symbols that are marked unit tests and are instance methods. - if symbolProperties & UInt64(INDEXSTORE_SYMBOL_PROPERTY_UNITTEST.rawValue) == 0 { - return true - } - if fn.symbol_get_kind(sym) != INDEXSTORE_SYMBOL_KIND_INSTANCEMETHOD { - return true - } - - let classNameStoreRef = StoreRef("", api: testMethodsStoreRef.api) - let classNamePointer = unsafeBitCast(Unmanaged.passUnretained(classNameStoreRef), to: UnsafeMutableRawPointer.self) - - _ = fn.occurrence_relations_apply_f(occ!, classNamePointer) { classNamePointer, relation in - guard let relation = relation else { return true } - let classNameStoreRef = Unmanaged>.fromOpaque(classNamePointer!).takeUnretainedValue() - let fn = classNameStoreRef.api.fn - - // Look for the class. - if fn.symbol_relation_get_roles(relation) != UInt64(INDEXSTORE_SYMBOL_ROLE_REL_CHILDOF.rawValue) { - return true - } - - let classNameSym = fn.symbol_relation_get_symbol(relation) - classNameStoreRef.instance = fn.symbol_get_name(classNameSym).str - return true - } - - if !classNameStoreRef.instance.isEmpty { - let methodName = fn.symbol_get_name(sym).str - let isAsync = symbolProperties & UInt64(INDEXSTORE_SYMBOL_PROPERTY_SWIFT_ASYNC.rawValue) != 0 - testMethodsStoreRef.instance[classNameStoreRef.instance, default: []].append((name: methodName, async: isAsync)) - } - - return true - } - - return ( - inheritance: inheritanceStoreRef.instance, - testMethods: testMethodsStoreRef.instance - ) - - } - - private func getRecords(unitReader: indexstore_unit_reader_t?) throws -> [String] { - let builder = StoreRef([String](), api: api) - - let ctx = unsafeBitCast(Unmanaged.passUnretained(builder), to: UnsafeMutableRawPointer.self) - _ = self.api.fn.unit_reader_dependencies_apply_f(unitReader, ctx) { ctx , unit -> Bool in - let store = Unmanaged>.fromOpaque(ctx!).takeUnretainedValue() - let fn = store.api.fn - if fn.unit_dependency_get_kind(unit) == INDEXSTORE_UNIT_DEPENDENCY_RECORD { - store.instance.append(fn.unit_dependency_get_name(unit).str) - } - return true - } - - return builder.instance - } - - private func unitName(object: Path) -> String { - let initialSize = 64 - var buf = UnsafeMutablePointer.allocate(capacity: initialSize) - let len = self.api.fn.store_get_unit_name_from_output_path(store, object.str, buf, initialSize) - - if len + 1 > initialSize { - buf.deallocate() - buf = UnsafeMutablePointer.allocate(capacity: len + 1) - _ = self.api.fn.store_get_unit_name_from_output_path(store, object.str, buf, len + 1) - } - - defer { - buf.deallocate() - } - - return String(cString: buf) - } -} - -private class StoreRef { - let api: IndexStoreAPIImpl - var instance: T - init(_ instance: T, api: IndexStoreAPIImpl) { - self.instance = instance - self.api = api - } -} - -private final class IndexStoreAPIImpl { - - /// The path of the index store dylib. - private let path: Path - - /// Handle of the dynamic library. - private let dylib: LibraryHandle - - /// The index store API functions. - fileprivate let fn: indexstore_functions_t - - fileprivate func call(_ fn: (inout indexstore_error_t?) -> T) throws -> T { - var error: indexstore_error_t? = nil - let ret = fn(&error) - - if let error = error { - if let desc = self.fn.error_get_description(error) { - throw StubError.error(String(cString: desc)) - } - throw StubError.error("Unable to get description for error: \(error)") - } - - return ret - } - - public init(dylib path: Path) throws { - self.path = path - self.dylib = try Library.open(path) - - var api = indexstore_functions_t() - api.store_create = Library.lookup(dylib, "indexstore_store_create") - api.store_get_unit_name_from_output_path = Library.lookup(dylib, "indexstore_store_get_unit_name_from_output_path") - api.unit_reader_create = Library.lookup(dylib, "indexstore_unit_reader_create") - api.error_get_description = Library.lookup(dylib, "indexstore_error_get_description") - api.unit_reader_dependencies_apply_f = Library.lookup(dylib, "indexstore_unit_reader_dependencies_apply_f") - api.unit_reader_get_module_name = Library.lookup(dylib, "indexstore_unit_reader_get_module_name") - api.unit_dependency_get_kind = Library.lookup(dylib, "indexstore_unit_dependency_get_kind") - api.unit_dependency_get_name = Library.lookup(dylib, "indexstore_unit_dependency_get_name") - api.record_reader_create = Library.lookup(dylib, "indexstore_record_reader_create") - api.symbol_get_name = Library.lookup(dylib, "indexstore_symbol_get_name") - api.symbol_get_properties = Library.lookup(dylib, "indexstore_symbol_get_properties") - api.symbol_get_kind = Library.lookup(dylib, "indexstore_symbol_get_kind") - api.record_reader_occurrences_apply_f = Library.lookup(dylib, "indexstore_record_reader_occurrences_apply_f") - api.occurrence_get_symbol = Library.lookup(dylib, "indexstore_occurrence_get_symbol") - api.occurrence_relations_apply_f = Library.lookup(dylib, "indexstore_occurrence_relations_apply_f") - api.symbol_relation_get_symbol = Library.lookup(dylib, "indexstore_symbol_relation_get_symbol") - api.symbol_relation_get_roles = Library.lookup(dylib, "indexstore_symbol_relation_get_roles") - - self.fn = api - } -} - -extension indexstore_string_ref_t { - fileprivate var str: String { - return String( - bytesNoCopy: UnsafeMutableRawPointer(mutating: data), - length: length, - encoding: .utf8, - freeWhenDone: false - )! - } -} diff --git a/Sources/SWBWindowsPlatform/Specs/Windows.xcspec b/Sources/SWBWindowsPlatform/Specs/Windows.xcspec index 9c58f4f4..df09990f 100644 --- a/Sources/SWBWindowsPlatform/Specs/Windows.xcspec +++ b/Sources/SWBWindowsPlatform/Specs/Windows.xcspec @@ -42,31 +42,6 @@ BasedOn = com.apple.product-type.tool; }, - { - Domain = windows; - Type = ProductType; - Identifier = com.apple.product-type.bundle.unit-test; - BasedOn = com.apple.product-type.library.dynamic; - DefaultBuildProperties = { - // Index store data is required to discover XCTest tests - COMPILER_INDEX_STORE_ENABLE = YES; - SWIFT_INDEX_STORE_ENABLE = YES; - // Testability is needed to generate code to invoke discovered XCTest tests - SWIFT_ENABLE_TESTABILITY = YES; - }; - }, - - { - Domain = windows; - Type = ProductType; - Identifier = com.apple.product-type.tool.swiftpm-test-runner; - BasedOn = default:com.apple.product-type.tool.swiftpm-test-runner; - DefaultBuildProperties = { - EXECUTABLE_SUFFIX = ".$(EXECUTABLE_EXTENSION)"; - EXECUTABLE_EXTENSION = "exe"; - }; - }, - { Domain = windows; Type = ProductType; diff --git a/Sources/SwiftBuild/ProjectModel/BuildSettings.swift b/Sources/SwiftBuild/ProjectModel/BuildSettings.swift index ae10d9de..a8909c03 100644 --- a/Sources/SwiftBuild/ProjectModel/BuildSettings.swift +++ b/Sources/SwiftBuild/ProjectModel/BuildSettings.swift @@ -99,7 +99,6 @@ extension ProjectModel { case SUPPORTS_TEXT_BASED_API case SUPPRESS_WARNINGS case SWIFT_ENABLE_BARE_SLASH_REGEX - case SWIFT_INDEX_STORE_ENABLE case SWIFT_INSTALL_MODULE case SWIFT_PACKAGE_NAME case SWIFT_USER_MODULE_VERSION @@ -147,7 +146,6 @@ extension ProjectModel { case SPECIALIZATION_SDK_OPTIONS case SWIFT_VERSION case SWIFT_ACTIVE_COMPILATION_CONDITIONS - case DYLIB_INSTALL_NAME_BASE } public enum Platform: Hashable, CaseIterable, Sendable { diff --git a/Sources/SwiftBuild/ProjectModel/Targets.swift b/Sources/SwiftBuild/ProjectModel/Targets.swift index efd4749c..0f8a201a 100644 --- a/Sources/SwiftBuild/ProjectModel/Targets.swift +++ b/Sources/SwiftBuild/ProjectModel/Targets.swift @@ -316,7 +316,6 @@ extension ProjectModel { case executable = "com.apple.product-type.tool" case hostBuildTool = "com.apple.product-type.tool.host-build" case unitTest = "com.apple.product-type.bundle.unit-test" - case swiftpmTestRunner = "com.apple.product-type.tool.swiftpm-test-runner" case bundle = "com.apple.product-type.bundle" case packageProduct = "packageProduct" } diff --git a/Tests/SWBBuildSystemTests/BuildOperationTests.swift b/Tests/SWBBuildSystemTests/BuildOperationTests.swift index f3a0c446..e6c0caaf 100644 --- a/Tests/SWBBuildSystemTests/BuildOperationTests.swift +++ b/Tests/SWBBuildSystemTests/BuildOperationTests.swift @@ -399,7 +399,7 @@ fileprivate struct BuildOperationTests: CoreBasedTests { @Test(.requireSDKs(.host), .skipHostOS(.macOS), .skipHostOS(.windows, "cannot find testing library")) func unitTestWithGeneratedEntryPoint() async throws { - try await withTemporaryDirectory(removeTreeOnDeinit: false) { (tmpDir: Path) in + try await withTemporaryDirectory { (tmpDir: Path) in let testProject = try await TestProject( "TestProject", sourceRoot: tmpDir, @@ -417,32 +417,14 @@ fileprivate struct BuildOperationTests: CoreBasedTests { "SDKROOT": "$(HOST_PLATFORM)", "SUPPORTED_PLATFORMS": "$(HOST_PLATFORM)", "SWIFT_VERSION": swiftVersion, - "INDEX_DATA_STORE_DIR": "\(tmpDir.join("index").str)", - "LINKER_DRIVER": "swiftc" ]) ], targets: [ TestStandardTarget( - "UnitTestRunner", - type: .swiftpmTestRunner, - buildConfigurations: [ - TestBuildConfiguration("Debug", - buildSettings: [:]), - ], - buildPhases: [ - TestSourcesBuildPhase(), - TestFrameworksBuildPhase([ - "MyTests.so" - ]) - ], - dependencies: ["MyTests"] - ), - TestStandardTarget( - "MyTests", + "test", type: .unitTest, buildConfigurations: [ TestBuildConfiguration("Debug", buildSettings: [ - "DYLIB_INSTALL_NAME_BASE": "$ORIGIN", "LD_RUNPATH_SEARCH_PATHS": "@loader_path/", ]) ], @@ -451,10 +433,10 @@ fileprivate struct BuildOperationTests: CoreBasedTests { TestFrameworksBuildPhase([ TestBuildFile(.target("library")), ]) - ], dependencies: [ - "library" ], - productReferenceName: "MyTests.so" + dependencies: [ + "library" + ] ), TestStandardTarget( "library", @@ -462,7 +444,6 @@ fileprivate struct BuildOperationTests: CoreBasedTests { buildConfigurations: [ TestBuildConfiguration("Debug", buildSettings: [ "DYLIB_INSTALL_NAME_BASE": "$ORIGIN", - "LD_RUNPATH_SEARCH_PATHS": "@loader_path/", // FIXME: Find a way to make these default "EXECUTABLE_PREFIX": "lib", @@ -476,7 +457,7 @@ fileprivate struct BuildOperationTests: CoreBasedTests { ]) let core = try await getCore() let tester = try await BuildOperationTester(core, testProject, simulated: false) - try localFS.createDirectory(tmpDir.join("index")) + let projectDir = tester.workspace.projects[0].sourceRoot try await tester.fs.writeFileContents(projectDir.join("library.swift")) { stream in @@ -486,19 +467,12 @@ fileprivate struct BuildOperationTests: CoreBasedTests { try await tester.fs.writeFileContents(projectDir.join("test.swift")) { stream in stream <<< """ import Testing - import XCTest import library @Suite struct MySuite { - @Test func myTest() { + @Test func myTest() async throws { #expect(foo() == 42) } } - - final class MYXCTests: XCTestCase { - func testFoo() { - XCTAssertTrue(true) - } - } """ } @@ -509,19 +483,13 @@ fileprivate struct BuildOperationTests: CoreBasedTests { let toolchain = try #require(try await getCore().toolchainRegistry.defaultToolchain) let environment: Environment if destination.platform == "linux" { - environment = ["LD_LIBRARY_PATH": "\(toolchain.path.join("usr/lib/swift/linux").str):\(projectDir.join("build").join("Debug\(destination.builtProductsDirSuffix)"))"] + environment = ["LD_LIBRARY_PATH": toolchain.path.join("usr/lib/swift/linux").str] } else { environment = .init() } - do { - let executionResult = try await Process.getOutput(url: URL(fileURLWithPath: projectDir.join("build").join("Debug\(destination.builtProductsDirSuffix)").join(core.hostOperatingSystem.imageFormat.executableName(basename: "UnitTestRunner")).str), arguments: [], environment: environment) - #expect(String(decoding: executionResult.stdout, as: UTF8.self).contains("Executed 1 test, with 0 failures")) - } - do { - let executionResult = try await Process.getOutput(url: URL(fileURLWithPath: projectDir.join("build").join("Debug\(destination.builtProductsDirSuffix)").join(core.hostOperatingSystem.imageFormat.executableName(basename: "UnitTestRunner")).str), arguments: ["--testing-library", "swift-testing"], environment: environment) - #expect(String(decoding: executionResult.stderr, as: UTF8.self).contains("Test run with 1 test in 1 suite passed")) - } + let executionResult = try await Process.getOutput(url: URL(fileURLWithPath: projectDir.join("build").join("Debug\(destination.builtProductsDirSuffix)").join(core.hostOperatingSystem.imageFormat.executableName(basename: "test.xctest")).str), arguments: ["--testing-library", "swift-testing"], environment: environment) + #expect(String(decoding: executionResult.stderr, as: UTF8.self).contains("Test run started")) } } } diff --git a/Tests/SWBTaskConstructionTests/UnitTestTaskConstructionTests.swift b/Tests/SWBTaskConstructionTests/UnitTestTaskConstructionTests.swift index ce4515df..d40bc363 100644 --- a/Tests/SWBTaskConstructionTests/UnitTestTaskConstructionTests.swift +++ b/Tests/SWBTaskConstructionTests/UnitTestTaskConstructionTests.swift @@ -300,7 +300,7 @@ fileprivate struct UnitTestTaskConstructionTests: CoreBasedTests { } @Test(.requireSDKs(.linux)) - func unitTestRunnerTarget_linux() async throws { + func unitTestTarget_linux() async throws { let swiftCompilerPath = try await self.swiftCompilerPath let swiftVersion = try await self.swiftVersion let testProject = TestProject( @@ -319,26 +319,9 @@ fileprivate struct UnitTestTaskConstructionTests: CoreBasedTests { "PRODUCT_NAME": "$(TARGET_NAME)", "SDKROOT": "linux", "SWIFT_VERSION": swiftVersion, - "INDEX_DATA_STORE_DIR": "/index", - "LINKER_DRIVER": "swiftc" ]), ], targets: [ - TestStandardTarget( - "UnitTestRunner", - type: .swiftpmTestRunner, - buildConfigurations: [ - TestBuildConfiguration("Debug", - buildSettings: [:]), - ], - buildPhases: [ - TestSourcesBuildPhase(), - TestFrameworksBuildPhase([ - "UnitTestTarget.so" - ]) - ], - dependencies: ["UnitTestTarget"], - ), TestStandardTarget( "UnitTestTarget", type: .unitTest, @@ -352,8 +335,7 @@ fileprivate struct UnitTestTaskConstructionTests: CoreBasedTests { "TestTwo.swift", ]), ], - dependencies: [], - productReferenceName: "UnitTestTarget.so" + dependencies: [] ), ]) let core = try await getCore() @@ -364,17 +346,14 @@ fileprivate struct UnitTestTaskConstructionTests: CoreBasedTests { try await fs.writeFileContents(swiftCompilerPath) { $0 <<< "binary" } await tester.checkBuild(runDestination: .linux, fs: fs) { results in - results.checkTarget("UnitTestRunner") { target in + results.checkTarget("UnitTestTarget") { target in results.checkTask(.matchTarget(target), .matchRuleType("GenerateTestEntryPoint")) { task in - task.checkCommandLineMatches([.suffix("builtin-generateTestEntryPoint"), "--output", .suffix("test_entry_point.swift"), "--index-store-library-path", .suffix("libIndexStore.so"), "--linker-filelist", .suffix("UnitTestTarget.LinkFileList"), "--index-store", "/index", "--index-unit-base-path", "/tmp/Test/aProject/build"]) - task.checkInputs([ - .pathPattern(.suffix("UnitTestTarget.LinkFileList")), - .pathPattern(.suffix("UnitTestTarget.so")), - .namePattern(.any), - .namePattern(.any) - ]) + task.checkCommandLineMatches([.suffix("builtin-generateTestEntryPoint"), "--output", .suffix("test_entry_point.swift")]) task.checkOutputs([.pathPattern(.suffix("test_entry_point.swift"))]) } + results.checkTask(.matchTarget(target), .matchRuleType("SwiftDriver Compilation")) { task in + task.checkInputs(contain: [.pathPattern(.suffix("test_entry_point.swift"))]) + } } results.checkNoDiagnostics()