summaryrefslogtreecommitdiff
path: root/Tests/barTests/phbarTests.swift
blob: 982e7282e330f7f6bbc1c10a66bca712d755adc7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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"])
}