import Foundation import Synchronization import Testing @testable import bar /// Blocking Runner work stays off the cooperative executor. The outer deadline /// also fails promptly if a regression prevents Runner from returning. private func runCommand(_ command: String, env: [String: String] = [:]) throws -> (lines: [String], diagnostics: Data) { let url = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) FileManager.default.createFile(atPath: url.path, contents: nil) let output = try FileHandle(forWritingTo: url) defer { try? FileManager.default.removeItem(at: url) } let result = Mutex<[String]?>(nil) let finished = DispatchSemaphore(value: 0) DispatchQueue.global(qos: .utility).async { let lines = Runner.run(command, env: env, errorOutput: output) try? output.close() result.withLock { $0 = lines } finished.signal() } let completed = finished.wait(timeout: .now() + 5) == .success try #require(completed, "Runner exceeded the five-second outer deadline") return (try #require(result.withLock { $0 }), try Data(contentsOf: url)) } @Test func drainsLargeStderrBeforeStdout() throws { let result = try runCommand("/usr/bin/head -c 1048576 /dev/zero >&2; printf ' ready \\n'") #expect(result.lines == [" ready "]) #expect(result.diagnostics == Data(repeating: 0, count: 1048576)) } @Test func drainsSimultaneousLargeStreams() throws { let result = try runCommand("/usr/bin/head -c 1048576 /dev/zero >&2 & /usr/bin/head -c 1048576 /dev/zero; wait") #expect(result.lines == [String(repeating: "\0", count: 1048576)]) #expect(result.diagnostics == Data(repeating: 0, count: 1048576)) } @Test func emptyCommandOutput() throws { let result = try runCommand(":") #expect(result.lines.isEmpty) #expect(result.diagnostics.isEmpty) } @Test func failedCommandForwardsDiagnostics() throws { let result = try runCommand("printf 'ignored'; printf 'failure\\n' >&2; exit 7") #expect(result.lines == ["ERROR"]) #expect(result.diagnostics == Data("failure\n".utf8)) } @Test func shellEnvironmentAndWhitespaceArePreserved() throws { let result = try runCommand("printf ' %s \\n\\nlast\\n' \"$BAR_RUNNER_TEST\"; test -n \"$PATH\"", env: ["BAR_RUNNER_TEST": "value"]) #expect(result.lines == [" value ", "", "last"]) } @Test func parsingEmptyOutputProducesNoCells() { #expect(Runner.parse("") == []) } @Test func parsingRemovesOneFinalNewline() { #expect(Runner.parse("cell\n") == ["cell"]) #expect(Runner.parse("cell") == ["cell"]) } @Test func parsingPreservesInternalBlankLines() { #expect(Runner.parse("first\n\n\nlast\n") == ["first", "", "", "last"]) #expect(Runner.parse("\nfirst") == ["", "first"]) } @Test func parsingPreservesAdditionalTrailingBlankLines() { #expect(Runner.parse("cell\n\n\n") == ["cell", "", ""]) #expect(Runner.parse("\n") == [""]) #expect(Runner.parse("\n\n") == ["", ""]) } @Test func parsingPreservesLineOrder() { #expect(Runner.parse("third\nfirst\nsecond\n") == ["third", "first", "second"]) } @Test func parsingDoesNotTrimWhitespace() { #expect(Runner.parse(" leading\ntrailing \n\t \t\n") == [" leading", "trailing ", "\t \t"]) }