Implemented the RunProcessUseCase use case in the app target.
This commit is contained in:
parent
12177be8db
commit
66844fe389
@ -35,6 +35,7 @@
|
||||
membershipExceptions = (
|
||||
UITests/UITests.swift,
|
||||
UITests/UITestsLaunchTests.swift,
|
||||
UnitTests/Tests/UseCases/RunProcessUseCaseTests.swift,
|
||||
UnitTests/UnitTests.swift,
|
||||
);
|
||||
target = 46D4BE762CB06ED300FCFB84 /* Piper */;
|
||||
@ -42,6 +43,7 @@
|
||||
46D4BEF72CB07CCB00FCFB84 /* Exceptions for "Tests" folder in "UnitTests" target */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
UnitTests/Tests/UseCases/RunProcessUseCaseTests.swift,
|
||||
UnitTests/UnitTests.swift,
|
||||
);
|
||||
target = 46D4BED32CB07C7A00FCFB84 /* UnitTests */;
|
||||
@ -492,6 +494,7 @@
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = 7FMNM89WKG;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.6;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.rock-n-code.piper.tests.unit";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@ -509,6 +512,7 @@
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = 7FMNM89WKG;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.6;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.rock-n-code.piper.tests.unit";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
87
Piper/Sources/Logic/UseCases/RunProcessUseCase.swift
Normal file
87
Piper/Sources/Logic/UseCases/RunProcessUseCase.swift
Normal file
@ -0,0 +1,87 @@
|
||||
//
|
||||
// RunProcessUseCase.swift
|
||||
// Piper ~ App
|
||||
//
|
||||
// Created by Javier Cicchelli on 05/10/2024.
|
||||
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct RunProcessUseCase {
|
||||
|
||||
// MARK: Type aliases
|
||||
|
||||
typealias Output = String
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
private let path: String
|
||||
private let arguments: [String]?
|
||||
|
||||
// MARK: Initialisers
|
||||
|
||||
init(
|
||||
path: String,
|
||||
arguments: [String] = []
|
||||
) {
|
||||
self.path = path
|
||||
self.arguments = arguments
|
||||
}
|
||||
|
||||
// MARK: Functions
|
||||
|
||||
func callAsFunction() async throws -> Output {
|
||||
let process = Process()
|
||||
|
||||
process.executableURL = URL(fileURLWithPath: path)
|
||||
process.arguments = arguments
|
||||
|
||||
let pipeError = Pipe()
|
||||
let pipeOutput = Pipe()
|
||||
|
||||
process.standardError = pipeError
|
||||
process.standardOutput = pipeOutput
|
||||
|
||||
async let streamOutput = pipeOutput.availableData.append()
|
||||
async let streamError = pipeError.availableData.append()
|
||||
|
||||
do {
|
||||
try process.run()
|
||||
|
||||
let dataOutput = await streamOutput
|
||||
let dataError = await streamError
|
||||
|
||||
guard dataError.isEmpty else {
|
||||
guard let errorOutput = String(data: dataError, encoding: .utf8) else {
|
||||
throw RunProcessError.unexpected
|
||||
}
|
||||
|
||||
throw RunProcessError.output(errorOutput)
|
||||
}
|
||||
|
||||
guard let output = String(data: dataOutput, encoding: .utf8) else {
|
||||
throw RunProcessError.unexpected
|
||||
}
|
||||
|
||||
return await withCheckedContinuation { continuation in
|
||||
process.terminationHandler = { _ in
|
||||
continuation.resume(returning: output)
|
||||
}
|
||||
}
|
||||
} catch let error as RunProcessError {
|
||||
throw error
|
||||
} catch {
|
||||
throw RunProcessError.captured(error)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Errors
|
||||
|
||||
enum RunProcessError: Error {
|
||||
case captured(_ error: Error)
|
||||
case output(_ output: String)
|
||||
case unexpected
|
||||
}
|
69
Tests/UnitTests/Tests/UseCases/RunProcessUseCaseTests.swift
Normal file
69
Tests/UnitTests/Tests/UseCases/RunProcessUseCaseTests.swift
Normal file
@ -0,0 +1,69 @@
|
||||
//
|
||||
// RunProcessUseCaseTests.swift
|
||||
// UnitTests
|
||||
//
|
||||
// Created by Javier Cicchelli on 05/10/2024.
|
||||
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
||||
//
|
||||
|
||||
import Testing
|
||||
|
||||
@testable import Piper
|
||||
|
||||
struct RunProcessUseCaseTests {
|
||||
|
||||
// MARK: Functions tests
|
||||
|
||||
@Test("Run a simple process without arguments")
|
||||
func simpleCommand_withoutArguments() async throws {
|
||||
// GIVEN
|
||||
let useCase = RunProcessUseCase(path: .ls)
|
||||
|
||||
// WHEN
|
||||
let output = try await useCase()
|
||||
|
||||
// THEN
|
||||
#expect(output.isEmpty == false)
|
||||
}
|
||||
|
||||
@Test("Run a simple process with arguments")
|
||||
func simpleCommand_withArguments() async throws {
|
||||
// GIVEN
|
||||
let useCase = RunProcessUseCase(
|
||||
path: .ls,
|
||||
arguments: ["-la", "."]
|
||||
)
|
||||
|
||||
// WHEN
|
||||
let output = try await useCase()
|
||||
|
||||
// THEN
|
||||
#expect(output.isEmpty == false)
|
||||
}
|
||||
|
||||
@Test("Run a simple command with arguments that throws an error")
|
||||
func simpleCommand_withArguments_throwsError() async throws {
|
||||
// GIVEN
|
||||
let useCase = RunProcessUseCase(
|
||||
path: .ls,
|
||||
arguments: ["-la", "~"]
|
||||
)
|
||||
|
||||
// WHEN
|
||||
// THEN
|
||||
await #expect(throws: RunProcessError.self) {
|
||||
try await useCase()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - String+Constants
|
||||
|
||||
private extension String {
|
||||
|
||||
// MARK: Constants
|
||||
|
||||
static let ls = "/bin/ls"
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user