test(links): a path with spaces is one argument to the file command

expand_file_command_template splits the template into tokens first and
substitutes {path} inside a token, which is what keeps
`/Users/me/My Notes/a.rs` together. Substituting first and splitting
after reads like the same operation and is not — the editor is handed
`/Users/me/My` and `Notes/a.rs` and opens neither.

Nothing pinned that order, and every existing case used a path without a
space, so the invariant that makes the design correct was never exercised.
Paths with spaces are the common case on the platform this ships on:
Application Support, My Documents.

Three shapes: the plain `{path}`, a compound `{path}:{line}:{column}` where
the glue would part company with it too, and a template carrying spaces of
its own, which are still separators — only the substituted value is
protected.

Checked by writing the refactor it guards against: the path comes back as
three arguments.
This commit is contained in:
l0ng-ai
2026-08-23 20:55:02 +08:00
parent 65094a415b
commit 93129f04e2
+38
View File
@@ -7890,6 +7890,44 @@ mod tests {
assert_eq!(argv, vec!["herdr", "/tmp/foo.rs"]);
}
/// A path with a space in it is one argument, not two.
///
/// The template is split into tokens *first* and `{path}` substituted
/// inside a token, which is what keeps `/Users/me/My Notes/a.rs` together.
/// Substituting first and splitting after reads like the same thing and is
/// not: the editor would be handed `/Users/me/My` and `Notes/a.rs` and
/// open neither. Nothing pinned the order, and paths with spaces are the
/// common case on macOS — `Application Support`, `My Documents`.
#[test]
fn a_path_with_spaces_stays_one_argument() {
let spacey = Path::new("/Users/me/My Notes/a file.rs");
let argv = expand_file_command_template("herdr edit {path}", spacey, None, None);
assert_eq!(
argv,
vec!["herdr", "edit", "/Users/me/My Notes/a file.rs"],
"the path was split on its own spaces"
);
// And inside a compound token, where the glue would be lost too.
let argv = expand_file_command_template(
"code --goto {path}:{line}:{column}",
spacey,
Some(42),
Some(7),
);
assert_eq!(
argv,
vec!["code", "--goto", "/Users/me/My Notes/a file.rs:42:7"],
"the line and column parted company with the path"
);
// A template may legitimately carry several spaces of its own; those
// are still separators. Only the substituted value is protected.
let argv = expand_file_command_template("a b {path}", spacey, None, None);
assert_eq!(argv, vec!["a", "b", "/Users/me/My Notes/a file.rs"]);
}
/// #542's contract: a failed open is an `Err` the click site can toast,
/// not a line in a logfile nobody is watching.
#[test]