diff --git a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift index f82f050328b..e19e1cc6428 100644 --- a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift +++ b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift @@ -314,11 +314,26 @@ public struct BuildParameters: Encodable { case .library(.automatic), .plugin: fatalError() case .test: - let base = "\(product.name).xctest" - if self.triple.isDarwin() { - return try RelativePath(validating: "\(base)/Contents/MacOS/\(product.name)") - } else { - return try RelativePath(validating: base) + switch buildSystemKind { + case .native, .xcode: + let base = "\(product.name).xctest" + if self.triple.isDarwin() { + return try RelativePath(validating: "\(base)/Contents/MacOS/\(product.name)") + } else { + return try RelativePath(validating: base) + } + case .swiftbuild: + if self.triple.isDarwin() { + let base = "\(product.name).xctest" + return try RelativePath(validating: "\(base)/Contents/MacOS/\(product.name)") + } else { + var base = "\(product.name)-test-runner" + let ext = self.triple.executableExtension + if !ext.isEmpty { + base += ext + } + return try RelativePath(validating: base) + } } case .macro: #if BUILD_MACROS_AS_DYLIBS diff --git a/Sources/SPMBuildCore/BuiltTestProduct.swift b/Sources/SPMBuildCore/BuiltTestProduct.swift index 3c923ce5c57..7830caffcaf 100644 --- a/Sources/SPMBuildCore/BuiltTestProduct.swift +++ b/Sources/SPMBuildCore/BuiltTestProduct.swift @@ -28,6 +28,10 @@ public struct BuiltTestProduct: Codable { /// When the test product is not bundled (for instance, when using XCTest on /// non-Darwin targets), this path is equal to ``binaryPath``. public var bundlePath: AbsolutePath { + // If the binary path is a test runner binary, return it as-is. + guard !binaryPath.basenameWithoutExt.hasSuffix("test-runner") else { + return binaryPath + } // Go up the folder hierarchy until we find the .xctest bundle. let pathExtension = ".xctest" let hierarchySequence = sequence(first: binaryPath, next: { $0.isRoot ? nil : $0.parentDirectory }) diff --git a/Sources/SwiftBuildSupport/PIFBuilder.swift b/Sources/SwiftBuildSupport/PIFBuilder.swift index fdc89124ea9..00d438cd1f7 100644 --- a/Sources/SwiftBuildSupport/PIFBuilder.swift +++ b/Sources/SwiftBuildSupport/PIFBuilder.swift @@ -633,13 +633,13 @@ fileprivate func buildAggregateProject( continue } } - + aggregateProject[keyPath: allIncludingTestsTargetKeyPath].common.addDependency( on: target.id, platformFilters: [], linkProduct: false ) - if target.productType != .unitTest { + if ![.unitTest, .swiftpmTestRunner].contains(target.productType) { aggregateProject[keyPath: allExcludingTestsTargetKeyPath].common.addDependency( on: target.id, platformFilters: [], diff --git a/Sources/SwiftBuildSupport/PackagePIFBuilder+Helpers.swift b/Sources/SwiftBuildSupport/PackagePIFBuilder+Helpers.swift index f49dffc2601..c863167c274 100644 --- a/Sources/SwiftBuildSupport/PackagePIFBuilder+Helpers.swift +++ b/Sources/SwiftBuildSupport/PackagePIFBuilder+Helpers.swift @@ -897,7 +897,7 @@ extension ProjectModel.BuildSettings { // Appending implies the setting is resilient to having ["$(inherited)"] self.platformSpecificSettings[platform]![setting]!.append(contentsOf: values) - case .SWIFT_VERSION: + case .SWIFT_VERSION, .DYLIB_INSTALL_NAME_BASE: self.platformSpecificSettings[platform]![setting] = values // We are not resilient to $(inherited). case .ARCHS, .IPHONEOS_DEPLOYMENT_TARGET, .SPECIALIZATION_SDK_OPTIONS: @@ -922,6 +922,9 @@ extension ProjectModel.BuildSettings { case .SWIFT_VERSION: self[.SWIFT_VERSION] = values.only.unwrap(orAssert: "Invalid values for 'SWIFT_VERSION': \(values)") + case .DYLIB_INSTALL_NAME_BASE: + self[.DYLIB_INSTALL_NAME_BASE] = values.only.unwrap(orAssert: "Invalid values for 'DYLIB_INSTALL_NAME_BASE': \(values)") + case .ARCHS, .IPHONEOS_DEPLOYMENT_TARGET, .SPECIALIZATION_SDK_OPTIONS: fatalError("Unexpected BuildSettings.Declaration: \(setting)") // Allow staging in new cases @@ -953,7 +956,7 @@ extension ProjectModel.BuildSettings.MultipleValueSetting { self = .SPECIALIZATION_SDK_OPTIONS case .SWIFT_ACTIVE_COMPILATION_CONDITIONS: self = .SWIFT_ACTIVE_COMPILATION_CONDITIONS - case .ARCHS, .IPHONEOS_DEPLOYMENT_TARGET, .SWIFT_VERSION: + case .ARCHS, .IPHONEOS_DEPLOYMENT_TARGET, .SWIFT_VERSION, .DYLIB_INSTALL_NAME_BASE: return nil // Allow staging in new cases default: diff --git a/Sources/SwiftBuildSupport/PackagePIFBuilder.swift b/Sources/SwiftBuildSupport/PackagePIFBuilder.swift index 27ca56e19e4..8a3bb6e3b69 100644 --- a/Sources/SwiftBuildSupport/PackagePIFBuilder.swift +++ b/Sources/SwiftBuildSupport/PackagePIFBuilder.swift @@ -362,6 +362,7 @@ public final class PackagePIFBuilder { case framework case executable case unitTest + case unitTestRunner case bundle case resourceBundle case packageProduct @@ -385,6 +386,7 @@ public final class PackagePIFBuilder { case .framework: .framework case .executable: .executable case .unitTest: .unitTest + case .swiftpmTestRunner: .unitTestRunner case .bundle: .bundle case .packageProduct: .packageProduct case .hostBuildTool: fatalError("Unexpected hostBuildTool type") @@ -520,7 +522,11 @@ public final class PackagePIFBuilder { settings[.WATCHOS_DEPLOYMENT_TARGET] = builder.deploymentTargets[.watchOS] ?? nil settings[.DRIVERKIT_DEPLOYMENT_TARGET] = builder.deploymentTargets[.driverKit] ?? nil settings[.XROS_DEPLOYMENT_TARGET] = builder.deploymentTargets[.visionOS] ?? nil - settings[.DYLIB_INSTALL_NAME_BASE] = "@rpath" + + for machoPlatform in [ProjectModel.BuildSettings.Platform.macOS, .macCatalyst, .iOS, .watchOS, .tvOS, .xrOS, .driverKit] { + settings.platformSpecificSettings[machoPlatform]![.DYLIB_INSTALL_NAME_BASE]! = ["@rpath"] + } + settings[.USE_HEADERMAP] = "NO" settings[.OTHER_SWIFT_FLAGS].lazilyInitializeAndMutate(initialValue: ["$(inherited)"]) { $0.append("-DXcode") } diff --git a/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Modules.swift b/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Modules.swift index 284d7860f4e..c8c4751ba8b 100644 --- a/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Modules.swift +++ b/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Modules.swift @@ -768,7 +768,7 @@ extension PackagePIFProjectBuilder { // // An imparted build setting on C will propagate back to both B and A. impartedSettings[.LD_RUNPATH_SEARCH_PATHS] = - ["@loader_path"] + + ["$(RPATH_ORIGIN)"] + (impartedSettings[.LD_RUNPATH_SEARCH_PATHS] ?? ["$(inherited)"]) var impartedDebugSettings = impartedSettings diff --git a/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Products.swift b/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Products.swift index 9525b69ba76..90d47bd2830 100644 --- a/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Products.swift +++ b/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Products.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import Foundation +import TSCBasic import TSCUtility import struct Basics.AbsolutePath @@ -121,13 +122,15 @@ extension PackagePIFProjectBuilder { if mainModule.type == .test { // FIXME: we shouldn't always include both the deep and shallow bundle paths here, but for that we'll need rdar://31867023 settings[.LD_RUNPATH_SEARCH_PATHS] = [ - "@loader_path/Frameworks", - "@loader_path/../Frameworks", + "$(RPATH_ORIGIN)/Frameworks", + "$(RPATH_ORIGIN)/../Frameworks", "$(inherited)" ] settings[.GENERATE_INFOPLIST_FILE] = "YES" settings[.SKIP_INSTALL] = "NO" settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS].lazilyInitialize { ["$(inherited)"] } + // Enable index-while building for Swift compilations to facilitate discovery of XCTest tests. + settings[.SWIFT_INDEX_STORE_ENABLE] = "YES" } else if mainModule.type == .executable { // Setup install path for executables if it's in root of a pure Swift package. if pifBuilder.delegate.hostsOnlyPackages && pifBuilder.delegate.isRootPackage { @@ -502,9 +505,13 @@ extension PackagePIFProjectBuilder { linkedPackageBinaries: linkedPackageBinaries, swiftLanguageVersion: mainModule.packageSwiftLanguageVersion(manifest: packageManifest), declaredPlatforms: self.declaredPlatforms, - deploymentTargets: self.deploymentTargets + deploymentTargets: mainTargetDeploymentTargets ) self.builtModulesAndProducts.append(moduleOrProduct) + + if moduleOrProductType == .unitTest { + try makeTestRunnerProduct(for: moduleOrProduct) + } } private mutating func handleProduct( @@ -995,6 +1002,102 @@ extension PackagePIFProjectBuilder { ) self.builtModulesAndProducts.append(pluginProductMetadata) } + + // MARK: - Test Runners + mutating func makeTestRunnerProduct(for unitTestProduct: PackagePIFBuilder.ModuleOrProduct) throws { + // Only generate a test runner for root packages with tests. + guard pifBuilder.delegate.isRootPackage else { + return + } + + guard let unitTestModuleName = unitTestProduct.moduleName else { + throw StringError("Unit test product '\(unitTestProduct.name)' is missing a module name") + } + + let name = "\(unitTestProduct.name)-test-runner" + let moduleName = "\(unitTestModuleName)_test_runner" + let guid = PackagePIFBuilder.targetGUID(forModuleName: moduleName) + + let testRunnerTargetKeyPath = try self.project.addTarget { _ in + ProjectModel.Target ( + id: guid, + productType: .swiftpmTestRunner, + name: name, + productName: name + ) + } + + var settings: BuildSettings = self.package.underlying.packageBaseBuildSettings + let impartedSettings = BuildSettings() + + settings[.TARGET_NAME] = name + settings[.PACKAGE_RESOURCE_TARGET_KIND] = "regular" + settings[.PRODUCT_NAME] = "$(TARGET_NAME)" + settings[.PRODUCT_MODULE_NAME] = moduleName + settings[.PRODUCT_BUNDLE_IDENTIFIER] = "\(self.package.identity).\(name)" + .spm_mangledToBundleIdentifier() + settings[.EXECUTABLE_NAME] = name + settings[.SKIP_INSTALL] = "NO" + settings[.SWIFT_VERSION] = "5.0" + // This should eventually be set universally for all package targets/products. + settings[.LINKER_DRIVER] = "swiftc" + + let deploymentTargets = unitTestProduct.deploymentTargets + settings[.MACOSX_DEPLOYMENT_TARGET] = deploymentTargets?[.macOS] ?? nil + settings[.IPHONEOS_DEPLOYMENT_TARGET] = deploymentTargets?[.iOS] ?? nil + if let deploymentTarget_macCatalyst = deploymentTargets?[.macCatalyst] ?? nil { + settings.platformSpecificSettings[.macCatalyst]![.IPHONEOS_DEPLOYMENT_TARGET] = [deploymentTarget_macCatalyst] + } + settings[.TVOS_DEPLOYMENT_TARGET] = deploymentTargets?[.tvOS] ?? nil + settings[.WATCHOS_DEPLOYMENT_TARGET] = deploymentTargets?[.watchOS] ?? nil + settings[.DRIVERKIT_DEPLOYMENT_TARGET] = deploymentTargets?[.driverKit] ?? nil + settings[.XROS_DEPLOYMENT_TARGET] = deploymentTargets?[.visionOS] ?? nil + + // Add an empty sources phase so derived sources are compiled + self.project[keyPath: testRunnerTargetKeyPath].common.addSourcesBuildPhase { id in + ProjectModel.SourcesBuildPhase(id: id) + } + + guard let unitTestGUID = unitTestProduct.pifTarget?.id else { + throw StringError("Unit test product '\(unitTestProduct.name)' is missing a PIF GUID") + } + self.project[keyPath: testRunnerTargetKeyPath].common.addDependency( + on: unitTestGUID, + platformFilters: [], + linkProduct: true + ) + + self.project[keyPath: testRunnerTargetKeyPath].common.addBuildConfig { id in + BuildConfig( + id: id, + name: "Debug", + settings: settings, + impartedBuildSettings: impartedSettings + ) + } + self.project[keyPath: testRunnerTargetKeyPath].common.addBuildConfig { id in + BuildConfig( + id: id, + name: "Release", + settings: settings, + impartedBuildSettings: impartedSettings + ) + } + + let testRunner = PackagePIFBuilder.ModuleOrProduct( + type: .unitTestRunner, + name: name, + moduleName: moduleName, + pifTarget: .target(self.project[keyPath: testRunnerTargetKeyPath]), + indexableFileURLs: [], + headerFiles: [], + linkedPackageBinaries: [], + swiftLanguageVersion: nil, + declaredPlatforms: self.declaredPlatforms, + deploymentTargets: self.deploymentTargets + ) + self.builtModulesAndProducts.append(testRunner) + } } // MARK: - Helper Types diff --git a/Tests/CommandsTests/PackageCommandTests.swift b/Tests/CommandsTests/PackageCommandTests.swift index 537612b23ff..8d1a27ecdcf 100644 --- a/Tests/CommandsTests/PackageCommandTests.swift +++ b/Tests/CommandsTests/PackageCommandTests.swift @@ -4107,7 +4107,6 @@ class PackageCommandSwiftBuildTests: PackageCommandTestCase { } override func testCommandPluginTestingCallbacks() async throws { - throw XCTSkip("SWBINTTODO: Requires PIF generation to adopt new test runner product type") try XCTSkipOnWindows(because: "TSCBasic/Path.swift:969: Assertion failed, https://github.com/swiftlang/swift-package-manager/issues/8602") try await super.testCommandPluginTestingCallbacks() } diff --git a/Tests/FunctionalTests/TestDiscoveryTests.swift b/Tests/FunctionalTests/TestDiscoveryTests.swift index ce0987ea147..b77ce814648 100644 --- a/Tests/FunctionalTests/TestDiscoveryTests.swift +++ b/Tests/FunctionalTests/TestDiscoveryTests.swift @@ -12,159 +12,185 @@ import Basics import PackageModel +import SPMBuildCore import _InternalTestSupport -import XCTest +import Testing +import struct Foundation.UUID +import class Foundation.ProcessInfo -final class TestDiscoveryTests: XCTestCase { - func testBuild() async throws { - try await fixture(name: "Miscellaneous/TestDiscovery/Simple") { fixturePath in - let (stdout, _) = try await executeSwiftBuild(fixturePath) - // in "swift build" build output goes to stdout - XCTAssertMatch(stdout, .contains("Build complete!")) +@Suite +struct TestDiscoveryTests { + static var buildSystems: [BuildSystemProvider.Kind] = [BuildSystemProvider.Kind.native, .swiftbuild] + + @Test(arguments: buildSystems) + func build(_ buildSystem: BuildSystemProvider.Kind) async throws { + try await withKnownIssue("Windows builds encounter long path handling issues", isIntermittent: true) { + try await fixture(name: "Miscellaneous/TestDiscovery/Simple") { fixturePath in + let (stdout, _) = try await executeSwiftBuild(fixturePath, buildSystem: buildSystem) + // in "swift build" build output goes to stdout + #expect(stdout.contains("Build complete!")) + } + } when: { + buildSystem == .swiftbuild && ProcessInfo.hostOperatingSystem == .windows } } - func testDiscovery() async throws { - try await fixture(name: "Miscellaneous/TestDiscovery/Simple") { fixturePath in - let (stdout, stderr) = try await executeSwiftTest(fixturePath) - // in "swift test" build output goes to stderr - XCTAssertMatch(stderr, .contains("Build complete!")) - // in "swift test" test output goes to stdout - XCTAssertMatch(stdout, .contains("Executed 3 tests")) + @Test(arguments: buildSystems) + func discovery(_ buildSystem: BuildSystemProvider.Kind) async throws { + try await withKnownIssue("Windows builds encounter long path handling issues", isIntermittent: true) { + try await fixture(name: "Miscellaneous/TestDiscovery/Simple") { fixturePath in + let (stdout, stderr) = try await executeSwiftTest(fixturePath, extraArgs: ["-vv"], buildSystem: buildSystem) + // in "swift test" build output goes to stderr + #expect(stderr.contains("Build complete!")) + // in "swift test" test output goes to stdout + #expect(stdout.contains("Executed 3 tests")) + } + } when: { + buildSystem == .swiftbuild && ProcessInfo.hostOperatingSystem == .windows } } - func testNonStandardName() async throws { + @Test(.bug("https://github.com/swiftlang/swift-build/issues/13"), arguments: [BuildSystemProvider.Kind.native]) + func nonStandardName(_ buildSystem: BuildSystemProvider.Kind) async throws { try await fixture(name: "Miscellaneous/TestDiscovery/hello world") { fixturePath in - let (stdout, stderr) = try await executeSwiftTest(fixturePath) + let (stdout, stderr) = try await executeSwiftTest(fixturePath, buildSystem: buildSystem) // in "swift test" build output goes to stderr - XCTAssertMatch(stderr, .contains("Build complete!")) + #expect(stderr.contains("Build complete!")) // in "swift test" test output goes to stdout - XCTAssertMatch(stdout, .contains("Executed 1 test")) + #expect(stdout.contains("Executed 1 test")) } } - func testAsyncMethods() async throws { - try await fixture(name: "Miscellaneous/TestDiscovery/Async") { fixturePath in - let (stdout, stderr) = try await executeSwiftTest(fixturePath) - // in "swift test" build output goes to stderr - XCTAssertMatch(stderr, .contains("Build complete!")) - // in "swift test" test output goes to stdout - XCTAssertMatch(stdout, .contains("Executed 4 tests")) + @Test(arguments: buildSystems) + func asyncMethods(_ buildSystem: BuildSystemProvider.Kind) async throws { + try await withKnownIssue("Windows builds encounter long path handling issues", isIntermittent: true) { + try await fixture(name: "Miscellaneous/TestDiscovery/Async") { fixturePath in + let (stdout, stderr) = try await executeSwiftTest(fixturePath, buildSystem: buildSystem) + // in "swift test" build output goes to stderr + #expect(stderr.contains("Build complete!")) + // in "swift test" test output goes to stdout + #expect(stdout.contains("Executed 4 tests")) + } + } when: { + buildSystem == .swiftbuild && ProcessInfo.hostOperatingSystem == .windows } } - func testDiscovery_whenNoTests() async throws { - #if os(macOS) - try XCTSkipIf(true) - #endif + // FIXME: eliminate extraneous warnings with --build-system swiftbuild + @Test(.bug("https://github.com/swiftlang/swift-build/issues/573"), .skipHostOS(.macOS), arguments: [BuildSystemProvider.Kind.native]) + func discovery_whenNoTests(_ buildSystem: BuildSystemProvider.Kind) async throws { try await fixture(name: "Miscellaneous/TestDiscovery/NoTests") { fixturePath in - let (stdout, stderr) = try await executeSwiftTest(fixturePath) + let (stdout, stderr) = try await executeSwiftTest(fixturePath, buildSystem: buildSystem) // in "swift test" build output goes to stderr - XCTAssertMatch(stderr, .contains("Build complete!")) + #expect(stderr.contains("Build complete!")) // we are expecting that no warning is produced - XCTAssertNoMatch(stderr, .contains("warning:")) + #expect(!stderr.contains("warning:")) // in "swift test" test output goes to stdout - XCTAssertMatch(stdout, .contains("Executed 0 tests")) + #expect(stdout.contains("Executed 0 tests")) } } - func testEntryPointOverride() async throws { - #if os(macOS) - try XCTSkipIf(true) - #endif - + // FIXME: --build-system swiftbuild should support hand-authored entry points. + @Test(.bug("https://github.com/swiftlang/swift-build/issues/572"), .skipHostOS(.macOS), arguments: [BuildSystemProvider.Kind.native]) + func entryPointOverride(_ buildSystem: BuildSystemProvider.Kind) async throws { for name in SwiftModule.testEntryPointNames { try await fixture(name: "Miscellaneous/TestDiscovery/Simple") { fixturePath in let random = UUID().uuidString let manifestPath = fixturePath.appending(components: "Tests", name) try localFileSystem.writeFileContents(manifestPath, string: "print(\"\(random)\")") - let (stdout, stderr) = try await executeSwiftTest(fixturePath) + let (stdout, stderr) = try await executeSwiftTest(fixturePath, buildSystem: buildSystem) // in "swift test" build output goes to stderr - XCTAssertMatch(stderr, .contains("Build complete!")) + #expect(stderr.contains("Build complete!")) // in "swift test" test output goes to stdout - XCTAssertNoMatch(stdout, .contains("Executed 1 test")) - XCTAssertMatch(stdout, .contains(random)) + #expect(!stdout.contains("Executed 1 test")) + #expect(stdout.contains(random)) } } } - func testEntryPointOverrideIgnored() async throws { - #if os(macOS) - try XCTSkipIf(true) - #endif - - try await fixture(name: "Miscellaneous/TestDiscovery/Simple") { fixturePath in - let manifestPath = fixturePath.appending(components: "Tests", SwiftModule.defaultTestEntryPointName) - try localFileSystem.writeFileContents(manifestPath, string: "fatalError(\"should not be called\")") - let (stdout, stderr) = try await executeSwiftTest(fixturePath, extraArgs: ["--enable-test-discovery"]) - // in "swift test" build output goes to stderr - XCTAssertMatch(stderr, .contains("Build complete!")) - // in "swift test" test output goes to stdout - XCTAssertNoMatch(stdout, .contains("Executed 1 test")) + @Test(.skipHostOS(.macOS), arguments: buildSystems) + func entryPointOverrideIgnored(_ buildSystem: BuildSystemProvider.Kind) async throws { + try await withKnownIssue("Windows builds encounter long path handling issues", isIntermittent: true) { + try await fixture(name: "Miscellaneous/TestDiscovery/Simple") { fixturePath in + let manifestPath = fixturePath.appending(components: "Tests", SwiftModule.defaultTestEntryPointName) + try localFileSystem.writeFileContents(manifestPath, string: "fatalError(\"should not be called\")") + let (stdout, stderr) = try await executeSwiftTest(fixturePath, extraArgs: ["--enable-test-discovery"], buildSystem: buildSystem) + // in "swift test" build output goes to stderr + #expect(stderr.contains("Build complete!")) + // in "swift test" test output goes to stdout + #expect(!stdout.contains("Executed 1 test")) + } + } when: { + buildSystem == .swiftbuild && ProcessInfo.hostOperatingSystem == .windows } } - func testTestExtensions() async throws { - #if os(macOS) - try XCTSkipIf(true) - #endif - try await fixture(name: "Miscellaneous/TestDiscovery/Extensions") { fixturePath in - let (stdout, stderr) = try await executeSwiftTest(fixturePath) - // in "swift test" build output goes to stderr - XCTAssertMatch(stderr, .contains("Build complete!")) - // in "swift test" test output goes to stdout - XCTAssertMatch(stdout, .contains("SimpleTests1.testExample1")) - XCTAssertMatch(stdout, .contains("SimpleTests1.testExample1_a")) - XCTAssertMatch(stdout, .contains("SimpleTests2.testExample2")) - XCTAssertMatch(stdout, .contains("SimpleTests2.testExample2_a")) - XCTAssertMatch(stdout, .contains("SimpleTests4.testExample")) - XCTAssertMatch(stdout, .contains("SimpleTests4.testExample1")) - XCTAssertMatch(stdout, .contains("SimpleTests4.testExample2")) - XCTAssertMatch(stdout, .contains("Executed 7 tests")) + @Test(.skipHostOS(.macOS), arguments: buildSystems) + func testExtensions(_ buildSystem: BuildSystemProvider.Kind) async throws { + try await withKnownIssue("Windows builds encounter long path handling issues", isIntermittent: true) { + try await fixture(name: "Miscellaneous/TestDiscovery/Extensions") { fixturePath in + let (stdout, stderr) = try await executeSwiftTest(fixturePath, buildSystem: buildSystem) + // in "swift test" build output goes to stderr + #expect(stderr.contains("Build complete!")) + // in "swift test" test output goes to stdout + #expect(stdout.contains("SimpleTests1.testExample1")) + #expect(stdout.contains("SimpleTests1.testExample1_a")) + #expect(stdout.contains("SimpleTests2.testExample2")) + #expect(stdout.contains("SimpleTests2.testExample2_a")) + #expect(stdout.contains("SimpleTests4.testExample")) + #expect(stdout.contains("SimpleTests4.testExample1")) + #expect(stdout.contains("SimpleTests4.testExample2")) + #expect(stdout.contains("Executed 7 tests")) + } + } when: { + buildSystem == .swiftbuild && ProcessInfo.hostOperatingSystem == .windows } } - func testDeprecatedTests() async throws { - #if os(macOS) - try XCTSkipIf(true) - #endif - try await fixture(name: "Miscellaneous/TestDiscovery/Deprecation") { fixturePath in - let (stdout, stderr) = try await executeSwiftTest(fixturePath) - // in "swift test" test output goes to stdout - XCTAssertMatch(stdout, .contains("Executed 2 tests")) - XCTAssertNoMatch(stderr, .contains("is deprecated")) + @Test(.skipHostOS(.macOS), arguments: buildSystems) + func deprecatedTests(_ buildSystem: BuildSystemProvider.Kind) async throws { + try await withKnownIssue("Windows builds encounter long path handling issues", isIntermittent: true) { + try await fixture(name: "Miscellaneous/TestDiscovery/Deprecation") { fixturePath in + let (stdout, stderr) = try await executeSwiftTest(fixturePath, buildSystem: buildSystem) + // in "swift test" test output goes to stdout + #expect(stdout.contains("Executed 2 tests")) + #expect(!stderr.contains("is deprecated")) + } + } when: { + buildSystem == .swiftbuild && ProcessInfo.hostOperatingSystem == .windows } } - func testSubclassedTestClassTests() async throws { - #if os(macOS) - try XCTSkipIf(true) - #endif - try await fixture(name: "Miscellaneous/TestDiscovery/Subclass") { fixturePath in - let (stdout, stderr) = try await executeSwiftTest(fixturePath) - // in "swift test" build output goes to stderr - XCTAssertMatch(stderr, .contains("Build complete!")) - // in "swift test" test output goes to stdout - XCTAssertMatch(stdout, .contains("Tests3.test11")) - XCTAssertMatch(stdout, .contains("->Module1::Tests1::test11")) - XCTAssertMatch(stdout, .contains("Tests3.test12")) - XCTAssertMatch(stdout, .contains("->Module1::Tests1::test12")) - XCTAssertMatch(stdout, .contains("Tests3.test13")) - XCTAssertMatch(stdout, .contains("->Module1::Tests1::test13")) - XCTAssertMatch(stdout, .contains("Tests3.test21")) - XCTAssertMatch(stdout, .contains("->Module1::Tests2::test21")) - XCTAssertMatch(stdout, .contains("Tests3.test22")) - XCTAssertMatch(stdout, .contains("->Module1::Tests2::test22")) - XCTAssertMatch(stdout, .contains("Tests3.test31")) - XCTAssertMatch(stdout, .contains("->Module1::Tests3::test31")) - XCTAssertMatch(stdout, .contains("Tests3.test32")) - XCTAssertMatch(stdout, .contains("->Module1::Tests3::test32")) - XCTAssertMatch(stdout, .contains("Tests3.test33")) - XCTAssertMatch(stdout, .contains("->Module1::Tests3::test33")) + @Test(.skipHostOS(.macOS), arguments: buildSystems) + func testSubclassedTestClassTests(_ buildSystem: BuildSystemProvider.Kind) async throws { + try await withKnownIssue("Windows builds encounter long path handling issues", isIntermittent: true) { + try await fixture(name: "Miscellaneous/TestDiscovery/Subclass") { fixturePath in + let (stdout, stderr) = try await executeSwiftTest(fixturePath, buildSystem: buildSystem) + // in "swift test" build output goes to stderr + #expect(stderr.contains("Build complete!")) + // in "swift test" test output goes to stdout + #expect(stdout.contains("Tests3.test11")) + #expect(stdout.contains("->Module1::Tests1::test11")) + #expect(stdout.contains("Tests3.test12")) + #expect(stdout.contains("->Module1::Tests1::test12")) + #expect(stdout.contains("Tests3.test13")) + #expect(stdout.contains("->Module1::Tests1::test13")) + #expect(stdout.contains("Tests3.test21")) + #expect(stdout.contains("->Module1::Tests2::test21")) + #expect(stdout.contains("Tests3.test22")) + #expect(stdout.contains("->Module1::Tests2::test22")) + #expect(stdout.contains("Tests3.test31")) + #expect(stdout.contains("->Module1::Tests3::test31")) + #expect(stdout.contains("Tests3.test32")) + #expect(stdout.contains("->Module1::Tests3::test32")) + #expect(stdout.contains("Tests3.test33")) + #expect(stdout.contains("->Module1::Tests3::test33")) - XCTAssertMatch(stdout, .contains("->Module2::Tests1::test11")) - XCTAssertMatch(stdout, .contains("->Module2::Tests1::test12")) + #expect(stdout.contains("->Module2::Tests1::test11")) + #expect(stdout.contains("->Module2::Tests1::test12")) + } + } when: { + buildSystem == .swiftbuild && ProcessInfo.hostOperatingSystem == .windows } } } diff --git a/Tests/FunctionalTests/TraitTests.swift b/Tests/FunctionalTests/TraitTests.swift index 78555939e33..c608190b223 100644 --- a/Tests/FunctionalTests/TraitTests.swift +++ b/Tests/FunctionalTests/TraitTests.swift @@ -401,7 +401,7 @@ struct TraitTests { } } when: { ProcessInfo.hostOperatingSystem == .windows && CiEnvironment.runningInSmokeTestPipeline - || (buildSystem == .swiftbuild && [.windows, .linux].contains(ProcessInfo.hostOperatingSystem)) + || (buildSystem == .swiftbuild && [.windows].contains(ProcessInfo.hostOperatingSystem)) } }