Skip to content
Draft
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
31 changes: 25 additions & 6 deletions Sources/_InternalTestSupport/SwiftTesting+Helpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@
import Basics
import Testing

public func expectFileExists(
at path: AbsolutePath,
_ comment: Comment? = nil,
sourceLocation: SourceLocation = #_sourceLocation,
) {
private func fileExistsErrorMessage(
for path: AbsolutePath,
comment: Comment?
) -> Comment {
let commentPrefix =
if let comment {
"\(comment): "
Expand All @@ -30,9 +29,29 @@ public func expectFileExists(
} catch {
msgSuffix = ""
}
return Comment("\(commentPrefix)File '\(path)' does not exist. \(msgSuffix)")
}

public func expectFileExists(
at path: AbsolutePath,
_ comment: Comment? = nil,
sourceLocation: SourceLocation = #_sourceLocation,
) {
#expect(
localFileSystem.exists(path),
"\(commentPrefix)File '\(path)' does not exist. \(msgSuffix)",
fileExistsErrorMessage(for: path, comment: comment),
sourceLocation: sourceLocation,
)
}

public func requireFileExists(
at path: AbsolutePath,
_ comment: Comment? = nil,
sourceLocation: SourceLocation = #_sourceLocation,
) throws {
try #require(
localFileSystem.exists(path),
fileExistsErrorMessage(for: path, comment: comment),
sourceLocation: sourceLocation,
)
}
Expand Down
4 changes: 4 additions & 0 deletions Sources/_InternalTestSupport/SwiftTesting+Tags.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ extension Tag.FunctionalArea {
@Tag public static var IndexMode: Tag
@Tag public static var Sanitizer: Tag
@Tag public static var LinkSwiftStaticStdlib: Tag
@Tag public static var Metal: Tag
@Tag public static var ModuleMaps: Tag
@Tag public static var Resources: Tag
@Tag public static var Workspace: Tag
}

