Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Sources/_InternalTestSupport/SwiftTesting+TraitsBug.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ extension Trait where Self == Testing.Bug {
)
}

public static var IssueWindowsCannotSaveAttachment: Self {
// error: unable to write file 'C:\Users\ContainerAdministrator\AppData\Local\Temp\CFamilyTargets_CDynamicLookup.hNxGHC\CFamilyTargets_CDynamicLookup\.build\x86_64-unknown-windows-msvc\Intermediates.noindex\CDynamicLookup.build\Release-windows\CDynamicLookup.build\Objects-normal\x86_64\CDynamicLookup.LinkFileList': No such file or directory (2)
.issue(
"https://github.com/swiftlang/swift-foundation/issues/1486",
relationship: .defect,
)
}

public static var IssueProductTypeForObjectLibraries: Self {
.issue(
"https://github.com/swiftlang/swift-build/issues/609",
Expand Down
271 changes: 210 additions & 61 deletions Tests/FunctionalTests/CFamilyTargetTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -18,98 +19,246 @@ 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
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")
let path = try SwiftPM.packagePath(for: "Foo", packageRoot: packageRoot)
XCTAssertEqual(try GitRepository(path: path).getTags(), ["1.2.3"])
@Test(
.tags(
.Feature.Command.Build,
),
.IssueWindowsLongPath,
.IssueWindowsPathLastConponent,
.IssueWindowsRelativePathAssert,
.IssueWindowsCannotSaveAttachment,
arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms),
)
func cUsingCAndSwiftDep(
data: BuildData,
) async throws {
try await withKnownIssue(isIntermittent: true) {
try await fixture(name: "DependencyResolution/External/CUsingCDep") { fixturePath in
let packageRoot = fixturePath.appending("Bar")
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)
let actualTags = try GitRepository(path: path).getTags()
#expect(actualTags == ["1.2.3"])
}
} when: {
ProcessInfo.hostOperatingSystem == .windows && data.buildSystem == .swiftbuild
}
}

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,
),
.IssueWindowsLongPath,
.IssueWindowsPathLastConponent,
.IssueWindowsRelativePathAssert,
.IssueWindowsCannotSaveAttachment,
arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms),
)
func moduleMapGenerationCases(
data: BuildData,
) async throws {
try await withKnownIssue(isIntermittent: true) {
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")
}
}
} when: {
ProcessInfo.hostOperatingSystem == .windows && data.buildSystem == .swiftbuild
}
}

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,
),
.IssueWindowsLongPath,
.IssueWindowsPathLastConponent,
.IssueWindowsRelativePathAssert,
.IssueWindowsCannotSaveAttachment,
arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms),
)
func canForwardExtraFlagsToClang(
data: BuildData,
) async throws {
try await withKnownIssue(isIntermittent: true) {
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")
}
}
} when: {
ProcessInfo.hostOperatingSystem == .windows && data.buildSystem == .swiftbuild
}
}

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,
),
.IssueWindowsLongPath,
.IssueWindowsPathLastConponent,
.IssueWindowsRelativePathAssert,
.IssueWindowsCannotSaveAttachment,
arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms),
)
func canBuildRelativeHeaderSearchPaths(
data: BuildData,

) async throws {
try await withKnownIssue(isIntermittent: true) {
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")
}
}
} when: {
ProcessInfo.hostOperatingSystem == .windows && data.buildSystem == .swiftbuild
}
}
}