diff --git a/Sources/_InternalTestSupport/BuildSystemProvider+Configuration.swift b/Sources/_InternalTestSupport/BuildSystemProvider+Configuration.swift index 5b7adcff485..30b3db4b2c7 100644 --- a/Sources/_InternalTestSupport/BuildSystemProvider+Configuration.swift +++ b/Sources/_InternalTestSupport/BuildSystemProvider+Configuration.swift @@ -12,16 +12,18 @@ import struct SPMBuildCore.BuildSystemProvider import enum PackageModel.BuildConfiguration +import class PackageModel.UserToolchain extension BuildSystemProvider.Kind { + @available(*, deprecated, message: "use binPath(for:scrathPath:triple) instead") public func binPathSuffixes(for config: BuildConfiguration) -> [String] { let suffix: String #if os(Linux) suffix = "-linux" #elseif os(Windows) - suffix = "-windows" + suffix = "-windows" #else suffix = "" #endif @@ -34,4 +36,40 @@ extension BuildSystemProvider.Kind { return ["apple", "Products" , "\(config)".capitalized + suffix] } } + + public func binPath( + for config: BuildConfiguration, + scratchPath: [String] = [".build"], + triple: String? = nil, + ) throws -> [String] { + let suffix: String + + #if os(Linux) + suffix = "-linux" + #elseif os(Windows) + suffix = "-windows" + #else + suffix = "" + #endif + + let tripleString: String + if let triple { + tripleString = triple + } else { + do { + tripleString = try UserToolchain.default.targetTriple.platformBuildPathComponent + } catch { + tripleString = "" + } + } + switch self { + case .native: + return scratchPath + [tripleString, "\(config)".lowercased()] + case .swiftbuild: + return scratchPath + [tripleString, "Products", "\(config)".capitalized + suffix] + case .xcode: + return scratchPath + ["apple", "Products", "\(config)".capitalized + suffix] + } + } + } diff --git a/Sources/_InternalTestSupport/SwiftTesting+TraitConditional.swift b/Sources/_InternalTestSupport/SwiftTesting+TraitConditional.swift index 9f7802e69fa..995391b89d7 100644 --- a/Sources/_InternalTestSupport/SwiftTesting+TraitConditional.swift +++ b/Sources/_InternalTestSupport/SwiftTesting+TraitConditional.swift @@ -79,6 +79,13 @@ extension Trait where Self == Testing.ConditionTrait { } } + /// Enabled if toolsupm suported SDK Dependent Tests + public static var requiresSDKDependentTestsSupport: Self { + enabled("skipping because test environment doesn't support this test") { + (try? UserToolchain.default)!.supportsSDKDependentTests() + } + } + // Enabled if the toolchain has supported features public static var supportsSupportedFeatures: Self { enabled("skipping because test environment compiler doesn't support `-print-supported-features`") { diff --git a/Tests/BuildTests/BuildSystemDelegateTests.swift b/Tests/BuildTests/BuildSystemDelegateTests.swift index 364df5cf7c7..52108d01e62 100644 --- a/Tests/BuildTests/BuildSystemDelegateTests.swift +++ b/Tests/BuildTests/BuildSystemDelegateTests.swift @@ -2,50 +2,94 @@ // // This source file is part of the Swift open source project // -// Copyright (c) 2024 Apple Inc. and the Swift project authors +// Copyright (c) 2024-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 Foundation import PackageModel import _InternalTestSupport -import XCTest +import Testing import var TSCBasic.localFileSystem -final class BuildSystemDelegateTests: XCTestCase { - func testDoNotFilterLinkerDiagnostics() async throws { - try XCTSkipIf(!UserToolchain.default.supportsSDKDependentTests(), "skipping because test environment doesn't support this test") - try await fixtureXCTest(name: "Miscellaneous/DoNotFilterLinkerDiagnostics") { fixturePath in - #if !os(macOS) - // These linker diagnostics are only produced on macOS. - try XCTSkipIf(true, "test is only supported on macOS") - #endif - let (fullLog, _) = try await executeSwiftBuild(fixturePath, buildSystem: .native) - XCTAssertTrue(fullLog.contains("ld: warning: search path 'foobar' not found"), "log didn't contain expected linker diagnostics") +@Suite( + .tags( + .TestSize.large, + ) +) +struct BuildSystemDelegateTests { + @Test( + .requiresSDKDependentTestsSupport, + .requireHostOS(.macOS), // These linker diagnostics are only produced on macOS. + arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms), + ) + func doNotFilterLinkerDiagnostics( + data: BuildData, + ) async throws { + try await fixture(name: "Miscellaneous/DoNotFilterLinkerDiagnostics") { fixturePath in + let (stdout, stderr) = try await executeSwiftBuild( + fixturePath, + configuration: data.config, + // extraArgs: ["--verbose"], + buildSystem: data.buildSystem, + ) + switch data.buildSystem { + case .native: + #expect( + stdout.contains("ld: warning: search path 'foobar' not found"), + "log didn't contain expected linker diagnostics. stderr: '\(stderr)')", + ) + case .swiftbuild: + #expect( + stderr.contains("warning: Search path 'foobar' not found"), + "log didn't contain expected linker diagnostics. stderr: '\(stdout)", + ) + #expect( + !stdout.contains("warning: Search path 'foobar' not found"), + "log didn't contain expected linker diagnostics. stderr: '\(stderr)')", + ) + case .xcode: + Issue.record("Test expectation has not be implemented") + } } } - func testFilterNonFatalCodesignMessages() async throws { - try XCTSkipOnWindows(because: "https://github.com/swiftlang/swift-package-manager/issues/8540: Package fails to build when the test is being executed") - - try XCTSkipIf(!UserToolchain.default.supportsSDKDependentTests(), "skipping because test environment doesn't support this test") - // Note: we can re-use the `TestableExe` fixture here since we just need an executable. - #if os(Windows) - let executableExt = ".exe" - #else - let executableExt = "" - #endif - try await fixtureXCTest(name: "Miscellaneous/TestableExe") { fixturePath in - _ = try await executeSwiftBuild(fixturePath, buildSystem: .native) - let execPath = fixturePath.appending(components: ".build", "debug", "TestableExe1\(executableExt)") - XCTAssertTrue(localFileSystem.exists(execPath), "executable not found at '\(execPath)'") - try localFileSystem.removeFileTree(execPath) - let (fullLog, _) = try await executeSwiftBuild(fixturePath, buildSystem: .native) - XCTAssertFalse(fullLog.contains("replacing existing signature"), "log contained non-fatal codesigning messages") + @Test( + .issue("https://github.com/swiftlang/swift-package-manager/issues/8540", relationship: .defect), // Package fails to build when the test is being executed" + .requiresSDKDependentTestsSupport, + arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms), + ) + func filterNonFatalCodesignMessages( + data: BuildData, + ) async throws { + try await withKnownIssue(isIntermittent: true) { + // Note: we can re-use the `TestableExe` fixture here since we just need an executable. + try await fixture(name: "Miscellaneous/TestableExe") { fixturePath in + _ = try await executeSwiftBuild( + fixturePath, + configuration: data.config, + buildSystem: data.buildSystem, + ) + let execPath = try fixturePath.appending( + components: data.buildSystem.binPath(for: data.config) + [executableName("TestableExe1")] + ) + expectFileExists(at: execPath) + try localFileSystem.removeFileTree(execPath) + let (stdout, stderr) = try await executeSwiftBuild( + fixturePath, + configuration: data.config, + buildSystem: data.buildSystem, + ) + #expect(!stdout.contains("replacing existing signature"), "log contained non-fatal codesigning messages stderr: '\(stderr)'") + #expect(!stderr.contains("replacing existing signature"), "log contained non-fatal codesigning messages. stdout: '\(stdout)'") + } + } when: { + ProcessInfo.hostOperatingSystem == .windows } } } diff --git a/Tests/CommandsTests/BuildCommandTests.swift b/Tests/CommandsTests/BuildCommandTests.swift index e47f1044cc7..6a6a1c6547f 100644 --- a/Tests/CommandsTests/BuildCommandTests.swift +++ b/Tests/CommandsTests/BuildCommandTests.swift @@ -52,7 +52,6 @@ struct SanitierTests { } @Suite( - .serialized, // to limit the number of swift executable running. .tags( Tag.TestSize.large, Tag.Feature.Command.Build, @@ -165,18 +164,11 @@ struct BuildCommandTestCases { // Test is not implemented for Xcode build system try await fixture(name: "ValidLayouts/SingleModule/ExecutableNew") { fixturePath in let fullPath = try resolveSymlinks(fixturePath) - - let rootScrathPath = fullPath.appending(component: ".build") - let targetPath: AbsolutePath - if buildSystem == .xcode { - targetPath = rootScrathPath - } else { - targetPath = try rootScrathPath.appending(component: UserToolchain.default.targetTriple.platformBuildPathComponent) - } + + let targetPath = try fullPath.appending(components: buildSystem.binPath(for: configuration)) let path = try await self.execute(["--show-bin-path"], packagePath: fullPath, configuration: configuration, buildSystem: buildSystem).stdout.trimmingCharacters(in: .whitespacesAndNewlines) #expect( - AbsolutePath(path).pathString == targetPath - .appending(components: buildSystem.binPathSuffixes(for: configuration)).pathString + AbsolutePath(path).pathString == targetPath.pathString ) } } @@ -288,29 +280,24 @@ struct BuildCommandTestCases { } @Test( - .SWBINTTODO("Test fails because of a difference in the build layout. This needs to be updated to the expected path"), - arguments: SupportedBuildSystemOnPlatform, BuildConfiguration.allCases + arguments: getBuildData(for: SupportedBuildSystemOnPlatform), ) func symlink( - buildSystem: BuildSystemProvider.Kind, - configuration: BuildConfiguration, + data: BuildData, ) async throws { - try await withKnownIssue { + let buildSystem = data.buildSystem + let configuration = data.config + try await withKnownIssue(isIntermittent: true) { try await fixture(name: "ValidLayouts/SingleModule/ExecutableNew") { fixturePath in let fullPath = try resolveSymlinks(fixturePath) - let targetPath = try fullPath.appending(components: - ".build", - UserToolchain.default.targetTriple.platformBuildPathComponent - ) // Test symlink. - let buildDir = fullPath.appending(components: ".build") try await self.execute(packagePath: fullPath, configuration: configuration, buildSystem: buildSystem) - let actualDebug = try resolveSymlinks(buildDir.appending(components: buildSystem.binPathSuffixes(for: configuration))) - let expectedDebug = targetPath.appending(components: buildSystem.binPathSuffixes(for: configuration)) + let actualDebug = try resolveSymlinks(fullPath.appending(components: buildSystem.binPath(for: configuration))) + let expectedDebug = try fullPath.appending(components: buildSystem.binPath(for: configuration)) #expect(actualDebug == expectedDebug) } } when: { - buildSystem != .native + ProcessInfo.hostOperatingSystem == .windows } } @@ -1125,10 +1112,9 @@ struct BuildCommandTestCases { return try SupportedBuildSystemOnPlatform.map { buildSystem in let triple = try UserToolchain.default.targetTriple.withoutVersion() let base = try RelativePath(validating: ".build") - let debugFolderComponents = buildSystem.binPathSuffixes(for: .debug) + let path = try base.appending(components: buildSystem.binPath(for: .debug, scratchPath: [])) switch buildSystem { case .xcode: - let path = base.appending(components: debugFolderComponents) return ( buildSystem, triple.platformName() == "macosx" ? path.appending("ExecutableNew") : path @@ -1137,8 +1123,6 @@ struct BuildCommandTestCases { .appending("\(triple).swiftsourceinfo") ) case .swiftbuild: - let path = base.appending(triple.tripleString) - .appending(components: debugFolderComponents) return ( buildSystem, triple.platformName() == "macosx" ? path.appending("ExecutableNew") : path @@ -1149,8 +1133,7 @@ struct BuildCommandTestCases { case .native: return ( buildSystem, - base.appending(components: debugFolderComponents) - .appending("ExecutableNew.build") + path.appending("ExecutableNew.build") .appending("main.swift.o") ) } diff --git a/Tests/CommandsTests/PackageCommandTests.swift b/Tests/CommandsTests/PackageCommandTests.swift index 492360468af..2e9f61dbfe1 100644 --- a/Tests/CommandsTests/PackageCommandTests.swift +++ b/Tests/CommandsTests/PackageCommandTests.swift @@ -2461,12 +2461,9 @@ struct PackageCommandTests { ) // Path to the executable. + let binPath = try fooPath.appending(components: data.buildSystem.binPath(for: data.config)) let exec = [ - fooPath.appending( - components: [ - ".build", try UserToolchain.default.targetTriple.platformBuildPathComponent, - ] + data.buildSystem.binPathSuffixes(for: data.config) + ["foo"] - ).pathString + binPath.appending("foo").pathString ] // We should see it now in packages directory. @@ -2602,10 +2599,8 @@ struct PackageCommandTests { buildSystem: data.buildSystem, ) let buildPath = packageRoot.appending(".build") - let binFile = buildPath.appending( - components: [try UserToolchain.default.targetTriple.platformBuildPathComponent] - + data.buildSystem.binPathSuffixes(for: data.config) + [executableName("Bar")] - ) + let binPath = try buildPath.appending(components: data.buildSystem.binPath(for: data.config, scratchPath: [])) + let binFile = binPath.appending(executableName("Bar")) expectFileExists(at: binFile) #expect(localFileSystem.isDirectory(buildPath)) @@ -2653,10 +2648,8 @@ struct PackageCommandTests { buildSystem: data.buildSystem ) let buildPath = packageRoot.appending(".build") - let binFile = buildPath.appending( - components: [try UserToolchain.default.targetTriple.platformBuildPathComponent] - + data.buildSystem.binPathSuffixes(for: data.config) + [executableName("Bar")] - ) + let binPath = try buildPath.appending(components: data.buildSystem.binPath(for: data.config, scratchPath: [], )) + let binFile = binPath.appending(executableName("Bar")) expectFileExists(at: binFile) #expect(localFileSystem.isDirectory(buildPath)) // Clean, and check for removal of the build directory but not Packages. @@ -2782,15 +2775,9 @@ struct PackageCommandTests { try await withKnownIssue(isIntermittent: (ProcessInfo.hostOperatingSystem == .linux)) { try await fixture(name: "Miscellaneous/PackageEdit") { fixturePath in let fooPath = fixturePath.appending("foo") + let binPath = try fooPath.appending(components: data.buildSystem.binPath(for: data.config)) let exec = [ - fooPath.appending( - components: [ - ".build", - try UserToolchain.default.targetTriple.platformBuildPathComponent, - ] + data.buildSystem.binPathSuffixes(for: data.config) + [ - "foo" - ] - ).pathString + binPath.appending("foo").pathString ] // Build and check. @@ -5015,15 +5002,8 @@ struct PackageCommandTests { func commandPluginTargetBuilds_BinaryIsBuildinDebugByDefault( buildData: BuildData, ) async throws { - let tripleString = try UserToolchain.default.targetTriple.platformBuildPathComponent - let debugTarget = - [".build", tripleString] + buildData.buildSystem.binPathSuffixes(for: .debug) + [ - executableName("placeholder") - ] - let releaseTarget = - [".build", tripleString] + buildData.buildSystem.binPathSuffixes(for: .release) + [ - executableName("placeholder") - ] + let debugTarget = try buildData.buildSystem.binPath(for: .debug) + [executableName("placeholder")] + let releaseTarget = try buildData.buildSystem.binPath(for: .release) + [executableName("placeholder")] try await withKnownIssue { // By default, a plugin-requested build produces a debug binary try await fixture(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in @@ -5053,15 +5033,8 @@ struct PackageCommandTests { func commandPluginTargetBuilds_BinaryWillBeBuiltInDebugIfPluginSpecifiesDebugBuild( buildData: BuildData, ) async throws { - let tripleString = try UserToolchain.default.targetTriple.platformBuildPathComponent - let debugTarget = - [".build", tripleString] + buildData.buildSystem.binPathSuffixes(for: .debug) + [ - executableName("placeholder") - ] - let releaseTarget = - [".build", tripleString] + buildData.buildSystem.binPathSuffixes(for: .release) + [ - executableName("placeholder") - ] + let debugTarget = try buildData.buildSystem.binPath(for: .debug) + [executableName("placeholder")] + let releaseTarget = try buildData.buildSystem.binPath(for: .release) + [executableName("placeholder")] try await withKnownIssue { // If the plugin specifies a debug binary, that is what will be built, regardless of overall configuration try await fixture(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in @@ -5095,17 +5068,9 @@ struct PackageCommandTests { func commandPluginTargetBuilds_BinaryWillBeBuiltInReleaseIfPluginSpecifiesReleaseBuild( buildData: BuildData, ) async throws { - let tripleString = try UserToolchain.default.targetTriple.platformBuildPathComponent - let debugTarget = - [".build", tripleString] + buildData.buildSystem.binPathSuffixes(for: .debug) + [ - executableName("placeholder") - ] - let releaseTarget = - [".build", tripleString] + buildData.buildSystem.binPathSuffixes(for: .release) + [ - executableName("placeholder") - ] + let debugTarget = try buildData.buildSystem.binPath(for: .debug) + [executableName("placeholder")] + let releaseTarget = try buildData.buildSystem.binPath(for: .release) + [executableName("placeholder")] try await withKnownIssue { - // If the plugin requests a release binary, that is what will be built, regardless of overall configuration try await fixture(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in let _ = try await execute( @@ -5137,15 +5102,8 @@ struct PackageCommandTests { func commandPluginTargetBuilds_BinaryWillBeBuiltCorrectlyIfPluginSpecifiesInheritBuild( buildData: BuildData, ) async throws { - let tripleString = try UserToolchain.default.targetTriple.platformBuildPathComponent - let debugTarget = - [".build", tripleString] + buildData.buildSystem.binPathSuffixes(for: .debug) + [ - executableName("placeholder") - ] - let releaseTarget = - [".build", tripleString] + buildData.buildSystem.binPathSuffixes(for: .release) + [ - executableName("placeholder") - ] + let debugTarget = try buildData.buildSystem.binPath(for: .debug) + [executableName("placeholder")] + let releaseTarget = try buildData.buildSystem.binPath(for: .release) + [executableName("placeholder")] try await withKnownIssue { // If the plugin inherits the overall build configuration, that is what will be built try await fixture(name: "Miscellaneous/Plugins/CommandPluginTestStub") { fixturePath in @@ -5246,7 +5204,7 @@ struct PackageCommandTests { } } when: { ProcessInfo.hostOperatingSystem == .windows - || (ProcessInfo.hostOperatingSystem == .linux && data.buildSystem == .swiftbuild) + || (ProcessInfo.hostOperatingSystem == .linux && data.buildSystem == .swiftbuild) } } @@ -5491,6 +5449,9 @@ struct PackageCommandTests { .tags( .Feature.Command.Package.CommandPlugin, ), + .IssueWindowsRelativePathAssert, + .IssueWindowsLongPath, + .IssueWindowsPathLastConponent, arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms), Self.getCommandPluginNetworkingPermissionTestData() ) @@ -5498,57 +5459,61 @@ struct PackageCommandTests { buildData: BuildData, testData: CommandPluginNetworkingPermissionsTestData, ) async throws { - try await testWithTemporaryDirectory { tmpPath in - // Create a sample package with a library target and a plugin. - let packageDir = tmpPath.appending(components: "MyPackage") - try localFileSystem.writeFileContents( - packageDir.appending(components: "Package.swift"), - string: - """ - // swift-tools-version: 5.9 - import PackageDescription - let package = Package( - name: "MyPackage", - targets: [ - .target(name: "MyLibrary"), - .plugin(name: "MyPlugin", capability: .command(intent: .custom(verb: "Network", description: "Help description"), permissions: \(testData.permissionsManifestFragment))), - ] - ) - """ - ) - try localFileSystem.writeFileContents( - packageDir.appending(components: "Sources", "MyLibrary", "library.swift"), - string: "public func Foo() { }" - ) - try localFileSystem.writeFileContents( - packageDir.appending(components: "Plugins", "MyPlugin", "plugin.swift"), - string: - """ - import PackagePlugin + try await withKnownIssue(isIntermittent: true) { + try await testWithTemporaryDirectory { tmpPath in + // Create a sample package with a library target and a plugin. + let packageDir = tmpPath.appending(components: "MyPackage") + try localFileSystem.writeFileContents( + packageDir.appending(components: "Package.swift"), + string: + """ + // swift-tools-version: 5.9 + import PackageDescription + let package = Package( + name: "MyPackage", + targets: [ + .target(name: "MyLibrary"), + .plugin(name: "MyPlugin", capability: .command(intent: .custom(verb: "Network", description: "Help description"), permissions: \(testData.permissionsManifestFragment))), + ] + ) + """ + ) + try localFileSystem.writeFileContents( + packageDir.appending(components: "Sources", "MyLibrary", "library.swift"), + string: "public func Foo() { }" + ) + try localFileSystem.writeFileContents( + packageDir.appending(components: "Plugins", "MyPlugin", "plugin.swift"), + string: + """ + import PackagePlugin - @main - struct MyCommandPlugin: CommandPlugin { - func performCommand(context: PluginContext, arguments: [String]) throws { - print("hello world") + @main + struct MyCommandPlugin: CommandPlugin { + func performCommand(context: PluginContext, arguments: [String]) throws { + print("hello world") + } } - } - """ - ) - - // Check that we don't get an error (and also are allowed to write to the package directory) if we pass `--allow-writing-to-package-directory`. - do { - let (stdout, _) = try await execute( - ["plugin"] + testData.remedy + ["Network"], - packagePath: packageDir, - configuration: buildData.config, - buildSystem: buildData.buildSystem, + """ ) - withKnownIssue(isIntermittent: true) { - #expect(stdout.contains("hello world")) - } when: { - ProcessInfo.hostOperatingSystem == .windows && buildData.buildSystem == .swiftbuild && buildData.config == .debug && testData.permissionError == Self.allNetworkConnectionPermissionError + + // Check that we don't get an error (and also are allowed to write to the package directory) if we pass `--allow-writing-to-package-directory`. + do { + let (stdout, _) = try await execute( + ["plugin"] + testData.remedy + ["Network"], + packagePath: packageDir, + configuration: buildData.config, + buildSystem: buildData.buildSystem, + ) + withKnownIssue(isIntermittent: true) { + #expect(stdout.contains("hello world")) + } when: { + ProcessInfo.hostOperatingSystem == .windows && buildData.buildSystem == .swiftbuild && buildData.config == .debug && testData.permissionError == Self.allNetworkConnectionPermissionError + } } } + } when: { + ProcessInfo.hostOperatingSystem == .windows } } @@ -6802,7 +6767,7 @@ struct PackageCommandTests { } #expect(stdout.contains("Building for \(data.config.buildFor)...")) } - } when : { + } when: { ProcessInfo.hostOperatingSystem == .windows && data.buildSystem == .swiftbuild } diff --git a/Tests/FunctionalTests/CFamilyTargetTests.swift b/Tests/FunctionalTests/CFamilyTargetTests.swift index a3f9d15d223..55bbd26beb7 100644 --- a/Tests/FunctionalTests/CFamilyTargetTests.swift +++ b/Tests/FunctionalTests/CFamilyTargetTests.swift @@ -2,13 +2,14 @@ // // This source file is part of the Swift open source project // -// Copyright (c) 2014-2024 Apple Inc. and the Swift project authors +// Copyright (c) 2014-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 Foundation import Basics import Commands @@ -18,98 +19,215 @@ import PackageModel import SourceControl import _InternalTestSupport import Workspace -import XCTest +import Testing import class Basics.AsyncProcess -/// Asserts if a directory (recursively) contains a file. -private func XCTAssertDirectoryContainsFile(dir: AbsolutePath, filename: String, file: StaticString = #file, line: UInt = #line) { +/// Expects a directory (recursively) contains a file. +fileprivate func expectDirectoryContainsFile( + dir: AbsolutePath, + filename: String, + sourceLocation: SourceLocation = #_sourceLocation, +) { do { for entry in try walk(dir) { if entry.basename == filename { return } } } catch { - XCTFail("Failed with error \(error)", file: file, line: line) + Issue.record("Failed with error \(error)", sourceLocation: sourceLocation) } - XCTFail("Directory \(dir) does not contain \(file)", file: file, line: line) + Issue.record("Directory \(dir) does not contain \(filename)", sourceLocation: sourceLocation) } -final class CFamilyTargetTestCase: XCTestCase { - func testCLibraryWithSpaces() async throws { - try await fixtureXCTest(name: "CFamilyTargets/CLibraryWithSpaces") { fixturePath in - await XCTAssertBuilds(fixturePath, buildSystem: .native) - let debugPath = fixturePath.appending(components: ".build", try UserToolchain.default.targetTriple.platformBuildPathComponent, "debug") - XCTAssertDirectoryContainsFile(dir: debugPath, filename: "Bar.c.o") - XCTAssertDirectoryContainsFile(dir: debugPath, filename: "Foo.c.o") +@Suite( + .tags( + .TestSize.large, + ), +) +struct CFamilyTargetTestCase { + @Test( + .issue("https://github.com/swiftlang/swift-build/issues/333", relationship: .defect), + .tags( + .Feature.Command.Build, + ), + arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms), + ) + func cLibraryWithSpaces( + data: BuildData, + ) async throws { + try await withKnownIssue(isIntermittent: true) { + try await fixture(name: "CFamilyTargets/CLibraryWithSpaces") { fixturePath in + try await executeSwiftBuild( + fixturePath, + configuration: data.config, + buildSystem: data.buildSystem, + ) + if data.buildSystem == .native { + let binPath = try fixturePath.appending(components: data.buildSystem.binPath(for: data.config)) + expectDirectoryContainsFile(dir: binPath, filename: "Bar.c.o") + expectDirectoryContainsFile(dir: binPath, filename: "Foo.c.o") + } + } + } when: { + data.buildSystem == .swiftbuild } } - func testCUsingCAndSwiftDep() async throws { - try await fixtureXCTest(name: "DependencyResolution/External/CUsingCDep") { fixturePath in + @Test( + .tags( + .Feature.Command.Build, + ), + arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms), + ) + func cUsingCAndSwiftDep( + data: BuildData, + ) async throws { + try await fixture(name: "DependencyResolution/External/CUsingCDep") { fixturePath in let packageRoot = fixturePath.appending("Bar") - await XCTAssertBuilds(packageRoot, buildSystem: .native) - let debugPath = fixturePath.appending(components: "Bar", ".build", try UserToolchain.default.targetTriple.platformBuildPathComponent, "debug") - XCTAssertDirectoryContainsFile(dir: debugPath, filename: "Sea.c.o") - XCTAssertDirectoryContainsFile(dir: debugPath, filename: "Foo.c.o") + try await executeSwiftBuild( + packageRoot, + configuration: data.config, + buildSystem: data.buildSystem, + ) + if data.buildSystem == .native { + let binPath = try packageRoot.appending(components: data.buildSystem.binPath(for: data.config)) + expectDirectoryContainsFile(dir: binPath, filename: "Sea.c.o") + expectDirectoryContainsFile(dir: binPath, filename: "Foo.c.o") + } let path = try SwiftPM.packagePath(for: "Foo", packageRoot: packageRoot) - XCTAssertEqual(try GitRepository(path: path).getTags(), ["1.2.3"]) + let actualTags = try GitRepository(path: path).getTags() + #expect(actualTags == ["1.2.3"]) } } - func testModuleMapGenerationCases() async throws { - try await fixtureXCTest(name: "CFamilyTargets/ModuleMapGenerationCases") { fixturePath in - await XCTAssertBuilds(fixturePath, buildSystem: .native) - let debugPath = fixturePath.appending(components: ".build", try UserToolchain.default.targetTriple.platformBuildPathComponent, "debug") - XCTAssertDirectoryContainsFile(dir: debugPath, filename: "Jaz.c.o") - XCTAssertDirectoryContainsFile(dir: debugPath, filename: "main.swift.o") - XCTAssertDirectoryContainsFile(dir: debugPath, filename: "FlatInclude.c.o") - XCTAssertDirectoryContainsFile(dir: debugPath, filename: "UmbrellaHeader.c.o") + @Test( + .tags( + .Feature.Command.Build, + ), + arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms), + ) + func moduleMapGenerationCases( + data: BuildData, + ) async throws { + try await fixture(name: "CFamilyTargets/ModuleMapGenerationCases") { fixturePath in + try await executeSwiftBuild( + fixturePath, + configuration: data.config, + buildSystem: data.buildSystem, + ) + if data.buildSystem == .native { + let binPath = try fixturePath.appending(components: data.buildSystem.binPath(for: data.config)) + expectDirectoryContainsFile(dir: binPath, filename: "Jaz.c.o") + expectDirectoryContainsFile(dir: binPath, filename: "main.swift.o") + expectDirectoryContainsFile(dir: binPath, filename: "FlatInclude.c.o") + expectDirectoryContainsFile(dir: binPath, filename: "UmbrellaHeader.c.o") + } } } - - func testNoIncludeDirCheck() async throws { - try await fixtureXCTest(name: "CFamilyTargets/CLibraryNoIncludeDir") { fixturePath in - await XCTAssertAsyncThrowsError( + + @Test( + .tags( + .Feature.Command.Build, + ), + arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms), + ) + func noIncludeDirCheck( + data: BuildData, + ) async throws { + try await fixture(name: "CFamilyTargets/CLibraryNoIncludeDir") { fixturePath in + let error = try await #require(throws: (any Error).self) { try await executeSwiftBuild( fixturePath, - buildSystem: .native, - ), - "This build should throw an error", - ) { err in - // The err.localizedDescription doesn't capture the detailed error string so interpolate - let errStr = "\(err)" - let missingIncludeDirStr = "\(ModuleError.invalidPublicHeadersDirectory("Cfactorial"))" - XCTAssert(errStr.contains(missingIncludeDirStr)) + configuration: data.config, + buildSystem: data.buildSystem, + ) } + + let errString = "\(error)" + let missingIncludeDirStr = "\(ModuleError.invalidPublicHeadersDirectory("Cfactorial"))" + #expect(errString.contains(missingIncludeDirStr)) } } - func testCanForwardExtraFlagsToClang() async throws { - // Try building a fixture which needs extra flags to be able to build. - try await fixtureXCTest(name: "CFamilyTargets/CDynamicLookup") { fixturePath in - await XCTAssertBuilds(fixturePath, Xld: ["-undefined", "dynamic_lookup"], buildSystem: .native) - let debugPath = fixturePath.appending(components: ".build", try UserToolchain.default.targetTriple.platformBuildPathComponent, "debug") - XCTAssertDirectoryContainsFile(dir: debugPath, filename: "Foo.c.o") + @Test( + .tags( + .Feature.Command.Build, + ), + arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms), + ) + func canForwardExtraFlagsToClang( + data: BuildData, + + ) async throws { + try await fixture(name: "CFamilyTargets/CDynamicLookup") { fixturePath in + try await executeSwiftBuild( + fixturePath, + configuration: data.config, + Xld: ["-undefined", "dynamic_lookup"], + buildSystem: data.buildSystem, + ) + if data.buildSystem == .native { + let binPath = try fixturePath.appending(components: data.buildSystem.binPath(for: data.config)) + expectDirectoryContainsFile(dir: binPath, filename: "Foo.c.o") + } } } - func testObjectiveCPackageWithTestTarget() async throws { - #if !os(macOS) - try XCTSkipIf(true, "test is only supported on macOS") - #endif - try await fixtureXCTest(name: "CFamilyTargets/ObjCmacOSPackage") { fixturePath in + @Test( + .tags( + .Feature.Command.Build, + .Feature.Command.Test, + ), + .requireHostOS(.macOS), + arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms), + + ) + func objectiveCPackageWithTestTarget( + data: BuildData, + + ) async throws { + try await fixture(name: "CFamilyTargets/ObjCmacOSPackage") { fixturePath in // Build the package. - await XCTAssertBuilds(fixturePath, buildSystem: .native) - XCTAssertDirectoryContainsFile(dir: fixturePath.appending(components: ".build", try UserToolchain.default.targetTriple.platformBuildPathComponent, "debug"), filename: "HelloWorldExample.m.o") + try await executeSwiftBuild( + fixturePath, + configuration: data.config, + buildSystem: data.buildSystem, + ) + if data.buildSystem == .native { + let binPath = try fixturePath.appending(components: data.buildSystem.binPath(for: data.config)) + expectDirectoryContainsFile(dir: binPath, filename: "HelloWorldExample.m.o") + expectDirectoryContainsFile(dir: binPath, filename: "HelloWorldExample.m.o") + } // Run swift-test on package. - await XCTAssertSwiftTest(fixturePath, buildSystem: .native) + try await executeSwiftTest( + fixturePath, + configuration: data.config, + buildSystem: data.buildSystem, + ) + } } - - func testCanBuildRelativeHeaderSearchPaths() async throws { - try await fixtureXCTest(name: "CFamilyTargets/CLibraryParentSearchPath") { fixturePath in - await XCTAssertBuilds(fixturePath, buildSystem: .native) - XCTAssertDirectoryContainsFile(dir: fixturePath.appending(components: ".build", try UserToolchain.default.targetTriple.platformBuildPathComponent, "debug"), filename: "HeaderInclude.swiftmodule") + + @Test( + .tags( + .Feature.Command.Build, + ), + arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms), + ) + func canBuildRelativeHeaderSearchPaths( + data: BuildData, + + ) async throws { + try await fixture(name: "CFamilyTargets/CLibraryParentSearchPath") { fixturePath in + try await executeSwiftBuild( + fixturePath, + configuration: data.config, + buildSystem: data.buildSystem, + ) + if data.buildSystem == .native { + let binPath = try fixturePath.appending(components: data.buildSystem.binPath(for: data.config)) + expectDirectoryContainsFile(dir: binPath, filename: "HeaderInclude.swiftmodule") + } } } } diff --git a/Tests/FunctionalTests/DependencyResolutionTests.swift b/Tests/FunctionalTests/DependencyResolutionTests.swift index 37e9842f8f2..32823fa2307 100644 --- a/Tests/FunctionalTests/DependencyResolutionTests.swift +++ b/Tests/FunctionalTests/DependencyResolutionTests.swift @@ -50,10 +50,8 @@ struct DependencyResolutionTests { buildSystem: buildSystem, ) - let executablePath = try fixturePath.appending( - components: [".build", UserToolchain.default.targetTriple.platformBuildPathComponent] - + buildSystem.binPathSuffixes(for: configuration) + ["Foo"] - ) + let binPath = try fixturePath.appending(components: buildSystem.binPath(for: configuration)) + let executablePath = binPath.appending(components: "Foo") let output = try await AsyncProcess.checkNonZeroExit(args: executablePath.pathString).withSwiftLineEnding #expect(output == "Foo\nBar\n") } @@ -111,10 +109,8 @@ struct DependencyResolutionTests { buildSystem: buildSystem, ) - let executablePath = try fixturePath.appending( - components: [".build", UserToolchain.default.targetTriple.platformBuildPathComponent] - + buildSystem.binPathSuffixes(for: configuration) + ["Foo"] - ) + let binPath = try fixturePath.appending(components: buildSystem.binPath(for: configuration)) + let executablePath = binPath.appending(components: "Foo") let output = try await AsyncProcess.checkNonZeroExit(args: executablePath.pathString) .withSwiftLineEnding #expect(output == "meiow Baz\n") @@ -152,12 +148,8 @@ struct DependencyResolutionTests { configuration: configuration, buildSystem: buildSystem, ) - let executablePath = packageRoot.appending( - components: [ - ".build", - try UserToolchain.default.targetTriple.platformBuildPathComponent, - ] + buildSystem.binPathSuffixes(for: configuration) + [executableName("Bar")] - ) + let binPath = try packageRoot.appending(components: buildSystem.binPath(for: configuration)) + let executablePath = binPath.appending(components: executableName("Bar")) #expect( localFileSystem.exists(executablePath), "Path \(executablePath) does not exist", @@ -185,22 +177,22 @@ struct DependencyResolutionTests { ) async throws { try await withKnownIssue(isIntermittent: ProcessInfo.hostOperatingSystem == .windows){ try await fixture(name: "DependencyResolution/External/Complex") { fixturePath in + let packageRoot = fixturePath.appending("app") try await executeSwiftBuild( - fixturePath.appending("app"), + packageRoot, configuration: configuration, buildSystem: buildSystem, ) - let executablePath = try fixturePath.appending( - components: [ - "app", ".build", UserToolchain.default.targetTriple.platformBuildPathComponent, - ] + buildSystem.binPathSuffixes(for: configuration) + ["Dealer"] - ) + let binPath = try packageRoot.appending(components: buildSystem.binPath(for: configuration)) + let executablePath = binPath.appending(components: "Dealer") + expectFileExists(at: executablePath) let output = try await AsyncProcess.checkNonZeroExit(args: executablePath.pathString) .withSwiftLineEnding #expect(output == "♣︎K\n♣︎Q\n♣︎J\n♣︎10\n♣︎9\n♣︎8\n♣︎7\n♣︎6\n♣︎5\n♣︎4\n") } } when: { - [.linux, .windows].contains(ProcessInfo.hostOperatingSystem) && buildSystem == .swiftbuild + ([.linux, .windows].contains(ProcessInfo.hostOperatingSystem) && buildSystem == .swiftbuild) + || (ProcessInfo.hostOperatingSystem == .windows) // due to long path isues } } diff --git a/Tests/FunctionalTests/ModuleAliasingFixtureTests.swift b/Tests/FunctionalTests/ModuleAliasingFixtureTests.swift index 88bb27b6e6a..bdefcfe9fcf 100644 --- a/Tests/FunctionalTests/ModuleAliasingFixtureTests.swift +++ b/Tests/FunctionalTests/ModuleAliasingFixtureTests.swift @@ -39,7 +39,7 @@ struct ModuleAliasingFixtureTests { try await withKnownIssue(isIntermittent: true) { try await fixture(name: "ModuleAliasing/DirectDeps1") { fixturePath in let pkgPath = fixturePath.appending(components: "AppPkg") - let buildPath = pkgPath.appending(components: [".build", try UserToolchain.default.targetTriple.platformBuildPathComponent] + buildSystem.binPathSuffixes(for: configuration)) + let buildPath = try pkgPath.appending(components: buildSystem.binPath(for: configuration)) try await executeSwiftBuild( pkgPath, configuration: configuration, @@ -82,7 +82,7 @@ struct ModuleAliasingFixtureTests { try await withKnownIssue { try await fixture(name: "ModuleAliasing/DirectDeps2") { fixturePath in let pkgPath = fixturePath.appending(components: "AppPkg") - let buildPath = pkgPath.appending(components: [".build", try UserToolchain.default.targetTriple.platformBuildPathComponent] + buildSystem.binPathSuffixes(for: configuration)) + let buildPath = try pkgPath.appending(components: buildSystem.binPath(for: configuration)) try await executeSwiftBuild( pkgPath, configuration: configuration, @@ -117,7 +117,7 @@ struct ModuleAliasingFixtureTests { try await withKnownIssue { try await fixture(name: "ModuleAliasing/NestedDeps1") { fixturePath in let pkgPath = fixturePath.appending(components: "AppPkg") - let buildPath = pkgPath.appending(components: [".build", try UserToolchain.default.targetTriple.platformBuildPathComponent] + buildSystem.binPathSuffixes(for: configuration)) + let buildPath = try pkgPath.appending(components: buildSystem.binPath(for: configuration)) try await executeSwiftBuild( pkgPath, configuration: configuration, @@ -156,7 +156,7 @@ struct ModuleAliasingFixtureTests { try await withKnownIssue { try await fixture(name: "ModuleAliasing/NestedDeps2") { fixturePath in let pkgPath = fixturePath.appending(components: "AppPkg") - let buildPath = pkgPath.appending(components: [".build", try UserToolchain.default.targetTriple.platformBuildPathComponent] + buildSystem.binPathSuffixes(for: configuration)) + let buildPath = try pkgPath.appending(components: buildSystem.binPath(for: configuration)) try await executeSwiftBuild( pkgPath, configuration: configuration, diff --git a/Tests/FunctionalTests/ToolsVersionTests.swift b/Tests/FunctionalTests/ToolsVersionTests.swift index 8d611e0f22a..6bc5d00f677 100644 --- a/Tests/FunctionalTests/ToolsVersionTests.swift +++ b/Tests/FunctionalTests/ToolsVersionTests.swift @@ -124,7 +124,8 @@ struct ToolsVersionTests { configuration: configuration, buildSystem: buildSystem, ) - let exe: String = primaryPath.appending(components: [".build", try UserToolchain.default.targetTriple.platformBuildPathComponent] + buildSystem.binPathSuffixes(for: configuration) + ["Primary"]).pathString + let binPath = try primaryPath.appending(components: buildSystem.binPath(for: configuration)) + let exe: String = binPath.appending(components: "Primary").pathString // v1 should get selected because v1.0.1 depends on a (way) higher set of tools. try await withKnownIssue { let executableActualOutput = try await AsyncProcess.checkNonZeroExit(args: exe).spm_chomp()