b69b6ff877
For some reason I apparently thought that lazy properties are always immutable. I have no idea why.
323 lines
10 KiB
Swift
Executable File
323 lines
10 KiB
Swift
Executable File
//
|
|
// Command_Tests.swift
|
|
// SwiftShell
|
|
//
|
|
// Created by Kåre Morstøl on 15/08/14.
|
|
// Copyright (c) 2014 NotTooBad Software. All rights reserved.
|
|
//
|
|
|
|
import SwiftShell
|
|
import XCTest
|
|
import Foundation
|
|
|
|
#if os(Linux)
|
|
import Glibc
|
|
#endif
|
|
|
|
public class Run_Tests: XCTestCase {
|
|
|
|
func testCompilesWhenNotDefiningReturnType() {
|
|
_ = SwiftShell.run("echo", "hi")
|
|
_ = SwiftShell.run(bash: "echo hi")
|
|
main.run("echo", "hi")
|
|
main.run(bash: "echo hi")
|
|
}
|
|
|
|
func testBashCommand() {
|
|
XCTAssertEqual( SwiftShell.run(bash:"echo one").stdout, "one" )
|
|
}
|
|
|
|
func testArgumentsFromArray() {
|
|
let stringarray = ["one", "two"]
|
|
XCTAssertEqual( SwiftShell.run("/bin/echo", stringarray).stdout, "one two" )
|
|
}
|
|
|
|
func testSinglelineOutput() {
|
|
XCTAssertEqual( SwiftShell.run("/bin/echo", "one", "two").stdout, "one two" )
|
|
}
|
|
|
|
func testMultilineOutput() {
|
|
XCTAssertEqual( SwiftShell.run("/bin/echo", "one\ntwo").stdout, "one\ntwo\n" )
|
|
}
|
|
|
|
func testStandardErrorOutput() {
|
|
XCTAssertEqual( SwiftShell.run(bash:"echo one 1>&2").stderror, "one" )
|
|
}
|
|
|
|
func testCombinesOutput() {
|
|
XCTAssertEqual( SwiftShell.run(bash: "echo stdout; echo stderr > /dev/stderr", combineOutput: true).stdout, "stdout\nstderr\n" )
|
|
}
|
|
|
|
func testExecutableWithoutPath() {
|
|
XCTAssertEqual( SwiftShell.run("echo", "one").stdout, "one")
|
|
}
|
|
|
|
func testSuccess() {
|
|
let success = SwiftShell.run(bash: "exit 0")
|
|
XCTAssertEqual( success.exitcode, 0)
|
|
XCTAssertEqual( success.succeeded, true)
|
|
|
|
let failure = SwiftShell.run(bash: "exit 1")
|
|
XCTAssertEqual( failure.exitcode, 1)
|
|
XCTAssertEqual( failure.succeeded, false)
|
|
}
|
|
|
|
func testAnd() {
|
|
main.currentdirectory = main.tempdirectory
|
|
let bothsucceed = SwiftShell.run("touch", "created") && SwiftShell.run("echo", "thisran")
|
|
XCTAssert(Files.fileExists(atPath: "created"))
|
|
XCTAssertEqual(bothsucceed.stdout, "thisran")
|
|
|
|
let firstfails = SwiftShell.run(bash: "exit 1") && SwiftShell.run("touch", "notcreated")
|
|
XCTAssertFalse(firstfails.succeeded)
|
|
XCTAssertFalse(Files.fileExists(atPath: "notcreated"))
|
|
}
|
|
|
|
func testOr() {
|
|
main.currentdirectory = main.tempdirectory
|
|
let firstran = SwiftShell.run("echo", "thisran") || SwiftShell.run("touch", "notcreated")
|
|
XCTAssertEqual(firstran.stdout, "thisran")
|
|
XCTAssertFalse(Files.fileExists(atPath: "notcreated"))
|
|
|
|
let firstfailedsecondran = SwiftShell.run(bash: "exit 1") || SwiftShell.run("echo", "thisran")
|
|
XCTAssertEqual(firstfailedsecondran.stdout, "thisran")
|
|
}
|
|
|
|
// https://github.com/kareman/SwiftShell/issues/52
|
|
func testDoesNotHaltOnLargeOutput() {
|
|
SwiftShell.run(bash: "for i in {1..65537}; do echo -n '='; done") // standard output
|
|
|
|
SwiftShell.run(bash: "for i in {1..65537}; do echo -n '=' 1>&2; done") // standard error
|
|
|
|
SwiftShell.run(bash: "for i in {1..65537}; do echo -n '='; echo -n '=' 1>&2; done") // both
|
|
}
|
|
}
|
|
|
|
public class RunAsync_Tests: XCTestCase {
|
|
|
|
func testReturnsStandardOutput() {
|
|
let asynccommand = runAsync("/bin/echo", "one", "two" )
|
|
AssertDoesNotThrow { try asynccommand.finish() }
|
|
|
|
XCTAssertEqual( asynccommand.stdout.read(), "one two\n" )
|
|
XCTAssertEqual( asynccommand.stderror.read(), "" )
|
|
}
|
|
|
|
func testReturnsStandardError() {
|
|
let asynccommand = runAsync(bash: "echo one two > /dev/stderr" )
|
|
AssertDoesNotThrow { try asynccommand.finish() }
|
|
|
|
XCTAssertEqual( asynccommand.stderror.read(), "one two\n" )
|
|
XCTAssertEqual( asynccommand.stdout.read(), "" )
|
|
}
|
|
|
|
func testArgumentsFromArray() {
|
|
AssertDoesNotThrow {
|
|
let output = try runAsync("/bin/echo", ["one", "two"]).finish().stdout.read()
|
|
XCTAssertEqual( output, "one two\n" )
|
|
}
|
|
}
|
|
|
|
func testFinishThrowsErrorOnExitcodeNotZero() {
|
|
let asynccommand = runAsync(bash: "echo errormessage > /dev/stderr; exit 1" )
|
|
|
|
AssertThrows(CommandError.returnedErrorCode(command: "/bin/bash -c \"echo errormessage > /dev/stderr; exit 1\"", errorcode: 1))
|
|
{ try asynccommand.finish() }
|
|
XCTAssertEqual( asynccommand.stderror.read(), "errormessage\n" )
|
|
}
|
|
|
|
func testExitCode() {
|
|
let asynccommand = runAsync(bash: "exit 1" )
|
|
|
|
XCTAssertEqual( asynccommand.exitcode(), 1 )
|
|
}
|
|
|
|
func testOnCompletion() {
|
|
let expectcompletion = expectation(description: "onCompletion will be called when command has finished.")
|
|
|
|
runAsync("echo").onCompletion { command in
|
|
XCTAssertFalse(command.isRunning)
|
|
expectcompletion.fulfill()
|
|
}
|
|
waitForExpectations(timeout: 0.5, handler: nil)
|
|
}
|
|
|
|
func testStop() {
|
|
// Start a command that won't exit for a long time
|
|
let command = runAsync(bash: "sleep 100")
|
|
|
|
XCTAssertTrue(command.isRunning)
|
|
command.stop()
|
|
|
|
// On Linux, command.isRunning becomes false once the command has been
|
|
// stopped, but the terminationReason does not become .uncaughtSignal
|
|
#if os(Linux)
|
|
// Checking the isRunning occasionally happens too quick for the
|
|
// assert. Sleeping for 1 second ensures the assert should pass
|
|
sleep(1)
|
|
XCTAssertFalse(command.isRunning)
|
|
// On macOS, command.isRunning is true until waitUntilExit() has been
|
|
// called, but the process's terminationReason becomes .uncaughtSignal.
|
|
#else
|
|
XCTAssertEqual(command.terminationReason(), Process.TerminationReason.uncaughtSignal)
|
|
#endif
|
|
}
|
|
|
|
func testInterrupt() {
|
|
// Start a command that won't exit for a long time
|
|
let command = runAsync(bash: "sleep 100")
|
|
|
|
XCTAssertTrue(command.isRunning)
|
|
command.interrupt()
|
|
|
|
// On Linux, command.isRunning becomes false once the command has been
|
|
// interrupted, but the terminationReason does not become
|
|
// .uncaughtSignal
|
|
#if os(Linux)
|
|
// Checking the isRunning occasionally happens too quick for the
|
|
// assert. Sleeping for 1 second ensures the assert should pass
|
|
sleep(1)
|
|
XCTAssertFalse(command.isRunning)
|
|
// On macOS, command.isRunning is true until waitUntilExit() has been
|
|
// called, but the process's terminationReason becomes .uncaughtSignal.
|
|
#else
|
|
XCTAssertEqual(command.terminationReason(), Process.TerminationReason.uncaughtSignal)
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
Cannot test the suspend/resume calls reliably
|
|
|
|
func testSuspendAndResume() {
|
|
// Start a command that wouldn't ever exit normally
|
|
let command = runAsync("cat")
|
|
|
|
XCTAssertTrue(command.isRunning)
|
|
command.suspend()
|
|
|
|
XCTAssertFalse(command.isRunning)
|
|
command.resume()
|
|
|
|
XCTAssertTrue(command.isRunning)
|
|
}
|
|
*/
|
|
}
|
|
|
|
public class XCTestCase_TestOutput: XCTestCase {
|
|
var test_stdout: FileHandle!
|
|
var test_stderr: FileHandle!
|
|
|
|
public override func setUp() {
|
|
let outputpipe = Pipe()
|
|
main.stdout = FileHandleStream(outputpipe.fileHandleForWriting, encoding: .utf8)
|
|
test_stdout = outputpipe.fileHandleForReading
|
|
|
|
let errorpipe = Pipe()
|
|
main.stderror = FileHandleStream(errorpipe.fileHandleForWriting, encoding: .utf8)
|
|
test_stderr = errorpipe.fileHandleForReading
|
|
}
|
|
}
|
|
|
|
public class RunAsyncAndPrint_Tests: XCTestCase_TestOutput {
|
|
func testReturnsStandardOutput() {
|
|
AssertDoesNotThrow { try runAsyncAndPrint("/bin/echo", "one", "two" ).finish() }
|
|
|
|
XCTAssertEqual( test_stdout.readSome(encoding: .utf8), "one two\n" )
|
|
}
|
|
|
|
func testReturnsStandardError() {
|
|
AssertDoesNotThrow { try runAsyncAndPrint(bash: "echo one two > /dev/stderr" ).finish() }
|
|
|
|
XCTAssertEqual( test_stderr.readSome(encoding: .utf8), "one two\n" )
|
|
}
|
|
|
|
func testOnCompletion() {
|
|
let expectcompletion = expectation(description: "onCompletion will be called when command has finished.")
|
|
|
|
runAsyncAndPrint("echo").onCompletion { command in
|
|
XCTAssertFalse(command.isRunning)
|
|
expectcompletion.fulfill()
|
|
}
|
|
waitForExpectations(timeout: 0.5, handler: nil)
|
|
}
|
|
}
|
|
|
|
public class RunAndPrint_Tests: XCTestCase_TestOutput {
|
|
|
|
func testReturnsStandardOutput() {
|
|
AssertDoesNotThrow { try runAndPrint("/bin/echo", "one", "two" ) }
|
|
|
|
XCTAssertEqual( test_stdout.readSome(encoding: .utf8), "one two\n" )
|
|
}
|
|
|
|
func testArgumentsFromArray() {
|
|
AssertDoesNotThrow { try runAndPrint("/bin/echo", ["one", "two"] ) }
|
|
|
|
XCTAssertEqual( test_stdout.readSome(encoding: .utf8), "one two\n" )
|
|
}
|
|
|
|
func testReturnsStandardError() {
|
|
AssertDoesNotThrow { try runAndPrint(bash: "echo one two > /dev/stderr" ) }
|
|
|
|
XCTAssertEqual( test_stderr.readSome(encoding: .utf8), "one two\n" )
|
|
}
|
|
|
|
func testThrowsErrorOnExitcodeNotZero() {
|
|
AssertThrows(CommandError.returnedErrorCode(command: "/bin/bash -c \"exit 1\"", errorcode: 1))
|
|
{ try runAndPrint("bash", "-c", "exit 1") }
|
|
}
|
|
|
|
func testThrowsErrorOnInaccessibleExecutable() {
|
|
AssertThrows(CommandError.inAccessibleExecutable(path: "notachance"))
|
|
{ try runAndPrint("notachance") }
|
|
}
|
|
}
|
|
|
|
extension Run_Tests {
|
|
public static var allTests = [
|
|
("testCompilesWhenNotDefiningReturnType", testCompilesWhenNotDefiningReturnType),
|
|
("testBashCommand", testBashCommand),
|
|
("testArgumentsFromArray", testArgumentsFromArray),
|
|
("testSinglelineOutput", testSinglelineOutput),
|
|
("testMultilineOutput", testMultilineOutput),
|
|
("testStandardErrorOutput", testStandardErrorOutput),
|
|
("testCombinesOutput", testCombinesOutput),
|
|
("testExecutableWithoutPath", testExecutableWithoutPath),
|
|
("testSuccess", testSuccess),
|
|
("testAnd", testAnd),
|
|
("testOr", testOr),
|
|
("testDoesNotHaltOnLargeOutput", testDoesNotHaltOnLargeOutput),
|
|
]
|
|
}
|
|
|
|
extension RunAsync_Tests {
|
|
public static var allTests = [
|
|
("testReturnsStandardOutput", testReturnsStandardOutput),
|
|
("testReturnsStandardError", testReturnsStandardError),
|
|
("testArgumentsFromArray", testArgumentsFromArray),
|
|
("testFinishThrowsErrorOnExitcodeNotZero", testFinishThrowsErrorOnExitcodeNotZero),
|
|
("testExitCode", testExitCode),
|
|
("testOnCompletion", testOnCompletion),
|
|
("testStop", testStop),
|
|
("testInterrupt", testInterrupt),
|
|
// ("testSuspendAndResume", testSuspendAndResume),
|
|
]
|
|
}
|
|
|
|
extension RunAsyncAndPrint_Tests {
|
|
public static var allTests = [
|
|
("testReturnsStandardOutput", testReturnsStandardOutput),
|
|
("testReturnsStandardError", testReturnsStandardError),
|
|
]
|
|
}
|
|
|
|
extension RunAndPrint_Tests {
|
|
public static var allTests = [
|
|
("testReturnsStandardOutput", testReturnsStandardOutput),
|
|
("testArgumentsFromArray", testArgumentsFromArray),
|
|
("testReturnsStandardError", testReturnsStandardError),
|
|
("testThrowsErrorOnExitcodeNotZero", testThrowsErrorOnExitcodeNotZero),
|
|
("testThrowsErrorOnInaccessibleExecutable", testThrowsErrorOnInaccessibleExecutable),
|
|
]
|
|
}
|