extension Tag.Feature {
Expand Down
34 changes: 22 additions & 12 deletions Tests/BuildMetalTests/BuildMetalTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,33 @@ import _InternalTestSupport
import Testing
import Basics
import Foundation
import struct SPMBuildCore.BuildSystemProvider
import enum PackageModel.BuildConfiguration
#if os(macOS)
import Metal
#endif

@Suite
@Suite(
.tags(
.FunctionalArea.Metal,
)
)
struct BuildMetalTests {

#if os(macOS)
@Test(
.disabled("Require downloadable Metal toolchain"),
.tags(.TestSize.large),
.tags(
.TestSize.large,
),
.requireHostOS(.macOS),
arguments: getBuildData(for: [.swiftbuild])
arguments: BuildConfiguration.allCases,
)
func simpleLibrary(data: BuildData) async throws {
let buildSystem = data.buildSystem
let configuration = data.config

func simpleLibrary(
config: BuildConfiguration,
) async throws {
let buildSystem = BuildSystemProvider.Kind.swiftbuild
let configuration = config

try await fixture(name: "Metal/SimpleLibrary") { fixturePath in

// Build the package
Expand All @@ -41,7 +50,7 @@ struct BuildMetalTests {
buildSystem: buildSystem,
throwIfCommandFails: true
)

// Get the bin path
let (binPathOutput, _) = try await executeSwiftBuild(
fixturePath,
Expand All @@ -50,22 +59,23 @@ struct BuildMetalTests {
buildSystem: buildSystem,
throwIfCommandFails: true
)

let binPath = try AbsolutePath(validating: binPathOutput.trimmingCharacters(in: .whitespacesAndNewlines))

// Check that default.metallib exists
let metallibPath = binPath.appending(components:["MyRenderer_MyRenderer.bundle", "Contents", "Resources", "default.metallib"])
#expect(
localFileSystem.exists(metallibPath),
"Expected default.metallib to exist at \(metallibPath)"
)

#if os(macOS)
// Verify we can load the metal library
let device = try #require(MTLCreateSystemDefaultDevice())
let library = try device.makeLibrary(URL: URL(fileURLWithPath: metallibPath.pathString))

#expect(library.functionNames.contains("simpleVertexShader"))
#endif
}
}
#endif
}
121 changes: 80 additions & 41 deletions Tests/FunctionalTests/ModuleMapTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,45 @@
//
// 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-2026 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
import PackageModel
import _InternalTestSupport
import Workspace
import XCTest
import Testing

import struct SPMBuildCore.BuildSystemProvider

final class ModuleMapsTestCase: XCTestCase {
private func fixtureXCTest(
@Suite(
.serialized, // crash occurs when executed in parallel. needs investigation
.tags(
.FunctionalArea.ModuleMaps,
),
)
struct ModuleMapsTestCase {
private func localFixture(
name: String,
cModuleName: String,
rootpkg: String,
buildSystem: BuildSystemProvider.Kind,
config: BuildConfiguration,
body: @escaping (AbsolutePath, [String]) async throws -> Void
) async throws {
try await _InternalTestSupport.fixtureXCTest(name: name) { fixturePath in
try await fixture(name: name) { fixturePath in
let input = fixturePath.appending(components: cModuleName, "C", "foo.c")
let triple = try UserToolchain.default.targetTriple
let outdir = fixturePath.appending(components: rootpkg, ".build", triple.platformBuildPathComponent, "debug")
let outdir = try fixturePath.appending(components: [rootpkg] + buildSystem.binPath(for: config))
try makeDirectories(outdir)
let triple = try UserToolchain.default.targetTriple
let output = outdir.appending("libfoo\(triple.dynamicLibraryExtension)")
try await AsyncProcess.checkNonZeroExit(args: executableName("clang"), "-shared", input.pathString, "-o", output.pathString)

Expand All @@ -41,53 +53,80 @@ final class ModuleMapsTestCase: XCTestCase {
}
}

func testDirectDependency() async throws {
try XCTSkipOnWindows(because: "fails to build on windows (maybe not supported?)")
try await fixtureXCTest(name: "ModuleMaps/Direct", cModuleName: "CFoo", rootpkg: "App") { fixturePath, Xld in
await XCTAssertBuilds(
fixturePath.appending("App"),
Xld: Xld,
buildSystem: .native,
)
@Test(
arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms),
)
func directDependency(
buildData: BuildData,
) async throws {
let configuration = buildData.config
let buildSystem = buildData.buildSystem
try await withKnownIssue(isIntermittent: true) {
try await localFixture(
name: "ModuleMaps/Direct",
cModuleName: "CFoo",
rootpkg: "App",
buildSystem: buildSystem,
config: configuration,
) { fixturePath, Xld in
try await executeSwiftBuild(
fixturePath.appending("App"),
configuration: configuration,
Xld: Xld,
buildSystem: buildSystem,
)

let triple = try UserToolchain.default.targetTriple
let targetPath = fixturePath.appending(components: "App", ".build", triple.platformBuildPathComponent)
let debugout = try await AsyncProcess.checkNonZeroExit(
args: targetPath.appending(components: "debug", "App").pathString
)
XCTAssertEqual(debugout, "123\n")
let releaseout = try await AsyncProcess.checkNonZeroExit(
args: targetPath.appending(components: "release", "App").pathString
)
XCTAssertEqual(releaseout, "123\n")
let executable = try fixturePath.appending(components: ["App"] + buildSystem.binPath(for: configuration) + ["App"])
let releaseout = try await AsyncProcess.checkNonZeroExit(
args: executable.pathString
)
#expect(releaseout == "123\n")
}
} when: {
ProcessInfo.hostOperatingSystem == .windows
|| (buildSystem == .swiftbuild && configuration == .release)
}
}

func testTransitiveDependency() async throws {
try XCTSkipOnWindows(because: "fails to build on windows (maybe not supported?)")
try await fixtureXCTest(name: "ModuleMaps/Transitive", cModuleName: "packageD", rootpkg: "packageA") { fixturePath, Xld in
await XCTAssertBuilds(
fixturePath.appending("packageA"),
Xld: Xld,
buildSystem: .native,
)

func verify(_ conf: String) async throws {
let triple = try UserToolchain.default.targetTriple
@Test(
.serialized, // crash occurs when executed in parallel. needs investigation
arguments: getBuildData(for: SupportedBuildSystemOnAllPlatforms),
)
func transitiveDependency(
buildData: BuildData,
) async throws {
let configuration = buildData.config
let buildSystem = buildData.buildSystem
try await withKnownIssue(isIntermittent: true) {
try await localFixture(
name: "ModuleMaps/Transitive",
cModuleName: "packageD",
rootpkg: "packageA",
buildSystem: buildSystem,
config: configuration,
) { fixturePath, Xld in
try await executeSwiftBuild(
fixturePath.appending("packageA"),
configuration: configuration,
Xld: Xld,
buildSystem: buildSystem,
)

let executable = try fixturePath.appending(components: ["packageA"] + buildSystem.binPath(for: configuration) + ["packageA"])
let out = try await AsyncProcess.checkNonZeroExit(
args: fixturePath.appending(components: "packageA", ".build", triple.platformBuildPathComponent, conf, "packageA").pathString
args: executable.pathString
)
XCTAssertEqual(out, """
#expect(out == """
calling Y.bar()
Y.bar() called
X.foo() called
123

""")
}

try await verify("debug")
try await verify("release")
} when: {
ProcessInfo.hostOperatingSystem == .windows
|| (buildSystem == .swiftbuild && configuration == .release)
}
}
}
Loading
Loading