Skip to content

Tests: Conditionally skip the Archiver tests #8601

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
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
2 changes: 1 addition & 1 deletion Sources/Basics/Archiver/TarArchiver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public struct TarArchiver: Archiver {
private let cancellator: Cancellator

/// The underlying command
private let tarCommand: String
internal let tarCommand: String

/// Creates a `TarArchiver`.
///
Expand Down
22 changes: 17 additions & 5 deletions Sources/Basics/Archiver/ZipArchiver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,14 @@ public struct ZipArchiver: Archiver, Cancellable {

/// Absolute path to the Windows tar in the system folder
#if os(Windows)
private let windowsTar: String
internal let windowsTar: String
#else
internal let unzip = "unzip"
internal let zip = "zip"
#endif

#if os(FreeBSD)
internal let tar = "tar"
#endif

/// Creates a `ZipArchiver`.
Expand Down Expand Up @@ -74,7 +81,9 @@ public struct ZipArchiver: Archiver, Cancellable {
// It's part of system32 anyway so use the absolute path.
let process = AsyncProcess(arguments: [windowsTar, "xf", archivePath.pathString, "-C", destinationPath.pathString])
#else
let process = AsyncProcess(arguments: ["unzip", archivePath.pathString, "-d", destinationPath.pathString])
let process = AsyncProcess(arguments: [
self.unzip, archivePath.pathString, "-d", destinationPath.pathString,
])
#endif
guard let registrationKey = self.cancellator.register(process) else {
throw CancellationError.failedToRegisterProcess(process)
Expand Down Expand Up @@ -113,7 +122,10 @@ public struct ZipArchiver: Archiver, Cancellable {
// On FreeBSD, the unzip command is available in base but not the zip command.
// Therefore; we use libarchive(bsdtar) to produce the ZIP archive instead.
let process = AsyncProcess(
arguments: ["tar", "-c", "--format", "zip", "-f", destinationPath.pathString, directory.basename],
arguments: [
self.tar, "-c", "--format", "zip", "-f", destinationPath.pathString,
directory.basename,
],
workingDirectory: directory.parentDirectory
)
#else
Expand All @@ -127,7 +139,7 @@ public struct ZipArchiver: Archiver, Cancellable {
arguments: [
"/bin/sh",
"-c",
"cd \(directory.parentDirectory.underlying.pathString) && zip -ry \(destinationPath.pathString) \(directory.basename)",
"cd \(directory.parentDirectory.underlying.pathString) && \(self.zip) -ry \(destinationPath.pathString) \(directory.basename)"
]
)
#endif
Expand All @@ -154,7 +166,7 @@ public struct ZipArchiver: Archiver, Cancellable {
#if os(Windows)
let process = AsyncProcess(arguments: [windowsTar, "tf", path.pathString])
#else
let process = AsyncProcess(arguments: ["unzip", "-t", path.pathString])
let process = AsyncProcess(arguments: [self.unzip, "-t", path.pathString])
#endif
guard let registrationKey = self.cancellator.register(process) else {
throw CancellationError.failedToRegisterProcess(process)
Expand Down
25 changes: 25 additions & 0 deletions Sources/_InternalTestSupport/XCTAssertHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,31 @@ public func XCTSkipOnWindows(because reason: String? = nil, skipPlatformCi: Bool
#endif
}

public func _requiresTools(_ executable: String) throws {
func getAsyncProcessArgs(_ executable: String) -> [String] {
#if os(Windows)
let args = ["cmd.exe", "/c", "where.exe", executable]
#else
let args = ["which", executable]
#endif
return args
}
try AsyncProcess.checkNonZeroExit(arguments: getAsyncProcessArgs(executable))
}
public func XCTRequires(
executable: String,
file: StaticString = #filePath,
line: UInt = #line
) throws {

do {
try _requiresTools(executable)
} catch (let AsyncProcessResult.Error.nonZeroExit(result)) {
throw XCTSkip(
"Skipping as tool \(executable) is not found in the path. (\(result.description))")
}
}

/// An `async`-friendly replacement for `XCTAssertThrowsError`.
public func XCTAssertAsyncThrowsError<T>(
_ expression: @autoclosure () async throws -> T,
Expand Down
6 changes: 6 additions & 0 deletions Tests/BasicsTests/Archiver/TarArchiverTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@
//===----------------------------------------------------------------------===//

import Basics
@testable import struct Basics.TarArchiver
import TSCclibc // for SPM_posix_spawn_file_actions_addchdir_np_supported
import _InternalTestSupport
import XCTest

import struct TSCBasic.FileSystemError

final class TarArchiverTests: XCTestCase {
override func setUp() async throws {
let archiver = TarArchiver(fileSystem: localFileSystem)
try XCTRequires(executable: archiver.tarCommand)
}

func testSuccess() async throws {
try await testWithTemporaryDirectory { tmpdir in
let archiver = TarArchiver(fileSystem: localFileSystem)
Expand Down
18 changes: 18 additions & 0 deletions Tests/BasicsTests/Archiver/UniversalArchiverTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,31 @@
//===----------------------------------------------------------------------===//

import Basics
@testable import struct Basics.TarArchiver
@testable import struct Basics.ZipArchiver
import TSCclibc // for SPM_posix_spawn_file_actions_addchdir_np_supported
import _InternalTestSupport
import XCTest

import struct TSCBasic.FileSystemError

final class UniversalArchiverTests: XCTestCase {
override func setUp() async throws {
let zipAchiver = ZipArchiver(fileSystem: localFileSystem)
#if os(Windows)
try XCTRequires(executable: zipAchiver.windowsTar)
#else
try XCTRequires(executable: zipAchiver.unzip)
try XCTRequires(executable: zipAchiver.zip)
#endif
#if os(FreeBSD)
try XCTRequires(executable: zipAchiver.tar)
#endif

let tarAchiver = TarArchiver(fileSystem: localFileSystem)
try XCTRequires(executable: tarAchiver.tarCommand)
}

func testSuccess() async throws {
try await testWithTemporaryDirectory { tmpdir in
let archiver = UniversalArchiver(localFileSystem)
Expand Down
14 changes: 14 additions & 0 deletions Tests/BasicsTests/Archiver/ZipArchiverTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,27 @@
//===----------------------------------------------------------------------===//

import Basics
@testable import struct Basics.ZipArchiver
import _InternalTestSupport
import XCTest
import TSCclibc // for SPM_posix_spawn_file_actions_addchdir_np_supported

import struct TSCBasic.FileSystemError

final class ZipArchiverTests: XCTestCase {
override func setUp() async throws {
let archiver = ZipArchiver(fileSystem: localFileSystem)
#if os(Windows)
try XCTRequires(executable: archiver.windowsTar)
#else
try XCTRequires(executable: archiver.unzip)
try XCTRequires(executable: archiver.zip)
#endif
#if os(FreeBSD)
try XCTRequires(executable: archiver.tar)
#endif
}

func testZipArchiverSuccess() async throws {
try await testWithTemporaryDirectory { tmpdir in
let archiver = ZipArchiver(fileSystem: localFileSystem)
Expand Down
11 changes: 11 additions & 0 deletions Tests/_InternalTestSupportTests/Misc.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// 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 SPMBuildCore
import _InternalTestSupport
import XCTest
Expand Down
38 changes: 38 additions & 0 deletions Tests/_InternalTestSupportTests/XCTAssertHelpersTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 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 Basics
import XCTest
import func _InternalTestSupport.XCTAssertThrows
import func _InternalTestSupport._requiresTools

final class TestRequiresTool: XCTestCase {
func testErrorIsThrownIfExecutableIsNotFoundOnThePath() throws {
XCTAssertThrows(
try _requiresTools("doesNotExists")
) { (error: AsyncProcessResult.Error) in
return true
}
}

func testErrorIsNotThrownIfExecutableIsOnThePath() throws {
// Essentially call either "which which" or "where.exe where.exe"
#if os(Window)
let executable = "where.exe"
#else
let executable = "which"
#endif
XCTAssertNoThrow(
try _requiresTools(executable)
)
}
}