use super::*;
fn with_command(mut ctx: TestContext, name: &str, command: &str, key: char) -> TestContext {
let config = ctx.config();
config
.general
.commands
.insert(name.to_owned(), command.to_owned());
config
.general
.diff_renderer
.feature_keys
.insert(name.to_owned(), key);
ctx
}
#[test]
fn a_command_key_runs_the_command_on_the_commit_under_the_cursor() {
let ctx = setup_clone!();
commit(&ctx.dir, "a", "");
let mut ctx = with_command(ctx, "record", "echo {commit} > recorded", 'o');
let mut app = ctx.init_app();
ctx.update(&mut app, keys("llo"));
let head = run(&ctx.dir, &["git", "rev-parse", "HEAD"]);
assert_eq!(
fs::read_to_string(ctx.dir.join("recorded")).unwrap(),
head,
"{}",
ctx.redact_buffer()
);
}
#[test]
fn a_command_key_runs_the_command_on_the_file_under_the_cursor() {
let ctx = setup_clone!();
fs::write(ctx.dir.join("a file"), "").unwrap();
let mut ctx = with_command(ctx, "record", "echo {file} > recorded", 'o');
let mut app = ctx.init_app();
ctx.update(&mut app, keys("/a file<enter>o"));
assert_eq!(
fs::read_to_string(ctx.dir.join("recorded")).unwrap(),
"a file\n",
"{}",
ctx.redact_buffer()
);
}
#[test]
fn a_command_needing_a_commit_is_not_run_off_one() {
let ctx = setup_clone!();
let mut ctx = with_command(ctx, "record", "echo {commit} > recorded", 'o');
let mut app = ctx.init_app();
ctx.update(&mut app, keys("o"));
assert!(!ctx.dir.join("recorded").exists());
assert!(
ctx.redact_buffer().contains("{commit}"),
"{}",
ctx.redact_buffer()
);
}
#[test]
fn the_feature_list_lists_commands() {
let ctx = setup_clone!();
let mut ctx = with_command(ctx, "record", "echo {commit} > recorded", 'o');
let mut app = ctx.init_app();
ctx.update(&mut app, keys("H"));
assert!(
ctx.redact_buffer().contains("o record"),
"{}",
ctx.redact_buffer()
);
}
#[test]
fn a_failing_command_shows_its_stderr_and_the_command_as_written() {
let ctx = setup_clone!();
commit(&ctx.dir, "a", "");
let mut ctx = with_command(ctx, "fail", "echo {commit} oops >&2; exit 3", 'o');
let mut app = ctx.init_app();
ctx.update(&mut app, keys("llo"));
let head = run(&ctx.dir, &["git", "rev-parse", "HEAD"]);
let head = head.trim();
let buffer = ctx.redact_buffer();
let rows: Vec<&str> = buffer
.lines()
.skip_while(|row| !row.starts_with('!'))
.take(4)
.map(str::trim_end)
.map(|row| row.trim_end_matches('|').trim_end())
.collect();
assert_eq!(
rows,
[
format!("! echo {head} oops >&2; exit 3"),
" exit code: 3".to_owned(),
" stderr:".to_owned(),
format!(" {head} oops"),
],
"{buffer}"
);
}
#[test]
fn a_command_key_runs_the_command_on_the_git_command_shown() {
let ctx = setup_clone!();
let mut ctx = with_command(ctx, "record", "echo {command} > recorded", 'o');
let mut app = ctx.init_app();
ctx.update(&mut app, keys("llo"));
let recorded = fs::read_to_string(ctx.dir.join("recorded")).unwrap_or_default();
assert!(recorded.starts_with("git log"), "{recorded:?}");
}
#[test]
fn a_command_gets_the_width_and_features_gitu_draws_with() {
let ctx = setup_clone!();
let mut ctx = with_command(
ctx,
"record",
r#"printf '%s %s' "$COLUMNS" "$DELTA_FEATURES" > recorded"#,
'o',
);
let mut app = ctx.init_app();
ctx.update(&mut app, keys("So"));
let recorded = fs::read_to_string(ctx.dir.join("recorded")).unwrap_or_default();
assert!(recorded.starts_with("78 "), "{recorded:?}");
assert!(recorded.contains("side-by-side"), "{recorded:?}");
}
#[test]
fn a_command_writing_much_output_finishes() {
let ctx = setup_clone!();
let mut ctx = with_command(
ctx,
"write",
"yes | head -c 1000000 & w=$!; \
(sleep 5; kill $w) >/dev/null 2>&1 & \
wait $w && touch finished",
'o',
);
let mut app = ctx.init_app();
ctx.update(&mut app, keys("o"));
assert!(ctx.dir.join("finished").exists(), "{}", ctx.redact_buffer());
}