use rch_common::e2e::{HarnessResult, HookInputFixture, TestHarness, TestHarnessBuilder};
use rch_common::test_guard;
use rch_common::{Classification, TierDecision, classify_command, classify_command_detailed};
use std::path::PathBuf;
use std::process::{Command, Stdio};
use std::time::{Duration, Instant};
fn create_hook_harness(test_name: &str) -> HarnessResult<TestHarness> {
let target_dir = if let Ok(target_dir) = std::env::var("CARGO_TARGET_DIR") {
PathBuf::from(target_dir).join("debug")
} else {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR")
.map(PathBuf::from)
.unwrap_or_else(|_| PathBuf::from("."));
let project_root = manifest_dir.parent().unwrap_or(&manifest_dir);
project_root.join("target/debug")
};
TestHarnessBuilder::new(test_name)
.cleanup_on_success(true)
.cleanup_on_failure(false)
.default_timeout(Duration::from_secs(30))
.rch_binary(target_dir.join("rch"))
.rchd_binary(target_dir.join("rchd"))
.rch_wkr_binary(target_dir.join("rch-wkr"))
.build()
}
#[allow(dead_code)]
fn run_hook_with_input(
harness: &TestHarness,
hook_input: &str,
env_vars: Option<Vec<(&str, &str)>>,
) -> HarnessResult<(i32, String, String, Duration)> {
let start = Instant::now();
let mut cmd = Command::new(&harness.config.rch_binary);
cmd.arg("hook")
.arg("--input-format=json")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.current_dir(harness.test_dir());
if let Some(vars) = env_vars {
for (key, value) in vars {
cmd.env(key, value);
}
}
let mut child = cmd.spawn().map_err(|e| {
rch_common::e2e::HarnessError::ProcessStartFailed(format!("Failed to spawn hook: {}", e))
})?;
if let Some(mut stdin) = child.stdin.take() {
use std::io::Write;
stdin.write_all(hook_input.as_bytes()).ok();
}
let output = child.wait_with_output().map_err(|e| {
rch_common::e2e::HarnessError::ProcessStartFailed(format!("Failed to wait for hook: {}", e))
})?;
let duration = start.elapsed();
Ok((
output.status.code().unwrap_or(-1),
String::from_utf8_lossy(&output.stdout).to_string(),
String::from_utf8_lossy(&output.stderr).to_string(),
duration,
))
}
fn classify_and_log(harness: &TestHarness, command: &str) -> Classification {
let start = Instant::now();
let result = classify_command(command);
let duration = start.elapsed();
harness.logger.log_with_context(
rch_common::e2e::LogLevel::Info,
rch_common::e2e::LogSource::Custom("classify".to_string()),
format!(
"command='{}' is_compilation={} confidence={:.2} kind={:?}",
command, result.is_compilation, result.confidence, result.kind
),
vec![
("duration_us".to_string(), duration.as_micros().to_string()),
("reason".to_string(), result.reason.to_string()),
],
);
result
}
#[test]
fn test_hook_intercepts_cargo_build() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_intercepts_cargo_build").unwrap();
harness
.logger
.info("TEST START: test_hook_intercepts_cargo_build");
let result = classify_and_log(&harness, "cargo build");
harness
.assert(result.is_compilation, "cargo build should be intercepted")
.unwrap();
assert!(
result.confidence >= 0.95,
"cargo build confidence should be >= 0.95"
);
let result = classify_and_log(&harness, "cargo build --release");
harness
.assert(
result.is_compilation,
"cargo build --release should be intercepted",
)
.unwrap();
assert!(result.confidence >= 0.95);
let result = classify_and_log(&harness, "cargo build --target x86_64-unknown-linux-gnu");
harness
.assert(
result.is_compilation,
"cargo build with target should be intercepted",
)
.unwrap();
harness
.logger
.info("TEST PASS: test_hook_intercepts_cargo_build");
harness.mark_passed();
}
#[test]
fn test_hook_intercepts_cargo_test() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_intercepts_cargo_test").unwrap();
harness
.logger
.info("TEST START: test_hook_intercepts_cargo_test");
let result = classify_and_log(&harness, "cargo test");
harness
.assert(result.is_compilation, "cargo test should be intercepted")
.unwrap();
assert!(result.confidence >= 0.95);
let result = classify_and_log(&harness, "cargo test -p my_crate");
harness
.assert(result.is_compilation, "cargo test -p should be intercepted")
.unwrap();
let result = classify_and_log(&harness, "cargo test test_my_function");
harness
.assert(
result.is_compilation,
"cargo test with name should be intercepted",
)
.unwrap();
harness
.logger
.info("TEST PASS: test_hook_intercepts_cargo_test");
harness.mark_passed();
}
#[test]
fn test_hook_intercepts_cargo_check() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_intercepts_cargo_check").unwrap();
harness
.logger
.info("TEST START: test_hook_intercepts_cargo_check");
let result = classify_and_log(&harness, "cargo check");
harness
.assert(result.is_compilation, "cargo check should be intercepted")
.unwrap();
assert!(result.confidence >= 0.90);
harness
.logger
.info("TEST PASS: test_hook_intercepts_cargo_check");
harness.mark_passed();
}
#[test]
fn test_hook_intercepts_rustc() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_intercepts_rustc").unwrap();
harness
.logger
.info("TEST START: test_hook_intercepts_rustc");
let result = classify_and_log(&harness, "rustc main.rs");
harness
.assert(result.is_compilation, "rustc should be intercepted")
.unwrap();
assert!(result.confidence >= 0.95);
harness.logger.info("TEST PASS: test_hook_intercepts_rustc");
harness.mark_passed();
}
#[test]
fn test_hook_intercepts_bun_test() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_intercepts_bun_test").unwrap();
harness
.logger
.info("TEST START: test_hook_intercepts_bun_test");
let result = classify_and_log(&harness, "bun test");
harness
.assert(result.is_compilation, "bun test should be intercepted")
.unwrap();
assert!(result.confidence >= 0.95);
let result = classify_and_log(&harness, "bun test --coverage");
harness
.assert(
result.is_compilation,
"bun test --coverage should be intercepted",
)
.unwrap();
harness
.logger
.info("TEST PASS: test_hook_intercepts_bun_test");
harness.mark_passed();
}
#[test]
fn test_hook_intercepts_bun_typecheck() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_intercepts_bun_typecheck").unwrap();
harness
.logger
.info("TEST START: test_hook_intercepts_bun_typecheck");
let result = classify_and_log(&harness, "bun typecheck");
harness
.assert(result.is_compilation, "bun typecheck should be intercepted")
.unwrap();
assert!(result.confidence >= 0.95);
harness
.logger
.info("TEST PASS: test_hook_intercepts_bun_typecheck");
harness.mark_passed();
}
#[test]
fn test_hook_intercepts_gcc() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_intercepts_gcc").unwrap();
harness.logger.info("TEST START: test_hook_intercepts_gcc");
let result = classify_and_log(&harness, "gcc -o main main.c");
harness
.assert(
result.is_compilation,
"gcc compilation should be intercepted",
)
.unwrap();
assert!(result.confidence >= 0.90);
harness.logger.info("TEST PASS: test_hook_intercepts_gcc");
harness.mark_passed();
}
#[test]
fn test_hook_intercepts_make() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_intercepts_make").unwrap();
harness.logger.info("TEST START: test_hook_intercepts_make");
let result = classify_and_log(&harness, "make -j8");
harness
.assert(result.is_compilation, "make -j8 should be intercepted")
.unwrap();
assert!(result.confidence >= 0.85);
harness.logger.info("TEST PASS: test_hook_intercepts_make");
harness.mark_passed();
}
#[test]
fn test_hook_intercepts_cmake_build() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_intercepts_cmake_build").unwrap();
harness
.logger
.info("TEST START: test_hook_intercepts_cmake_build");
let result = classify_and_log(&harness, "cmake --build .");
harness
.assert(result.is_compilation, "cmake --build should be intercepted")
.unwrap();
assert!(result.confidence >= 0.85);
harness
.logger
.info("TEST PASS: test_hook_intercepts_cmake_build");
harness.mark_passed();
}
#[test]
fn test_hook_ignores_non_compilation() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_ignores_non_compilation").unwrap();
harness
.logger
.info("TEST START: test_hook_ignores_non_compilation");
let result = classify_and_log(&harness, "ls -la");
harness
.assert(!result.is_compilation, "ls should NOT be intercepted")
.unwrap();
let result = classify_and_log(&harness, "cd /tmp");
harness
.assert(!result.is_compilation, "cd should NOT be intercepted")
.unwrap();
let result = classify_and_log(&harness, "echo hello");
harness
.assert(!result.is_compilation, "echo should NOT be intercepted")
.unwrap();
let result = classify_and_log(&harness, "cat file.txt");
harness
.assert(!result.is_compilation, "cat should NOT be intercepted")
.unwrap();
let result = classify_and_log(&harness, "git status");
harness
.assert(!result.is_compilation, "git should NOT be intercepted")
.unwrap();
harness
.logger
.info("TEST PASS: test_hook_ignores_non_compilation");
harness.mark_passed();
}
#[test]
fn test_hook_offloads_benign_piped_commands() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_offloads_benign_piped").unwrap();
harness
.logger
.info("TEST START: test_hook_offloads_benign_piped_commands");
let result = classify_and_log(&harness, "cargo build | tee log");
harness
.assert(
result.is_compilation,
"cargo build piped into tee should be intercepted",
)
.unwrap();
assert_eq!(
result.extracted_command.as_deref(),
Some("cargo build | tee log")
);
let result = classify_and_log(&harness, "cargo build 2>&1 | grep error");
harness
.assert(
result.is_compilation,
"cargo build piped into grep should be intercepted",
)
.unwrap();
assert_eq!(
result.extracted_command.as_deref(),
Some("cargo build 2>&1 | grep error")
);
let result = classify_and_log(&harness, "bun test | grep PASS");
harness
.assert(
result.is_compilation,
"bun test piped into grep should be intercepted",
)
.unwrap();
assert_eq!(
result.extracted_command.as_deref(),
Some("bun test | grep PASS")
);
let result = classify_and_log(&harness, "cargo build | xargs rm");
harness
.assert(
!result.is_compilation,
"cargo build piped into xargs must not be intercepted",
)
.unwrap();
harness
.logger
.info("TEST PASS: test_hook_offloads_benign_piped_commands");
harness.mark_passed();
}
#[test]
fn test_hook_offloads_output_redirected_commands() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_offloads_output_redirected").unwrap();
harness
.logger
.info("TEST START: test_hook_offloads_output_redirected_commands");
let result = classify_and_log(&harness, "cargo build > output.txt");
harness
.assert(
result.is_compilation,
"stdout-redirected cargo build should be intercepted",
)
.unwrap();
assert_eq!(
result.extracted_command.as_deref(),
Some("cargo build > output.txt")
);
let result = classify_and_log(&harness, "cargo build 2> errors.txt");
harness
.assert(
result.is_compilation,
"stderr-redirected cargo build should be intercepted",
)
.unwrap();
assert_eq!(
result.extracted_command.as_deref(),
Some("cargo build 2> errors.txt")
);
let result = classify_and_log(&harness, "cargo build > out.txt 2>&1");
harness
.assert(
result.is_compilation,
"combined output redirect should be intercepted",
)
.unwrap();
assert_eq!(
result.extracted_command.as_deref(),
Some("cargo build > out.txt 2>&1")
);
let result = classify_and_log(&harness, "cargo build < input.txt");
harness
.assert(
!result.is_compilation,
"input-redirected cargo build must not be intercepted",
)
.unwrap();
harness
.logger
.info("TEST PASS: test_hook_offloads_output_redirected_commands");
harness.mark_passed();
}
#[test]
fn test_hook_offloads_background_commands() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_offloads_background").unwrap();
harness
.logger
.info("TEST START: test_hook_offloads_background_commands");
let result = classify_and_log(&harness, "cargo build &");
harness
.assert(
result.is_compilation,
"backgrounded cargo build should be intercepted",
)
.unwrap();
assert_eq!(result.extracted_command.as_deref(), Some("cargo build &"));
let result = classify_and_log(&harness, "bun test &");
harness
.assert(
result.is_compilation,
"backgrounded bun test should be intercepted",
)
.unwrap();
assert_eq!(result.extracted_command.as_deref(), Some("bun test &"));
let result = classify_and_log(&harness, "cargo build & echo done");
harness
.assert(
!result.is_compilation,
"backgrounded cargo build followed by another command must not be intercepted",
)
.unwrap();
harness
.logger
.info("TEST PASS: test_hook_offloads_background_commands");
harness.mark_passed();
}
#[test]
fn test_hook_handles_chained_commands() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_handles_chained").unwrap();
harness
.logger
.info("TEST START: test_hook_handles_chained_commands");
let result = classify_and_log(&harness, "cargo build && cargo test");
harness
.assert(
result.is_compilation,
"&& chained commands with compilation suffix should be accepted",
)
.unwrap();
assert!(result.reason.contains("compound"));
let result = classify_and_log(&harness, "cargo build && echo done");
harness
.assert(
!result.is_compilation,
"&& chained commands with non-compilation suffix should be rejected",
)
.unwrap();
let result = classify_and_log(&harness, "cargo build; cargo test");
harness
.assert(
!result.is_compilation,
"; chained commands should be rejected",
)
.unwrap();
assert!(result.reason.contains("chained"));
let result = classify_and_log(&harness, "cargo build || echo failed");
harness
.assert(
!result.is_compilation,
"|| chained commands should be rejected",
)
.unwrap();
assert!(result.reason.contains("chained"));
harness
.logger
.info("TEST PASS: test_hook_handles_chained_commands");
harness.mark_passed();
}
#[test]
fn test_hook_ignores_cargo_fmt() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_ignores_cargo_fmt").unwrap();
harness
.logger
.info("TEST START: test_hook_ignores_cargo_fmt");
let result = classify_and_log(&harness, "cargo fmt");
harness
.assert(
!result.is_compilation,
"cargo fmt should NOT be intercepted",
)
.unwrap();
assert!(
result.reason.contains("never-intercept"),
"Should match never-intercept pattern"
);
harness
.logger
.info("TEST PASS: test_hook_ignores_cargo_fmt");
harness.mark_passed();
}
#[test]
fn test_hook_ignores_bun_install() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_ignores_bun_install").unwrap();
harness
.logger
.info("TEST START: test_hook_ignores_bun_install");
let result = classify_and_log(&harness, "bun install");
harness
.assert(
!result.is_compilation,
"bun install should NOT be intercepted",
)
.unwrap();
let result = classify_and_log(&harness, "bun add lodash");
harness
.assert(!result.is_compilation, "bun add should NOT be intercepted")
.unwrap();
let result = classify_and_log(&harness, "bun run dev");
harness
.assert(!result.is_compilation, "bun run should NOT be intercepted")
.unwrap();
harness
.logger
.info("TEST PASS: test_hook_ignores_bun_install");
harness.mark_passed();
}
#[test]
fn test_hook_ignores_bun_watch_mode() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_ignores_bun_watch").unwrap();
harness
.logger
.info("TEST START: test_hook_ignores_bun_watch_mode");
let result = classify_and_log(&harness, "bun test --watch");
harness
.assert(
!result.is_compilation,
"bun test --watch should NOT be intercepted",
)
.unwrap();
assert!(
result.reason.contains("interactive"),
"Should indicate interactive mode"
);
let result = classify_and_log(&harness, "bun typecheck --watch");
harness
.assert(
!result.is_compilation,
"bun typecheck --watch should NOT be intercepted",
)
.unwrap();
harness
.logger
.info("TEST PASS: test_hook_ignores_bun_watch_mode");
harness.mark_passed();
}
#[test]
fn test_hook_timing_budget() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_timing_budget").unwrap();
harness.logger.info("TEST START: test_hook_timing_budget");
let commands = [
"ls -la",
"echo hello",
"cargo build",
"cargo test --release",
"bun test",
"gcc -o main main.c",
"make -j8",
"git status",
"npm install",
"cd /tmp",
];
let mut non_compilation_times: Vec<f64> = Vec::new();
let mut compilation_times: Vec<f64> = Vec::new();
for _ in 0..10 {
for cmd in &commands {
let start = Instant::now();
let result = classify_command(cmd);
let duration_ms = start.elapsed().as_secs_f64() * 1000.0;
if result.is_compilation {
compilation_times.push(duration_ms);
} else {
non_compilation_times.push(duration_ms);
}
}
}
non_compilation_times.sort_by(|a, b| a.partial_cmp(b).unwrap());
let p99_idx = (non_compilation_times.len() as f64 * 0.99) as usize;
let p99_non_compilation = non_compilation_times
.get(p99_idx.min(non_compilation_times.len() - 1))
.copied()
.unwrap_or(0.0);
compilation_times.sort_by(|a, b| a.partial_cmp(b).unwrap());
let p99_idx = (compilation_times.len() as f64 * 0.99) as usize;
let p99_compilation = compilation_times
.get(p99_idx.min(compilation_times.len() - 1))
.copied()
.unwrap_or(0.0);
harness.logger.log_with_context(
rch_common::e2e::LogLevel::Info,
rch_common::e2e::LogSource::Custom("timing".to_string()),
format!(
"TIMING: non_compilation_p99={:.3}ms compilation_p99={:.3}ms",
p99_non_compilation, p99_compilation
),
vec![
(
"non_compilation_count".to_string(),
non_compilation_times.len().to_string(),
),
(
"compilation_count".to_string(),
compilation_times.len().to_string(),
),
],
);
assert!(
p99_non_compilation < 5.0,
"Non-compilation P99 {:.3}ms should be < 5ms",
p99_non_compilation
);
assert!(
p99_compilation < 5.0,
"Compilation P99 {:.3}ms should be < 5ms",
p99_compilation
);
harness.logger.info(format!(
"TEST PASS: test_hook_timing_budget (non_comp_p99={:.3}ms, comp_p99={:.3}ms)",
p99_non_compilation, p99_compilation
));
harness.mark_passed();
}
#[test]
fn test_hook_classification_details() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_classification_details").unwrap();
harness
.logger
.info("TEST START: test_hook_classification_details");
let detailed = classify_command_detailed("cargo build --release");
assert!(detailed.tiers.len() >= 4, "Should have at least 4 tiers");
let tier0 = detailed.tiers.iter().find(|t| t.tier == 0).unwrap();
assert_eq!(tier0.decision, TierDecision::Pass, "Tier 0 should pass");
let tier1 = detailed.tiers.iter().find(|t| t.tier == 1).unwrap();
assert_eq!(tier1.decision, TierDecision::Pass, "Tier 1 should pass");
let tier2 = detailed.tiers.iter().find(|t| t.tier == 2).unwrap();
assert_eq!(tier2.decision, TierDecision::Pass, "Tier 2 should pass");
let tier3 = detailed.tiers.iter().find(|t| t.tier == 3).unwrap();
assert_eq!(tier3.decision, TierDecision::Pass, "Tier 3 should pass");
assert!(detailed.classification.is_compilation);
assert!(detailed.classification.confidence >= 0.95);
harness
.logger
.info("TEST PASS: test_hook_classification_details");
harness.mark_passed();
}
#[test]
fn test_hook_classification_details_piped_rejection() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_classification_details_piped").unwrap();
harness
.logger
.info("TEST START: test_hook_classification_details_piped_rejection");
let detailed = classify_command_detailed("cargo build | xargs rm");
let tier1 = detailed.tiers.iter().find(|t| t.tier == 1).unwrap();
assert_eq!(
tier1.decision,
TierDecision::Reject,
"Tier 1 should reject pipe into non-pager command"
);
assert!(
tier1.reason.contains("piped"),
"Reason should mention piped"
);
assert!(!detailed.classification.is_compilation);
let offloaded = classify_command_detailed("cargo build | tee log.txt");
assert!(offloaded.classification.is_compilation);
assert_eq!(
offloaded.classification.extracted_command.as_deref(),
Some("cargo build | tee log.txt")
);
harness
.logger
.info("TEST PASS: test_hook_classification_details_piped_rejection");
harness.mark_passed();
}
#[test]
fn test_hook_classification_details_never_intercept() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_classification_details_never_intercept").unwrap();
harness
.logger
.info("TEST START: test_hook_classification_details_never_intercept");
let detailed = classify_command_detailed("cargo fmt");
let tier3 = detailed.tiers.iter().find(|t| t.tier == 3).unwrap();
assert_eq!(
tier3.decision,
TierDecision::Reject,
"Tier 3 should reject cargo fmt"
);
assert!(
tier3.reason.contains("never-intercept"),
"Reason should mention never-intercept"
);
assert!(!detailed.classification.is_compilation);
harness
.logger
.info("TEST PASS: test_hook_classification_details_never_intercept");
harness.mark_passed();
}
#[test]
fn test_hook_wrapped_commands() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_wrapped_commands").unwrap();
harness
.logger
.info("TEST START: test_hook_wrapped_commands");
let result = classify_and_log(&harness, "time cargo build");
harness
.assert(
result.is_compilation,
"time cargo build should be intercepted",
)
.unwrap();
let result = classify_and_log(&harness, "sudo cargo check");
harness
.assert(
result.is_compilation,
"sudo cargo check should be intercepted",
)
.unwrap();
let result = classify_and_log(&harness, "env RUST_BACKTRACE=1 cargo test");
harness
.assert(
result.is_compilation,
"env-wrapped cargo test should be intercepted",
)
.unwrap();
harness.logger.info("TEST PASS: test_hook_wrapped_commands");
harness.mark_passed();
}
#[test]
fn test_hook_input_fixture_format() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_input_fixture").unwrap();
harness
.logger
.info("TEST START: test_hook_input_fixture_format");
let input = HookInputFixture::cargo_build();
let json = input.to_json();
assert!(json.contains("\"tool_name\": \"Bash\""));
assert!(json.contains("\"command\": \"cargo build\""));
let input = HookInputFixture::custom("cargo test --release");
let json = input.to_json();
assert!(json.contains("\"command\": \"cargo test --release\""));
harness
.logger
.info("TEST PASS: test_hook_input_fixture_format");
harness.mark_passed();
}
#[test]
fn test_hook_env_rch_disabled() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_env_disabled").unwrap();
harness
.logger
.info("TEST START: test_hook_env_rch_disabled");
let result = classify_command("cargo build");
assert!(
result.is_compilation,
"Classification should work regardless of RCH_ENABLED"
);
harness.logger.info("TEST PASS: test_hook_env_rch_disabled");
harness.mark_passed();
}
#[test]
fn test_hook_empty_command() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_empty_command").unwrap();
harness.logger.info("TEST START: test_hook_empty_command");
let result = classify_command("");
assert!(
!result.is_compilation,
"Empty command should not be intercepted"
);
assert!(
result.reason.contains("empty"),
"Reason should mention empty"
);
let result = classify_command(" ");
assert!(
!result.is_compilation,
"Whitespace-only command should not be intercepted"
);
harness.logger.info("TEST PASS: test_hook_empty_command");
harness.mark_passed();
}
#[test]
fn test_hook_subshell_capture() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_subshell_capture").unwrap();
harness
.logger
.info("TEST START: test_hook_subshell_capture");
let result = classify_command("cargo build $(echo src/)");
assert!(
!result.is_compilation,
"Subshell capture should not be intercepted"
);
assert!(
result.reason.contains("subshell"),
"Reason should mention subshell"
);
let result = classify_command("cargo build `echo flags`");
assert!(
!result.is_compilation,
"Backtick subshell should not be intercepted"
);
harness.logger.info("TEST PASS: test_hook_subshell_capture");
harness.mark_passed();
}
#[test]
fn test_hook_version_checks_not_intercepted() {
let _guard = test_guard!();
let harness = create_hook_harness("hook_version_checks").unwrap();
harness
.logger
.info("TEST START: test_hook_version_checks_not_intercepted");
let result = classify_command("cargo --version");
assert!(
!result.is_compilation,
"cargo --version should not be intercepted"
);
let result = classify_command("rustc --version");
assert!(
!result.is_compilation,
"rustc --version should not be intercepted"
);
let result = classify_command("gcc --version");
assert!(
!result.is_compilation,
"gcc --version should not be intercepted"
);
let result = classify_command("bun --version");
assert!(
!result.is_compilation,
"bun --version should not be intercepted"
);
harness
.logger
.info("TEST PASS: test_hook_version_checks_not_intercepted");
harness.mark_passed();
}