Files
rtk-ai__rtk/tests/hook_warning_scope_test.rs
Nicolas Le Cam 06d538728c test: cover which commands get the daily hook reminder
Pins both directions: the commands that report hook state themselves stay
quiet, and the filtered commands still warn. Also pins the reason the
suppression is worth having — `maybe_warn` touches the once-a-day marker, so
warning on a meta command would leave the next filtered command silent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-14 01:01:14 +02:00

80 lines
2.6 KiB
Rust

//! The "hook missing/outdated" reminder is a once-a-day nudge, so where it is
//! spent matters: a command the user ran to inspect or install the hook would
//! both duplicate that command's own reporting and burn the daily marker,
//! leaving the next filtered command silent.
//!
//! Unix only: the check resolves the Claude directory through the home
//! directory, and only Unix takes that from `$HOME`.
#![cfg(unix)]
use std::path::Path;
use std::process::Command;
const REMINDER: &str = "No hook installed";
/// Runs `rtk <args>` against a home directory whose Claude config directory
/// exists but registers no hook, and returns stderr.
fn run(home: &Path, args: &[&str]) -> String {
let out = Command::new(env!("CARGO_BIN_EXE_rtk"))
.args(args)
.env("HOME", home)
.env("RTK_DB_PATH", home.join("rtk.db"))
.output()
.expect("run rtk");
String::from_utf8_lossy(&out.stderr).into_owned()
}
fn fresh_home() -> tempfile::TempDir {
let home = tempfile::tempdir().expect("tempdir");
// Absent, the status check reports "not applicable"; present-but-empty is
// what makes a missing hook detectable.
std::fs::create_dir_all(home.path().join(".claude")).expect("claude dir");
home
}
#[test]
fn commands_that_report_hook_state_do_not_repeat_the_reminder() {
for args in [
vec!["init", "-g"],
vec!["verify"],
vec!["verify", "--filter", "cargo"],
vec!["gain"],
] {
let home = fresh_home();
let stderr = run(home.path(), &args);
assert!(
!stderr.contains(&format!("[rtk] /!\\ {REMINDER}")),
"rtk {} must not print the daily reminder: {stderr}",
args.join(" ")
);
}
}
#[test]
fn filtered_commands_still_get_the_reminder() {
for args in [vec!["ls"], vec!["git", "status"]] {
let home = fresh_home();
let stderr = run(home.path(), &args);
assert!(
stderr.contains(REMINDER),
"rtk {} must still warn: {stderr}",
args.join(" ")
);
}
}
#[test]
fn a_meta_command_leaves_the_daily_reminder_for_the_next_filtered_command() {
// The regression this guards: `maybe_warn` touches the once-a-day marker,
// so warning on a meta command would spend the reminder there and leave
// the next filtered command — the one that should have been hooked —
// silent for 24 hours.
let home = fresh_home();
run(home.path(), &["verify", "--filter", "cargo"]);
let stderr = run(home.path(), &["ls"]);
assert!(
stderr.contains(REMINDER),
"the reminder must survive a preceding meta command: {stderr}"
);
}