greatly simplify environment variables handling
This commit is contained in:
@@ -1,147 +0,0 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
import TOML
|
||||
|
||||
@testable import phbar
|
||||
|
||||
// MARK: - expand
|
||||
|
||||
@Test func envExpandDollarBraceForm() {
|
||||
let env = PHEnvironment(variables: ["ACCENT": "#ff0000"])
|
||||
#expect(env.expand("${ACCENT}") == "#ff0000")
|
||||
}
|
||||
|
||||
@Test func envExpandDollarForm() {
|
||||
let env = PHEnvironment(variables: ["FOO": "bar"])
|
||||
#expect(env.expand("$FOO") == "bar")
|
||||
}
|
||||
|
||||
@Test func envExpandsEmbeddedReferences() {
|
||||
let env = PHEnvironment(variables: ["HOME": "/Users/tom", "BIN": "/opt/bin"])
|
||||
#expect(env.expand("$HOME/bin:${BIN}/extra") == "/Users/tom/bin:/opt/bin/extra")
|
||||
}
|
||||
|
||||
@Test func envExpandLeavesUnresolvedIntact() {
|
||||
// Unresolved references stay literal instead of being blanked, so a typo
|
||||
// remains visible.
|
||||
let env = PHEnvironment(variables: [:])
|
||||
#expect(env.expand("$MISSING and ${ALSO_MISSING}") == "$MISSING and ${ALSO_MISSING}")
|
||||
}
|
||||
|
||||
@Test func envExpandIgnoresNonIdentifierDollar() {
|
||||
let env = PHEnvironment(variables: ["FOO": "bar"])
|
||||
// A `$` not followed by an identifier name is left untouched.
|
||||
#expect(env.expand("cost: $5 and $FOO") == "cost: $5 and bar")
|
||||
}
|
||||
|
||||
// MARK: - merging
|
||||
|
||||
@Test func envMergingOverridesExistingKeys() {
|
||||
let env = PHEnvironment(variables: ["PATH": "/usr/bin", "HOME": "/u"])
|
||||
let merged = env.merging(["PATH": "/usr/bin:/extra"])
|
||||
#expect(merged.variables["PATH"] == "/usr/bin:/extra")
|
||||
#expect(merged.variables["HOME"] == "/u")
|
||||
}
|
||||
|
||||
@Test func envMergingNilReturnsSameVariables() {
|
||||
let env = PHEnvironment(variables: ["A": "1"])
|
||||
#expect(env.merging(nil).variables == ["A": "1"])
|
||||
}
|
||||
|
||||
// MARK: - [env] value expansion (config load)
|
||||
|
||||
private func makeConfig(env: [String: String]?) -> PHConfig {
|
||||
PHConfig(theme: "default", window: "default", blocks: nil, env: env, monitors: nil)
|
||||
}
|
||||
|
||||
@Test func resolvingEnvExpandsValuesAgainstGivenEnvironment() {
|
||||
// `PATH = "$PATH:/extra"` extends an inherited variable.
|
||||
let config = makeConfig(env: [
|
||||
"PATH": "$PATH:/opt/phbar/bin",
|
||||
"WORKDIR": "${TMPDIR}/phbar",
|
||||
"PLAIN": "literal",
|
||||
])
|
||||
let resolved = config.resolvingEnv(in: PHEnvironment(variables: [
|
||||
"PATH": "/usr/bin",
|
||||
"TMPDIR": "/var/tmp",
|
||||
]))
|
||||
|
||||
#expect(resolved.env?["PATH"] == "/usr/bin:/opt/phbar/bin")
|
||||
#expect(resolved.env?["WORKDIR"] == "/var/tmp/phbar")
|
||||
#expect(resolved.env?["PLAIN"] == "literal")
|
||||
}
|
||||
|
||||
@Test func resolvingEnvDefaultsToProcessEnvironment() {
|
||||
// `$TMPDIR` is set in phbar's launch environment, so this also exercises
|
||||
// real process-env expansion end to end.
|
||||
guard let tmpdir = ProcessInfo.processInfo.environment["TMPDIR"] else { return }
|
||||
let config = makeConfig(env: ["OUT": "$TMPDIR"])
|
||||
let resolved = config.resolvingEnv()
|
||||
#expect(resolved.env?["OUT"] == tmpdir)
|
||||
}
|
||||
|
||||
@Test func resolvingEnvLeavesConfigUntouchedWhenEnvAbsent() {
|
||||
let config = makeConfig(env: nil)
|
||||
#expect(config.resolvingEnv(in: .process).env == nil)
|
||||
}
|
||||
|
||||
// MARK: - @EnvExpanded wrapper
|
||||
|
||||
/// Stand-in Decodable that mirrors how a theme field opts into expansion.
|
||||
private struct Color: Decodable {
|
||||
@EnvExpanded var hex: String
|
||||
}
|
||||
|
||||
@Test func envExpandedResolvesAgainstInjectedEnvironment() throws {
|
||||
let decoder = TOMLDecoder()
|
||||
decoder.userInfo[PHEnvironment.userInfoKey] = PHEnvironment(variables: ["ACCENT": "#ff0000"])
|
||||
|
||||
let color = try decoder.decode(Color.self, from: #"hex = "$ACCENT""#)
|
||||
|
||||
#expect(color.hex == "#ff0000")
|
||||
}
|
||||
|
||||
@Test func envExpandedFallsBackToLaunchEnvironment() throws {
|
||||
// Without injected userInfo the wrapper falls back to phbar's launch
|
||||
// environment (`ProcessInfo`), which is a snapshot taken at process start.
|
||||
guard let path = ProcessInfo.processInfo.environment["PATH"] else { return }
|
||||
|
||||
let color = try TOMLDecoder().decode(Color.self, from: #"hex = "$PATH""#)
|
||||
|
||||
#expect(color.hex == path)
|
||||
}
|
||||
|
||||
@Test func envExpandedLeavesUnresolvedIntact() throws {
|
||||
let color = try TOMLDecoder().decode(Color.self, from: #"hex = "$NEVER_SET""#)
|
||||
|
||||
#expect(color.hex == "$NEVER_SET")
|
||||
}
|
||||
|
||||
// MARK: - Theme integration
|
||||
|
||||
@Test func themeStyleColorExpandsEnvReference() throws {
|
||||
let decoder = TOMLDecoder()
|
||||
decoder.userInfo[PHEnvironment.userInfoKey] = PHEnvironment(variables: ["ACCENT": "#ff0000"])
|
||||
|
||||
let style = try decoder.decode(PHThemeStyleColor.self, from: #"color = "$ACCENT""#)
|
||||
|
||||
#expect(style.color == "#ff0000")
|
||||
}
|
||||
|
||||
@Test func themeTextFontExpandsEnvReference() throws {
|
||||
let decoder = TOMLDecoder()
|
||||
decoder.userInfo[PHEnvironment.userInfoKey] = PHEnvironment(variables: ["FONT": "Comic Code"])
|
||||
|
||||
let text = try decoder.decode(
|
||||
PHThemeText.self,
|
||||
from: """
|
||||
name = "default"
|
||||
font = "$FONT"
|
||||
size = 14
|
||||
weight = "regular"
|
||||
style = "normal"
|
||||
"""
|
||||
)
|
||||
|
||||
#expect(text.fontFamily == "Comic Code")
|
||||
}
|
||||
Reference in New Issue
Block a user