use super::*;
use std::fs;
fn workspace() -> tempfile::TempDir {
let dir = tempfile::TempDir::new().expect("temp dir");
let logs = wsb::logs::root(dir.path());
fs::create_dir_all(logs.join("test/2026-01-01")).expect("logs dir");
fs::write(logs.join("test/2026-01-01/wsb.build.log"), "compiling\n").expect("log");
dir
}
#[test]
fn test10237_a_log_inside_the_root_resolves() {
let dir = workspace();
let resolved = resolve_in_logs(
dir.path(),
".wsb/disposable/logs/test/2026-01-01/wsb.build.log",
)
.expect("a log inside the root resolves");
assert!(resolved.ends_with("wsb.build.log"));
}
#[test]
fn test10238_a_log_that_does_not_exist_yet_resolves() {
let dir = workspace();
resolve_in_logs(
dir.path(),
".wsb/disposable/logs/test/2026-01-01/not-yet.log",
)
.expect("a named but unwritten log resolves");
}
#[test]
fn test10239_traversal_out_of_the_logs_root_is_refused() {
let dir = workspace();
fs::write(dir.path().join("secrets.wsbs"), "ciphertext").expect("secret");
let error = resolve_in_logs(
dir.path(),
".wsb/disposable/logs/test/../../../secrets.wsbs",
)
.expect_err("a path climbing out of the logs root is refused");
assert!(
error.contains("not inside the logs root"),
"the refusal says why: {error}"
);
}
#[test]
fn test10240_an_absolute_path_outside_the_root_is_refused() {
let dir = workspace();
resolve_in_logs(dir.path(), "/etc/passwd")
.expect_err("an absolute path outside the logs root is refused");
}
#[test]
fn test10241_a_symlink_pointing_out_of_the_root_is_refused() {
let dir = workspace();
fs::write(dir.path().join("outside.txt"), "not a log").expect("target");
let link = wsb::logs::root(dir.path()).join("test/escape.log");
#[cfg(unix)]
std::os::unix::fs::symlink(dir.path().join("outside.txt"), &link).expect("symlink");
#[cfg(unix)]
{
resolve_in_logs(dir.path(), ".wsb/disposable/logs/test/escape.log")
.expect_err("a symlink out of the logs root is refused");
}
}
#[tokio::test]
async fn test10242_reading_resumes_from_the_offset() {
let dir = workspace();
let path = wsb::logs::root(dir.path()).join("test/2026-01-01/wsb.build.log");
let (text, offset) = read_from(&path, 0).await.expect("first read");
assert_eq!(text, "compiling\n");
let (again, same) = read_from(&path, offset).await.expect("second read");
assert!(again.is_empty(), "nothing was appended, so nothing is read");
assert_eq!(same, offset);
fs::write(&path, "compiling\nlinking\n").expect("append");
let (more, _) = read_from(&path, offset).await.expect("third read");
assert_eq!(more, "linking\n", "only what arrived after the offset");
}
#[tokio::test]
async fn test10243_a_truncated_log_restarts_from_its_beginning() {
let dir = workspace();
let path = wsb::logs::root(dir.path()).join("test/2026-01-01/wsb.build.log");
let (_, offset) = read_from(&path, 0).await.expect("first read");
fs::write(&path, "fresh\n").expect("rewrite shorter");
let (text, _) = read_from(&path, offset).await.expect("after truncation");
assert_eq!(text, "fresh\n");
}