#![allow(clippy::unwrap_used)]
use crate::repl::debugger::*;
#[test]
fn test_REPL_009_001_print_nonexistent() {
let script = "echo test";
let session = DebugSession::new(script);
assert_eq!(session.get_variable("DOES_NOT_EXIST"), None);
assert_eq!(session.get_variable(""), None);
}
#[test]
fn test_REPL_009_001_list_variables() {
let script = "echo test";
let mut session = DebugSession::new(script);
assert_eq!(session.list_variables(), vec![]);
session.set_variable("PATH", "/usr/bin");
session.set_variable("USER", "bob");
session.set_variable("HOME", "/home/bob");
let vars = session.list_variables();
assert_eq!(vars.len(), 3);
assert_eq!(vars[0], ("HOME", "/home/bob"));
assert_eq!(vars[1], ("PATH", "/usr/bin"));
assert_eq!(vars[2], ("USER", "bob"));
}
#[test]
fn test_REPL_009_001_variable_update() {
let script = "echo test";
let mut session = DebugSession::new(script);
session.set_variable("VERSION", "1.0");
assert_eq!(session.get_variable("VERSION"), Some("1.0"));
session.set_variable("VERSION", "2.0");
assert_eq!(session.get_variable("VERSION"), Some("2.0"));
assert_eq!(session.variable_count(), 1);
}
#[test]
fn test_REPL_009_001_clear_variables() {
let script = "echo test";
let mut session = DebugSession::new(script);
session.set_variable("A", "1");
session.set_variable("B", "2");
session.set_variable("C", "3");
assert_eq!(session.variable_count(), 3);
session.clear_variables();
assert_eq!(session.variable_count(), 0);
assert_eq!(session.list_variables(), vec![]);
assert_eq!(session.get_variable("A"), None);
}
#[test]
fn test_REPL_009_001_variables_persist_across_steps() {
let script = "echo line1\necho line2\necho line3";
let mut session = DebugSession::new(script);
session.set_variable("COUNTER", "0");
session.step();
assert_eq!(session.get_variable("COUNTER"), Some("0"));
session.step();
assert_eq!(session.get_variable("COUNTER"), Some("0"));
session.set_variable("COUNTER", "2");
session.step();
assert_eq!(session.get_variable("COUNTER"), Some("2"));
}
#[test]
fn test_REPL_009_002_env_display() {
let script = "echo test";
let session = DebugSession::new(script);
let path = session.get_env("PATH");
assert!(path.is_some(), "PATH environment variable should exist");
let nonexistent = session.get_env("BASHRS_NONEXISTENT_VAR_12345");
assert_eq!(nonexistent, None);
let env_vars = session.list_env();
assert!(!env_vars.is_empty(), "Should have at least one env var");
let mut sorted = env_vars.clone();
sorted.sort_by_key(|(name, _)| name.clone());
assert_eq!(env_vars, sorted, "Environment variables should be sorted");
}
#[test]
fn test_REPL_009_002_env_filter() {
let script = "echo test";
let session = DebugSession::new(script);
let path_vars = session.filter_env("PATH");
assert!(
!path_vars.is_empty(),
"Should find at least one PATH-related variable"
);
for (name, _) in &path_vars {
assert!(
name.starts_with("PATH"),
"Filtered variable {} should start with PATH",
name
);
}
let empty_filter = session.filter_env("BASHRS_NONEXISTENT_PREFIX");
assert_eq!(
empty_filter.len(),
0,
"Filter with non-matching prefix should return empty"
);
let mut sorted = path_vars.clone();
sorted.sort_by_key(|(name, _)| name.clone());
assert_eq!(path_vars, sorted, "Filtered env vars should be sorted");
}
#[test]
fn test_REPL_009_003_backtrace_single() {
let script = "echo line1\necho line2\necho line3";
let mut session = DebugSession::new(script);
let initial_len = session.call_stack().len();
assert_eq!(initial_len, 1, "Should have just main frame initially");
session.push_frame("function1", 1);
let stack = session.call_stack();
assert_eq!(stack.len(), 2, "Should have main + function1");
let frame = &stack[1];
assert_eq!(frame.name, "function1");
assert_eq!(frame.line, 1);
session.pop_frame();
let final_len = session.call_stack().len();
assert_eq!(final_len, initial_len);
}
#[test]
fn test_REPL_009_003_backtrace_nested() {
let script = "echo test";
let mut session = DebugSession::new(script);
session.push_frame("main", 1);
session.push_frame("func_a", 5);
session.push_frame("func_b", 10);
let stack = session.call_stack();
assert_eq!(
stack.len(),
4,
"Should have <main> + main + func_a + func_b"
);
assert_eq!(stack[1].name, "main");
assert_eq!(stack[1].line, 1);
assert_eq!(stack[2].name, "func_a");
assert_eq!(stack[2].line, 5);
assert_eq!(stack[3].name, "func_b");
assert_eq!(stack[3].line, 10);
session.pop_frame(); let stack2 = session.call_stack();
assert_eq!(stack2.len(), 3);
session.pop_frame(); let stack3 = session.call_stack();
assert_eq!(stack3.len(), 2);
session.pop_frame(); let stack4 = session.call_stack();
assert_eq!(stack4.len(), 1, "Should be back to just <main>");
}
#[test]
fn test_REPL_010_001_compare_at_breakpoint() {
let script = "mkdir /tmp/test";
let session = DebugSession::new(script);
let comparison = session.compare_current_line();
assert!(comparison.is_some(), "Should have comparison for line 1");
let cmp = comparison.unwrap();
assert_eq!(cmp.original, "mkdir /tmp/test");
assert!(
cmp.purified.contains("mkdir") && cmp.purified.contains("-p"),
"Purified should add -p flag, got: {}",
cmp.purified
);
assert!(cmp.differs, "Original and purified should differ");
}
#[test]
fn test_REPL_010_001_compare_diff_highlighting() {
let script = "echo $HOME";
let session = DebugSession::new(script);
let comparison = session.compare_current_line();
assert!(comparison.is_some());
let cmp = comparison.unwrap();
assert_eq!(cmp.original, "echo $HOME");
assert_eq!(cmp.purified, "echo \"$HOME\"");
assert!(cmp.differs);
let diff = session.format_diff_highlighting(&cmp);
assert!(diff.contains("$HOME"), "Diff should show variable");
assert!(
diff.contains("\"$HOME\""),
"Diff should show quoted version"
);
}
#[test]
fn test_REPL_010_002_highlight_mkdir_p() {
let script = "mkdir /tmp/foo";
let session = DebugSession::new(script);
let comparison = session.compare_current_line();
assert!(comparison.is_some(), "Should be able to compare");
let cmp = comparison.unwrap();
assert!(cmp.differs, "Lines should differ");
let highlighted = session.format_diff_highlighting(&cmp);
assert!(
highlighted.contains("mkdir") || highlighted.contains("dirname"),
"Should show mkdir-related content"
);
}
#[test]
fn test_REPL_010_002_highlight_quote() {
let script = "echo $USER";
let session = DebugSession::new(script);
let comparison = session.compare_current_line();
assert!(comparison.is_some(), "Should be able to compare");
let cmp = comparison.unwrap();
assert!(cmp.differs, "Lines should differ");
let highlighted = session.format_diff_highlighting(&cmp);
assert!(highlighted.contains("\""), "Should show quote addition");
assert!(
highlighted.to_lowercase().contains("quot")
|| highlighted.to_lowercase().contains("safe"),
"Should explain quoting: {}",
highlighted
);
}
#[test]
fn test_REPL_010_002_highlight_ln_sf() {
let script = "ln -s /tmp/src /tmp/link";
let session = DebugSession::new(script);
let comparison = session.compare_current_line();
assert!(comparison.is_some(), "Should be able to compare");
let cmp = comparison.unwrap();
if !cmp.differs {
return;
}
let highlighted = session.format_diff_highlighting(&cmp);
assert!(highlighted.contains("ln"), "Should show ln command");
assert!(
highlighted.contains("-") && highlighted.contains("f"),
"Should show flag addition"
);
assert!(
highlighted.to_lowercase().contains("safe")
|| highlighted.to_lowercase().contains("idempot")
|| highlighted.to_lowercase().contains("idem"),
"Should explain transformation: {}",
highlighted
);
}
#[test]
fn test_REPL_010_002_highlight_no_change() {
let script = "echo hello";
let session = DebugSession::new(script);
let comparison = session.compare_current_line();
assert!(comparison.is_some(), "Should be able to compare");
let cmp = comparison.unwrap();
let highlighted = session.format_diff_highlighting(&cmp);
assert!(!highlighted.is_empty(), "Should produce some output");
}
#[test]
fn test_REPL_010_002_highlight_multiple_changes() {
let script = "rm $FILE";
let session = DebugSession::new(script);
let comparison = session.compare_current_line();
assert!(comparison.is_some(), "Should be able to compare");
let cmp = comparison.unwrap();
assert!(cmp.differs, "Lines should differ");
let highlighted = session.format_diff_highlighting(&cmp);
assert!(
highlighted.contains("-f") || highlighted.contains("\""),
"Should show either -f flag or quoting: {}",
highlighted
);
}
#[test]
fn test_REPL_010_003_explain_mkdir_p() {
let script = "mkdir /tmp/foo";
let session = DebugSession::new(script);
let explanation = session.explain_current_line();
assert!(explanation.is_some(), "Should have explanation for mkdir");
let text = explanation.unwrap();
assert!(
text.contains("transform")
|| text.contains("permission")
|| text.contains("idempot")
|| text.contains("idem")
|| text.contains("-p"),
"Should explain transformation: {}",
text
);
}
#[test]
fn test_REPL_010_003_explain_quote() {
let script = "echo $USER";
let session = DebugSession::new(script);
let explanation = session.explain_current_line();
if let Some(text) = explanation {
assert!(
text.contains("quot") || text.contains("safe"),
"Should explain quoting or safety: {}",
text
);
}
}