From 39d8398a4a4a14732956cadee48b1c23d7cc1a32 Mon Sep 17 00:00:00 2001 From: Hashim1999164 <64767361+Hashim1999164@users.noreply.github.com> Date: Thu, 13 Aug 2026 16:20:39 +0500 Subject: [PATCH 1/2] Stop importing Testing from ContainerTestSupport --- Sources/ContainerTestSupport/BuildFixture.swift | 9 ++++++--- .../ContainerFixture+ImageHelpers.swift | 5 +++-- .../ContainerFixture+MachineHelpers.swift | 1 - Sources/ContainerTestSupport/ContainerFixture.swift | 1 - 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Sources/ContainerTestSupport/BuildFixture.swift b/Sources/ContainerTestSupport/BuildFixture.swift index f317c2fb9..7ad95191e 100644 --- a/Sources/ContainerTestSupport/BuildFixture.swift +++ b/Sources/ContainerTestSupport/BuildFixture.swift @@ -18,7 +18,6 @@ import ContainerizationExtras import Darwin import Foundation import SystemPackage -import Testing // MARK: - Build context types @@ -309,12 +308,16 @@ extension ContainerFixture { /// Asserts that `path` exists as a regular file inside `container`. public func assertContainerHasFile(_ container: String, at path: String, _ comment: String? = nil) throws { let exists = try containerHasFile(container, at: path) - #expect(exists, "\(comment ?? path) should exist in container") + guard exists else { + throw CommandError.executionFailed("\(comment ?? path) should exist in container") + } } /// Asserts that `path` does NOT exist inside `container`. public func assertContainerMissingFile(_ container: String, at path: String, _ comment: String? = nil) throws { let exists = try containerHasFile(container, at: path) - #expect(!exists, "\(comment ?? path) should NOT exist in container") + guard !exists else { + throw CommandError.executionFailed("\(comment ?? path) should NOT exist in container") + } } } diff --git a/Sources/ContainerTestSupport/ContainerFixture+ImageHelpers.swift b/Sources/ContainerTestSupport/ContainerFixture+ImageHelpers.swift index ffdc48db7..8aadcfbf1 100644 --- a/Sources/ContainerTestSupport/ContainerFixture+ImageHelpers.swift +++ b/Sources/ContainerTestSupport/ContainerFixture+ImageHelpers.swift @@ -16,7 +16,6 @@ import Foundation import SystemPackage -import Testing // MARK: - Image inspect types @@ -109,6 +108,8 @@ extension ContainerFixture { /// Asserts that the image was successfully built and is present in the image store. public func assertImageBuilt(_ image: String) throws { let name = try inspectImage(image) - #expect(name == image, "expected image \(image) to be present") + guard name == image else { + throw CommandError.executionFailed("expected image \(image) to be present") + } } } diff --git a/Sources/ContainerTestSupport/ContainerFixture+MachineHelpers.swift b/Sources/ContainerTestSupport/ContainerFixture+MachineHelpers.swift index 13e3ca9c7..8c5898605 100644 --- a/Sources/ContainerTestSupport/ContainerFixture+MachineHelpers.swift +++ b/Sources/ContainerTestSupport/ContainerFixture+MachineHelpers.swift @@ -15,7 +15,6 @@ //===----------------------------------------------------------------------===// import Foundation -import Testing // MARK: - Machine output types diff --git a/Sources/ContainerTestSupport/ContainerFixture.swift b/Sources/ContainerTestSupport/ContainerFixture.swift index 7431c642f..32a763129 100644 --- a/Sources/ContainerTestSupport/ContainerFixture.swift +++ b/Sources/ContainerTestSupport/ContainerFixture.swift @@ -20,7 +20,6 @@ import Foundation import Logging import Synchronization import SystemPackage -import Testing /// Per-test fixture for CLI integration tests. /// From e89a6a492e5bcf826604d65cfba936a238127401 Mon Sep 17 00:00:00 2001 From: Hashim1999164 <64767361+Hashim1999164@users.noreply.github.com> Date: Sun, 16 Aug 2026 15:15:20 +0500 Subject: [PATCH 2/2] Pass fixture test identity from the IntegrationTests target. --- .../ContainerFixture.swift | 47 ++++++++++++------- .../ContainerFixture+Testing.swift | 36 ++++++++++++++ 2 files changed, 67 insertions(+), 16 deletions(-) create mode 100644 Tests/IntegrationTests/ContainerFixture+Testing.swift diff --git a/Sources/ContainerTestSupport/ContainerFixture.swift b/Sources/ContainerTestSupport/ContainerFixture.swift index 32a763129..284bf03a1 100644 --- a/Sources/ContainerTestSupport/ContainerFixture.swift +++ b/Sources/ContainerTestSupport/ContainerFixture.swift @@ -72,29 +72,44 @@ public final class ContainerFixture: Sendable { // MARK: - Unstructured API + /// Identity of the running test, supplied by the test target. + /// + /// `ContainerTestSupport` does not import the Testing module, so callers that + /// can `import Testing` should pass `Test.current` / `Test.Case.current` here. + public struct TestIdentity: Sendable { + public var name: String? + public var identifier: String? + public var isParameterized: Bool + + public init(name: String? = nil, identifier: String? = nil, isParameterized: Bool = false) { + self.name = name + self.identifier = identifier + self.isParameterized = isParameterized + } + } + /// Runs `body` with a fresh fixture, then tears down all registered resources. /// /// Cleanup runs in LIFO order regardless of whether `body` throws. + /// Pass `identity` from the test target so log files and scratch directories + /// keep the current test name without this module importing Testing. @discardableResult - public static func with(_ body: (ContainerFixture) async throws -> T) async throws -> T { + public static func with(identity: TestIdentity, _ body: (ContainerFixture) async throws -> T) async throws -> T { let testID = String(UUID().uuidString.prefix(8)).lowercased() - let testName = - Test.current.map { $0.name.hasSuffix("()") ? String($0.name.dropLast(2)) : $0.name } - ?? testID - // Test.current is a value describing the running test, not an instance of the suite - // type, so `type(of:)` always yields `Test` itself. Derive the suite from the test's - // fully-qualified ID instead (e.g. "IntegrationTests.TestCLIStatus/explicitTableFormat()/...") - // — the same identifier format used in the swift-testing event-stream JSON. - let testIdentifier = Test.current.map { "\($0.id)" } + let testName: String = { + guard let name = identity.name else { return testID } + return name.hasSuffix("()") ? String(name.dropLast(2)) : name + }() + // Derive the suite from the test's fully-qualified ID + // (e.g. "IntegrationTests.TestCLIStatus/explicitTableFormat()/..."), + // the same identifier format used in the swift-testing event-stream JSON. + let testIdentifier = identity.identifier let suiteName = testIdentifier?.split(separator: "/", maxSplits: 1).first.map(String.init) ?? "unknown" - // Swift Testing doesn't expose a stable per-case identifier or the case's arguments - // publicly, only `isParameterized`. Parameterized tests share one `testName` across all - // their concurrently-running cases, so fall back to the per-invocation `testID` to keep - // each case's log file distinct. - let isParameterized = Test.Case.current?.isParameterized ?? false - let logFileName = isParameterized ? "\(testName)-\(testID).log" : "\(testName).log" + // Parameterized tests share one `testName` across concurrently-running cases, + // so fall back to the per-invocation `testID` to keep each case's log file distinct. + let logFileName = identity.isParameterized ? "\(testName)-\(testID).log" : "\(testName).log" // Set up logging before any fixture work (scratch dir creation, etc.) so a "test start" // message is the first thing recorded — bookended by "test end" once `body` returns. @@ -123,7 +138,7 @@ public final class ContainerFixture: Sendable { // Name the scratch directory so it's immediately identifiable when browsing: // {sanitizedTestName}-{testID} let safeName = testName.replacingOccurrences( - of: "[^a-zA-Z0-9]", with: "-", options: .regularExpression) + of: "[^a-zA-Z0-9]", with: "-", options: String.CompareOptions.regularExpression) let testDir = scratchRoot.appending("\(safeName)-\(testID)") try FileManager.default.createDirectory( atPath: testDir.string, withIntermediateDirectories: true, attributes: nil) diff --git a/Tests/IntegrationTests/ContainerFixture+Testing.swift b/Tests/IntegrationTests/ContainerFixture+Testing.swift new file mode 100644 index 000000000..41989670e --- /dev/null +++ b/Tests/IntegrationTests/ContainerFixture+Testing.swift @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// Copyright © 2026 Apple Inc. and the container project authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//===----------------------------------------------------------------------===// + +import ContainerTestSupport +import Testing + +extension ContainerFixture { + /// Opens a fixture scope using Swift Testing's current test identity. + /// + /// `ContainerTestSupport` cannot import Testing, so this test-target wrapper + /// reads `Test.current` / `Test.Case.current` and forwards them. + @discardableResult + static func with(_ body: (ContainerFixture) async throws -> T) async throws -> T { + try await with( + identity: TestIdentity( + name: Test.current?.name, + identifier: Test.current.map { "\($0.id)" }, + isParameterized: Test.Case.current?.isParameterized ?? false + ), + body + ) + } +}