use expectrl::{Eof, Session};
use std::fs;
use std::process::Command;
use std::time::Duration;
use tempfile::TempDir;
fn patchloom_cmd(cwd: &std::path::Path) -> Command {
let bin = env!("CARGO_BIN_EXE_patchloom");
let mut cmd = Command::new(bin);
cmd.arg("--cwd").arg(cwd);
cmd.arg("--color=never");
cmd
}
fn spawn_pty(cmd: Command) -> Session {
let mut session = Session::spawn(cmd).expect("failed to spawn PTY session");
session.set_expect_timeout(Some(Duration::from_secs(10)));
session
}
fn shell_touch(path: &std::path::Path) -> String {
let path = path.display();
format!("touch '{path}'")
}
#[test]
fn pty_replace_confirm_yes_applies() {
let dir = TempDir::new().unwrap();
let file = dir.path().join("f.txt");
fs::write(&file, "aaa\n").unwrap();
let mut cmd = patchloom_cmd(dir.path());
cmd.args(["replace", "aaa", "--to", "bbb", "--confirm"]);
let mut session = spawn_pty(cmd);
session.expect("aaa").expect("should see old text in diff");
session.expect("Apply?").expect("should see Apply? prompt");
session.send_line("y").expect("failed to send y");
session.expect(Eof).expect("process should exit");
let content = fs::read_to_string(&file).unwrap();
assert_eq!(content, "bbb\n", "file should be modified after confirm y");
}
#[test]
fn pty_replace_confirm_no_does_not_apply() {
let dir = TempDir::new().unwrap();
let file = dir.path().join("f.txt");
fs::write(&file, "aaa\n").unwrap();
let mut cmd = patchloom_cmd(dir.path());
cmd.args(["replace", "aaa", "--to", "bbb", "--confirm"]);
let mut session = spawn_pty(cmd);
session.expect("Apply?").expect("should see Apply? prompt");
session.send_line("n").expect("failed to send n");
session.expect(Eof).expect("process should exit");
let content = fs::read_to_string(&file).unwrap();
assert_eq!(
content, "aaa\n",
"file should NOT be modified after confirm n"
);
}
#[test]
fn pty_replace_confirm_yes_runs_format_command() {
let dir = TempDir::new().unwrap();
let file = dir.path().join("f.txt");
fs::write(&file, "aaa\n").unwrap();
let marker = dir.path().join("format_ran.marker");
let mut cmd = patchloom_cmd(dir.path());
cmd.args([
"replace",
"aaa",
"--to",
"bbb",
"--confirm",
"--format",
&shell_touch(&marker),
]);
let mut session = spawn_pty(cmd);
session.expect("Apply?").expect("should see Apply? prompt");
session.send_line("y").expect("failed to send y");
session.expect(Eof).expect("process should exit");
assert!(
marker.exists(),
"--format command should have run after --confirm y"
);
assert_eq!(fs::read_to_string(&file).unwrap(), "bbb\n");
}
#[test]
fn pty_replace_confirm_no_skips_format_command() {
let dir = TempDir::new().unwrap();
let file = dir.path().join("f.txt");
fs::write(&file, "aaa\n").unwrap();
let marker = dir.path().join("format_ran.marker");
let mut cmd = patchloom_cmd(dir.path());
cmd.args([
"replace",
"aaa",
"--to",
"bbb",
"--confirm",
"--format",
&shell_touch(&marker),
]);
let mut session = spawn_pty(cmd);
session.expect("Apply?").expect("should see Apply? prompt");
session.send_line("n").expect("failed to send n");
session.expect(Eof).expect("process should exit");
assert!(
!marker.exists(),
"--format should NOT run when user declines"
);
}
#[test]
fn pty_append_confirm_yes_runs_format_command() {
let dir = TempDir::new().unwrap();
let file = dir.path().join("f.txt");
fs::write(&file, "line\n").unwrap();
let marker = dir.path().join("format_ran.marker");
let mut cmd = patchloom_cmd(dir.path());
cmd.args([
"append",
"f.txt",
"--content",
"extra\n",
"--confirm",
"--format",
&shell_touch(&marker),
]);
let mut session = spawn_pty(cmd);
session.expect("extra").expect("should see diff output");
session.expect("Apply?").expect("should see Apply? prompt");
session.send_line("y").expect("failed to send y");
session.expect(Eof).expect("process should exit");
assert!(
marker.exists(),
"--format command should have run after append --confirm y"
);
let content = fs::read_to_string(&file).unwrap();
assert!(content.contains("extra"), "content should be appended");
}
#[test]
fn pty_create_confirm_yes_runs_format_command() {
let dir = TempDir::new().unwrap();
let marker = dir.path().join("format_ran.marker");
let mut cmd = patchloom_cmd(dir.path());
cmd.args([
"create",
"new.txt",
"--content",
"hello\n",
"--confirm",
"--format",
&shell_touch(&marker),
]);
let mut session = spawn_pty(cmd);
session.expect("Apply?").expect("should see Apply? prompt");
session.send_line("y").expect("failed to send y");
session.expect(Eof).expect("process should exit");
assert!(
marker.exists(),
"--format command should have run after create --confirm y"
);
assert!(
dir.path().join("new.txt").exists(),
"file should be created"
);
}
#[test]
fn pty_confirm_default_enter_accepts() {
let dir = TempDir::new().unwrap();
let file = dir.path().join("f.txt");
fs::write(&file, "aaa\n").unwrap();
let mut cmd = patchloom_cmd(dir.path());
cmd.args(["replace", "aaa", "--to", "bbb", "--confirm"]);
let mut session = spawn_pty(cmd);
session.expect("Apply?").expect("should see Apply? prompt");
session.send_line("").expect("failed to send enter");
session.expect(Eof).expect("process should exit");
let content = fs::read_to_string(&file).unwrap();
assert_eq!(
content, "bbb\n",
"pressing Enter should accept the default (Y)"
);
}