mirror of
https://github.com/rtk-ai/rtk.git
synced 2026-09-19 07:33:17 +08:00
784d347011
`rewritten_head_spellings_match_native_on_non_utf8_files` isolates `CLAUDE_CONFIG_DIR` but reads the ambient `XDG_CONFIG_HOME`, so a config carrying `exclude_commands = ["head", "tail"]` suppresses the rewrite and the exit-code-3 assertion fails. Clean runners have no such config, so the test passes in CI and fails only for the developers most likely to have opted out of these very rewrites. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
176 lines
6.1 KiB
Rust
176 lines
6.1 KiB
Rust
use std::fs;
|
|
use std::io::Write;
|
|
use std::process::{Command, Output, Stdio};
|
|
|
|
fn read_stdin(input: &[u8], args: &[&str]) -> Output {
|
|
let mut child = Command::new(env!("CARGO_BIN_EXE_rtk"))
|
|
.args(["read", "-"])
|
|
.args(args)
|
|
.stdin(Stdio::piped())
|
|
.stdout(Stdio::piped())
|
|
.stderr(Stdio::piped())
|
|
.spawn()
|
|
.expect("run rtk read from stdin");
|
|
child
|
|
.stdin
|
|
.take()
|
|
.expect("piped stdin")
|
|
.write_all(input)
|
|
.expect("write stdin");
|
|
child.wait_with_output().expect("wait for rtk read")
|
|
}
|
|
|
|
#[test]
|
|
fn read_windows_preserve_non_utf8_files() {
|
|
let dir = tempfile::tempdir().expect("create test directory");
|
|
let file = dir.path().join("binary.log");
|
|
fs::write(&file, b"\xff\xfe bad\nline2\nline3\n").expect("write binary file");
|
|
|
|
for (flag, expected) in [
|
|
("--head-lines", b"\xff\xfe bad\nline2\n".as_slice()),
|
|
("--tail-lines", b"line2\nline3\n".as_slice()),
|
|
] {
|
|
let output = Command::new(env!("CARGO_BIN_EXE_rtk"))
|
|
.arg("read")
|
|
.arg(&file)
|
|
.args([flag, "2"])
|
|
.output()
|
|
.expect("run rtk read");
|
|
|
|
assert!(output.status.success(), "{flag}: {:?}", output.stderr);
|
|
assert_eq!(output.stdout, expected, "{flag}");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn read_windows_preserve_binary_boundaries_for_files_and_stdin() {
|
|
let dir = tempfile::tempdir().expect("create test directory");
|
|
let file = dir.path().join("binary.log");
|
|
for input in [
|
|
b"\xff\r\nvalid\n\0\xfe".as_slice(),
|
|
b"\xff\r\nvalid\n\0\xfe\n".as_slice(),
|
|
] {
|
|
fs::write(&file, input).expect("write binary file");
|
|
let last = if input.ends_with(b"\n") {
|
|
b"\0\xfe\n".as_slice()
|
|
} else {
|
|
b"\0\xfe".as_slice()
|
|
};
|
|
for (flag, count, expected) in [
|
|
("--head-lines", "0", b"".as_slice()),
|
|
("--tail-lines", "0", b"".as_slice()),
|
|
("--head-lines", "1", b"\xff\r\n".as_slice()),
|
|
("--tail-lines", "1", last),
|
|
("--head-lines", "99", input),
|
|
("--tail-lines", "99", input),
|
|
] {
|
|
let from_file = Command::new(env!("CARGO_BIN_EXE_rtk"))
|
|
.arg("read")
|
|
.arg(&file)
|
|
.args([flag, count])
|
|
.output()
|
|
.expect("run rtk read");
|
|
let from_stdin = read_stdin(input, &[flag, count]);
|
|
for output in [from_file, from_stdin] {
|
|
assert!(
|
|
output.status.success(),
|
|
"{flag} {count}: {:?}",
|
|
output.stderr
|
|
);
|
|
assert_eq!(output.stdout, expected, "{flag} {count}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn read_windows_accept_invalid_bytes_outside_the_selected_window() {
|
|
for (input, flag) in [
|
|
(b"valid\n\xff\n".as_slice(), "--head-lines"),
|
|
(b"\xff\nvalid\n".as_slice(), "--tail-lines"),
|
|
] {
|
|
let output = read_stdin(input, &[flag, "1"]);
|
|
assert!(output.status.success(), "{flag}: {:?}", output.stderr);
|
|
assert_eq!(output.stdout, b"valid\n");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn read_windows_still_apply_text_filtering_and_line_numbers() {
|
|
let input = b"// comment\nfn alpha() {}\nfn beta() {}\nfn gamma() {}\n";
|
|
for (args, expected) in [
|
|
(
|
|
["--head-lines", "1", "--level", "minimal"].as_slice(),
|
|
"fn alpha() {}\n",
|
|
),
|
|
(
|
|
["--tail-lines", "1", "--level", "minimal"].as_slice(),
|
|
"fn gamma() {}",
|
|
),
|
|
(
|
|
["--head-lines", "1", "--line-numbers"].as_slice(),
|
|
"1 │ // comment\n",
|
|
),
|
|
(
|
|
["--tail-lines", "1", "--line-numbers"].as_slice(),
|
|
"1 │ fn gamma() {}\n",
|
|
),
|
|
] {
|
|
let output = read_stdin(input, args);
|
|
assert!(output.status.success(), "{args:?}: {:?}", output.stderr);
|
|
assert_eq!(output.stdout, expected.as_bytes(), "{args:?}");
|
|
}
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
#[test]
|
|
fn rewritten_head_spellings_match_native_on_non_utf8_files() {
|
|
let dir = tempfile::tempdir().expect("create test directory");
|
|
let claude_dir = dir.path().join(".claude");
|
|
fs::create_dir(&claude_dir).expect("create isolated Claude config directory");
|
|
let config_dir = dir.path().join("config");
|
|
fs::create_dir(&config_dir).expect("create isolated rtk config directory");
|
|
let file = dir.path().join("binary.log");
|
|
fs::write(&file, b"\xff\xfe bad\nline2\nline3\n").expect("write binary file");
|
|
for flags in ["-2", "-n 2", "--lines 2", "--lines=2", ""] {
|
|
let command = format!("head {flags} {}", file.display());
|
|
let rewrite = Command::new(env!("CARGO_BIN_EXE_rtk"))
|
|
.current_dir(dir.path())
|
|
.env("CLAUDE_CONFIG_DIR", &claude_dir)
|
|
.env("XDG_CONFIG_HOME", &config_dir)
|
|
.args(["rewrite", &command])
|
|
.output()
|
|
.expect("rewrite head command");
|
|
assert_eq!(
|
|
rewrite.status.code(),
|
|
Some(3),
|
|
"{command}: {:?}",
|
|
rewrite.stderr
|
|
);
|
|
let rewritten = String::from_utf8(rewrite.stdout).expect("UTF-8 command");
|
|
let count = if flags.is_empty() { "10" } else { "2" };
|
|
assert_eq!(
|
|
rewritten.trim(),
|
|
format!("rtk read {} --head-lines {count}", file.display())
|
|
);
|
|
let actual = Command::new(env!("CARGO_BIN_EXE_rtk"))
|
|
.args(
|
|
rewritten
|
|
.trim()
|
|
.strip_prefix("rtk ")
|
|
.expect("rtk rewrite prefix")
|
|
.split_whitespace(),
|
|
)
|
|
.output()
|
|
.expect("execute rewritten head");
|
|
let native = Command::new("head")
|
|
.args(flags.split_whitespace())
|
|
.arg(&file)
|
|
.output()
|
|
.expect("run native head");
|
|
assert!(native.status.success(), "{command}: {:?}", native.stderr);
|
|
assert_eq!(actual.status.code(), native.status.code(), "{command}");
|
|
assert_eq!(actual.stdout, native.stdout, "{command}");
|
|
}
|
|
}
|