use crate::brain::agent::service::feedback::enrich_metadata;
use serde_json::json;
#[test]
fn bash_failure_appends_cmd_to_snippet() {
let input = json!({ "command": "git rebase main" });
let result = enrich_metadata("bash", Some("Command exited with code 1"), Some(&input));
assert_eq!(
result,
Some("Command exited with code 1 | cmd=git rebase main".to_string())
);
}
#[test]
fn bash_success_appends_cmd_so_rsi_can_aggregate_patterns() {
let input = json!({ "command": "git status" });
let result = enrich_metadata("bash", None, Some(&input));
assert_eq!(result, Some("cmd=git status".to_string()));
}
#[test]
fn bash_with_no_snippet_still_emits_cmd() {
let input = json!({ "command": "docker build ." });
let result = enrich_metadata("bash", None, Some(&input));
assert_eq!(result, Some("cmd=docker build .".to_string()));
}
#[test]
fn non_bash_failure_passes_snippet_through_unchanged() {
let input = json!({ "path": "/tmp/x.pdf" });
let result = enrich_metadata("parse_document", Some("File not found"), Some(&input));
assert_eq!(result, Some("File not found".to_string()));
}
#[test]
fn bash_without_command_field_falls_back_to_snippet() {
let input = json!({ "something_else": "..." });
let result = enrich_metadata("bash", Some("Some error"), Some(&input));
assert_eq!(result, Some("Some error".to_string()));
}
#[test]
fn bash_with_none_input_falls_back_to_snippet() {
let result = enrich_metadata("bash", Some("user_denied_approval"), None);
assert_eq!(result, Some("user_denied_approval".to_string()));
}
#[test]
fn empty_command_string_is_not_appended() {
let input = json!({ "command": "" });
let result = enrich_metadata("bash", Some("error"), Some(&input));
assert_eq!(result, Some("error".to_string()));
}
#[test]
fn very_long_command_is_truncated_to_300_chars() {
let long_cmd = "git push origin main && ".repeat(200); let input = json!({ "command": long_cmd });
let result = enrich_metadata("bash", Some("error"), Some(&input)).unwrap();
assert!(
result.len() <= 312,
"command should be capped at 300 chars; got {} char meta: {}",
result.len(),
&result[..result.len().min(120)]
);
assert!(result.starts_with("error | cmd=git push"));
}
#[test]
fn snippet_with_special_chars_is_preserved() {
let input = json!({ "command": "ls /nonexistent" });
let snippet = "ls: cannot access '/nonexistent': No such file or directory\nexit code: 2";
let result = enrich_metadata("bash", Some(snippet), Some(&input)).unwrap();
assert!(result.contains("No such file or directory"));
assert!(result.contains("cmd=ls /nonexistent"));
assert!(result.contains('\n'));
}
#[test]
fn realistic_git_failure() {
let input = json!({ "command": "git rebase --continue" });
let snippet = "error: could not apply abc1234... fix typo\nhint: Resolve conflicts then run git rebase --continue";
let result = enrich_metadata("bash", Some(snippet), Some(&input)).unwrap();
assert!(result.starts_with("error: could not apply"));
assert!(result.ends_with("cmd=git rebase --continue"));
}
#[test]
fn realistic_python_module_not_found() {
let input = json!({ "command": "python3 -c \"import openpyxl\"" });
let snippet = "ModuleNotFoundError: No module named 'openpyxl'";
let result = enrich_metadata("bash", Some(snippet), Some(&input)).unwrap();
assert!(result.contains("ModuleNotFoundError"));
assert!(result.contains("cmd=python3 -c"));
}
#[test]
fn realistic_timeout() {
let input = json!({ "command": "cargo build --release", "timeout_secs": 60 });
let snippet = "Command timed out after 120 seconds";
let result = enrich_metadata("bash", Some(snippet), Some(&input)).unwrap();
assert!(result.contains("timed out"));
assert!(result.contains("cmd=cargo build --release"));
}
#[test]
fn command_with_unicode_is_preserved() {
let input = json!({ "command": "ls /Users/José/Documents" });
let result = enrich_metadata("bash", Some("not found"), Some(&input)).unwrap();
assert!(result.contains("José"));
}
#[test]
fn non_bash_tool_input_is_ignored_even_if_it_has_command_field() {
let input = json!({ "command": "some_arg" });
let result = enrich_metadata("custom_tool", Some("snip"), Some(&input));
assert_eq!(result, Some("snip".to_string()));
}