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
54
55
56
57
58
59
60
61
62
63
64
//! Unit tests for [`crate::env_paths`].
use super::*;
/// A set-but-empty variable is unset, not configured.
///
/// `var_os` returns `Some("")` for it, which was taken as a root: the config
/// root became the empty string, every state path turned relative, and the
/// router wrote `server.json` — holding a live `la_sk_` token — into whatever
/// directory the command ran from (issue #340).
#[test]
fn an_empty_variable_reads_as_unset() {
let value = |text: &str| Some(std::ffi::OsString::from(text));
assert_eq!(
from_value(value("/tmp/configured")),
Some(PathBuf::from("/tmp/configured")),
"a real value is still read"
);
assert_eq!(
from_value(value("")),
None,
"an empty value must fall through to the next candidate"
);
assert_eq!(from_value(None), None, "an unset value is unset");
// The point of the fix: empty and absent are now indistinguishable, so an
// `or_else` chain behaves the same either way.
assert_eq!(from_value(value("")), from_value(None));
}
/// A relative root is refused rather than used.
///
/// Whatever combination of variables produced it, a root that is not absolute
/// is a broken environment — and failing loudly beats writing a credential
/// into the process working directory.
#[test]
fn a_relative_root_is_refused_rather_than_written_to() {
// What counts as absolute is platform-specific: a leading slash is enough
// on unix, while Windows wants a drive or a UNC prefix.
let rooted = if cfg!(windows) {
r"C:\ProgramData\router"
} else {
"/var/lib/router"
};
let absolute =
require_absolute(PathBuf::from(rooted), "the state directory").expect("a rooted path");
assert_eq!(absolute, PathBuf::from(rooted));
// Relative under either set of rules. `/var/lib/router` is deliberately
// absent: it is absolute on unix and relative on Windows, so it belongs to
// neither list.
for relative in ["", "link-assistant-router", ".config", "./state", "../up"] {
let refused = require_absolute(PathBuf::from(relative), "the state directory")
.expect_err("a relative root must be refused");
assert!(
refused.contains("relative"),
"the refusal must say why: {refused}"
);
assert!(
refused.contains("XDG_CONFIG_HOME"),
"and name where to look: {refused}"
);
}
}