Files
phbar/Tests/phbarTests/PHBlockTests.swift

190 lines
4.6 KiB
Swift

import AppKit
import Foundation
import Testing
@testable import phbar
// MARK: - Loading
@MainActor
@Test func loadBlocksFromTOML() throws {
let toml = """
[[block]]
command = "echo hello"
name = "greeting"
refresh = 5.0
[[block]]
command = "echo world"
name = "world"
"""
let blocks = try PHBlock.load(from: toml)
#expect(blocks.count == 2)
#expect(blocks[0].command == "echo hello")
#expect(blocks[0].name == "greeting")
#expect(blocks[0].refresh == 5.0)
#expect(blocks[0].label == nil)
#expect(blocks[1].name == "world")
#expect(blocks[1].refresh == nil)
}
@MainActor
@Test func loadBlocksRejectsInvalidTOML() {
#expect(throws: (any Error).self) {
try PHBlock.load(from: "not = valid = toml = =")
}
}
// MARK: - Named set loading
private func makeBlocksConfigDir() throws -> URL {
let dir = FileManager.default.temporaryDirectory.appending(path: "phbar_blocks_\(UUID().uuidString)")
try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
return dir
}
@MainActor
@Test func loadSetReadsNamedFile() throws {
let dir = try makeBlocksConfigDir()
defer { try? FileManager.default.removeItem(at: dir) }
let blocksDir = dir.appending(path: "blocks")
try FileManager.default.createDirectory(at: blocksDir, withIntermediateDirectories: true)
try Data("""
[[block]]
command = "echo hi"
name = "greeting"
""".utf8).write(to: blocksDir.appending(path: "laptop.toml"))
let blocks = try PHBlock.load("laptop", in: dir)
#expect(blocks.count == 1)
#expect(blocks[0].name == "greeting")
}
@MainActor
@Test func loadSetThrowsForMissingSet() {
let dir = FileManager.default.temporaryDirectory.appending(path: "phbar_missing_\(UUID().uuidString)")
#expect(throws: (any Error).self) {
try PHBlock.load("nope", in: dir)
}
}
// MARK: - Compute
@MainActor
@Test func computeSeesBlockEnvironment() async throws {
// The `[env]` section (overlaid by `BarController`) must reach the script's
// process environment this is the wiring the `env` config documents.
let block = try PHBlock.load(from: """
[[block]]
name = "env"
command = "echo $PHBAR_TEST_VAR"
""")[0]
block.environment = PHEnvironment(variables: ["PHBAR_TEST_VAR": "panini"])
let output = await block.compute()
#expect(output == "panini")
}
@MainActor
@Test func computeReturnsCommandStdout() async throws {
let blocks = try PHBlock.load(from: """
[[block]]
command = "printf panini"
name = "panini"
""")
let output = await blocks[0].compute()
#expect(output == "panini")
}
@MainActor
@Test func computeRunsInConfigDirectory() async throws {
// Block commands execute with the resolved config root (see `PHPaths`) as
// their working directory, so a block from any set resolves relative paths
// the same way. Guards against the config dir being absent in sandboxed CIs.
guard FileManager.default.fileExists(atPath: PHPaths.configDirectory.path) else { return }
let blocks = try PHBlock.load(from: """
[[block]]
command = "pwd"
name = "pwd"
""")
let output = await blocks[0].compute()
// Resolve symlinks on both sides: the config dir is commonly a symlink into
// a dotfiles repo, and `pwd` reports the physical path.
let expected = PHPaths.configDirectory.resolvingSymlinksInPath().path
#expect(output == expected)
}
// MARK: - Auto-refresh
@MainActor
@Test func updateSetsLabel() async throws {
let block = try PHBlock.load(from: """
[[block]]
command = "printf panini"
name = "panini"
""")[0]
#expect(block.label == nil)
await block.update()
#expect(block.label == "panini")
}
@MainActor
@Test func startAutoRefreshWithoutIntervalComputesOnce() async throws {
let block = try PHBlock.load(from: """
[[block]]
command = "printf hi"
name = "hi"
""")[0]
block.startAutoRefresh()
// Allow the one-shot update task to run.
try await Task.sleep(for: .milliseconds(100))
#expect(block.label == "hi")
block.stopAutoRefresh()
}
@MainActor
@Test func startAutoRefreshRepeatsAtInterval() async throws {
// A counter file lets us observe how many times the command ran.
let counter = FileManager.default.temporaryDirectory
.appending(path: "phbar_test_\(UUID().uuidString)")
defer { try? FileManager.default.removeItem(at: counter) }
let path = counter.path
let toml = """
[[block]]
command = "n=$(cat \(path) 2>/dev/null || echo 0); n=$((n+1)); echo $n > \(path); echo $n"
name = "counter"
refresh = 0.05
"""
let block = try PHBlock.load(from: toml)[0]
block.startAutoRefresh()
try await Task.sleep(for: .milliseconds(250))
block.stopAutoRefresh()
let count = Int(block.label!.trimmingCharacters(in: .whitespacesAndNewlines)) ?? 0
// At ~20Hz over 250ms the command should have run more than once.
#expect(count >= 2)
}