Skip to content

Commit d8e9807

Browse files
committed
test(cli): redact the test temp directory by exact path
`filter_stderr` normalized the per-test temp directory to `TMPDIR` with a regex that guessed the path shape, matching only a `$TMPDIR` directly under `/tmp` or the macOS `/var/folders` location. Under a nix-shell `$TMPDIR` (`/tmp/nix-shell.XXXXXX/...`) it matched nothing, leaving absolute paths in `cli_test_ambiguous_package` and `cli_test_duplicate_lib_name` output. Replace the regex with a literal substitution of the harness's known temp directory - and its canonicalized form, since leo canonicalizes paths before printing them - with `TMPDIR`.
1 parent 7737b3a commit d8e9807

1 file changed

Lines changed: 26 additions & 12 deletions

File tree

crates/leo/tests/integration.rs

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,8 @@ fn run_test(test: &Test, force_rewrite: bool, port: u16) -> Option<String> {
201201
fs::write(&stdout_path, filter_stdout(stdout_utf8).as_bytes()).expect("Failed to write STDOUT");
202202
let stderr_path = test_context_directory.path().join("STDERR");
203203
let stderr_utf8 = std::str::from_utf8(&output.stderr).expect("stderr should be utf8");
204-
fs::write(&stderr_path, filter_stderr(stderr_utf8).as_bytes()).expect("Failed to write STDERR");
204+
fs::write(&stderr_path, filter_stderr(stderr_utf8, test_context_directory.path()).as_bytes())
205+
.expect("Failed to write STDERR");
205206

206207
let exitcode_path = test_context_directory.path().join("EXITCODE");
207208
if let Some(code) = output.status.code() {
@@ -291,26 +292,22 @@ fn filter_stdout(data: &str) -> String {
291292
}
292293

293294
/// Replace strings in the stderr of a Leo execution that we don't need to match exactly.
294-
fn filter_stderr(data: &str) -> String {
295+
fn filter_stderr(data: &str, temp_dir: &Path) -> String {
295296
use regex::Regex;
296297
use std::borrow::Cow;
297298

299+
// Rewrite the test's temp directory to a stable `TMPDIR` placeholder. The
300+
// harness created this directory, so substitute its exact path rather than
301+
// guessing the shape with a regex - `$TMPDIR` varies by environment.
302+
let data = redact_temp_dir(data, temp_dir);
303+
298304
let regexes = [
299305
// Strip ANSI color codes so downstream regexes match cleanly.
300306
(Regex::new(r"\x1b\[[0-9;]*m").unwrap(), ""),
301307
// Match `-->` followed by any path, capture only the filename with line/col
302308
(Regex::new(r"-->\s+.*?/([^/]+\.leo:\d+:\d+)").unwrap(), "--> SOURCE_DIRECTORY/$1"),
303309
// Match ariadne's `╭─[ path:line:col ]` header, normalize the path portion.
304310
(Regex::new(r"╭─\[\s*.*?/([^/]+\.leo:\d+:\d+)\s*\]").unwrap(), "╭─[ SOURCE_DIRECTORY/$1 ]"),
305-
// Normalize tempdir prefixes written by `tempfile::TempDir::new()` so expectations
306-
// are stable across machines and OSes, regardless of surrounding quoting:
307-
// /tmp/.tmpXXX/contents/ (Linux)
308-
// /private/var/folders/XX/XXXX/T/.tmpXXX/contents/ (macOS)
309-
// → TMPDIR/contents/
310-
(
311-
Regex::new(r"(?:/tmp|/private/var/folders/[^/]+/[^/]+/T)/\.tmp[A-Za-z0-9]+/contents/").unwrap(),
312-
"TMPDIR/contents/",
313-
),
314311
// Normalize dynamic devnode ports back to 3030 for stable expectations.
315312
(Regex::new(r"http://localhost:\d+").unwrap(), "http://localhost:3030"),
316313
// snarkVM prints parameter download warnings to stderr on fresh runners.
@@ -323,7 +320,7 @@ fn filter_stderr(data: &str) -> String {
323320
(Regex::new(r"⚠️ Network request failed, retrying in \d+s \(attempt \d+/\d+\)\.\.\.\n").unwrap(), ""),
324321
];
325322

326-
let mut cow = Cow::Borrowed(data);
323+
let mut cow = Cow::Borrowed(data.as_str());
327324
for (regex, replacement) in regexes {
328325
if let Cow::Owned(s) = regex.replace_all(&cow, replacement) {
329326
cow = Cow::Owned(s);
@@ -333,6 +330,23 @@ fn filter_stderr(data: &str) -> String {
333330
cow.into_owned()
334331
}
335332

333+
/// Rewrite every occurrence of the test's temporary directory in `data` to a
334+
/// stable `TMPDIR` placeholder, so expectations don't depend on where `$TMPDIR`
335+
/// points (it varies by environment - e.g. nix-shell uses `/tmp/nix-shell.XXX`).
336+
///
337+
/// Both the directory as created and its canonicalized form are rewritten: Leo
338+
/// canonicalizes paths before printing them, and the canonical form differs from
339+
/// the created path under a symlinked root (e.g. macOS, where `/var/folders/...`
340+
/// resolves to `/private/var/folders/...`). The canonical form is rewritten
341+
/// first since it can contain the created path as a substring.
342+
fn redact_temp_dir(data: &str, temp_dir: &Path) -> String {
343+
let mut out = data.to_owned();
344+
if let Ok(canonical) = temp_dir.canonicalize() {
345+
out = out.replace(&*canonical.to_string_lossy(), "TMPDIR");
346+
}
347+
out.replace(&*temp_dir.to_string_lossy(), "TMPDIR")
348+
}
349+
336350
/// Filter dynamic values in JSON output files to allow comparison across runs.
337351
fn filter_json_file(data: &str) -> String {
338352
use regex::Regex;

0 commit comments

Comments
 (0)