use crate::common::harness::{EditorTestHarness, HarnessOptions};
use crossterm::event::{KeyCode, KeyModifiers};
use fresh::config::Config;
use tempfile::TempDir;
fn run_command(harness: &mut EditorTestHarness, command_name: &str) {
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text(command_name).unwrap();
harness.render().unwrap();
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
harness.render().unwrap();
}
#[test]
fn test_toggle_comment_rust_prefix() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("test.rs");
std::fs::write(&file_path, "fn main() {\n println!(\"hello\");\n}").unwrap();
let config = Config::default();
let mut harness =
EditorTestHarness::create(80, 24, HarnessOptions::new().with_config(config)).unwrap();
harness.open_file(&file_path).unwrap();
harness.render().unwrap();
run_command(&mut harness, "Toggle Comment");
let content = harness.get_buffer_content().unwrap();
assert!(
content.starts_with("// fn main()"),
"Rust files should use // for comments. Got: {:?}",
content
);
}
#[test]
fn test_toggle_comment_python_prefix() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("test.py");
std::fs::write(&file_path, "def main():\n print(\"hello\")\n").unwrap();
let config = Config::default();
let mut harness =
EditorTestHarness::create(80, 24, HarnessOptions::new().with_config(config)).unwrap();
harness.open_file(&file_path).unwrap();
harness.render().unwrap();
run_command(&mut harness, "Toggle Comment");
let content = harness.get_buffer_content().unwrap();
assert!(
content.starts_with("# def main()"),
"Python files should use # for comments. Got: {:?}",
content
);
}
#[test]
fn test_toggle_comment_shell_prefix() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("test.sh");
std::fs::write(&file_path, "echo hello\n").unwrap();
let config = Config::default();
let mut harness =
EditorTestHarness::create(80, 24, HarnessOptions::new().with_config(config)).unwrap();
harness.open_file(&file_path).unwrap();
harness.render().unwrap();
run_command(&mut harness, "Toggle Comment");
let content = harness.get_buffer_content().unwrap();
assert!(
content.starts_with("# echo"),
"Shell files should use # for comments. Got: {:?}",
content
);
}
#[test]
fn test_toggle_comment_preserves_selection() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("test.rs");
std::fs::write(&file_path, "line1\nline2\nline3\nline4").unwrap();
let config = Config::default();
let mut harness =
EditorTestHarness::create(80, 24, HarnessOptions::new().with_config(config)).unwrap();
harness.open_file(&file_path).unwrap();
harness.render().unwrap();
harness.send_key(KeyCode::Home, KeyModifiers::NONE).unwrap();
harness.render().unwrap();
harness
.send_key(KeyCode::Down, KeyModifiers::SHIFT)
.unwrap();
harness
.send_key(KeyCode::Down, KeyModifiers::SHIFT)
.unwrap();
harness.render().unwrap();
let cursor_before = *harness.editor().active_state().cursors.primary();
assert!(
cursor_before.selection_range().is_some(),
"Should have selection before toggle comment"
);
let selection_before = cursor_before.selection_range().unwrap();
let selection_len_before = selection_before.end - selection_before.start;
run_command(&mut harness, "Toggle Comment");
let content = harness.get_buffer_content().unwrap();
assert!(
content.starts_with("// line1\n// line2"),
"First two lines should be commented. Got: {:?}",
content
);
let cursor_after = *harness.editor().active_state().cursors.primary();
assert!(
cursor_after.selection_range().is_some(),
"Selection should be preserved after toggle comment"
);
let selection_after = cursor_after.selection_range().unwrap();
let selection_len_after = selection_after.end - selection_after.start;
assert!(
selection_len_after > selection_len_before,
"Selection should have grown after adding comments. Before: {}, After: {}",
selection_len_before,
selection_len_after
);
}
#[test]
fn test_toggle_uncomment_preserves_selection() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("test.rs");
std::fs::write(&file_path, "// line1\n// line2\n// line3\nline4").unwrap();
let config = Config::default();
let mut harness =
EditorTestHarness::create(80, 24, HarnessOptions::new().with_config(config)).unwrap();
harness.open_file(&file_path).unwrap();
harness.render().unwrap();
harness.send_key(KeyCode::Home, KeyModifiers::NONE).unwrap();
harness.render().unwrap();
harness
.send_key(KeyCode::Down, KeyModifiers::SHIFT)
.unwrap();
harness
.send_key(KeyCode::Down, KeyModifiers::SHIFT)
.unwrap();
harness.render().unwrap();
let cursor_before = *harness.editor().active_state().cursors.primary();
assert!(
cursor_before.selection_range().is_some(),
"Should have selection before toggle comment"
);
run_command(&mut harness, "Toggle Comment");
let content = harness.get_buffer_content().unwrap();
assert!(
content.starts_with("line1\nline2"),
"First two lines should be uncommented. Got: {:?}",
content
);
let cursor_after = *harness.editor().active_state().cursors.primary();
assert!(
cursor_after.selection_range().is_some(),
"Selection should be preserved after toggle uncomment"
);
}
#[test]
fn test_toggle_comment_roundtrip_with_selection() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("test.rs");
let original_content = "line1\nline2\nline3";
std::fs::write(&file_path, original_content).unwrap();
let config = Config::default();
let mut harness =
EditorTestHarness::create(80, 24, HarnessOptions::new().with_config(config)).unwrap();
harness.open_file(&file_path).unwrap();
harness.render().unwrap();
harness
.send_key(KeyCode::Char('a'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
run_command(&mut harness, "Toggle Comment");
let content = harness.get_buffer_content().unwrap();
assert!(
content.contains("// line1")
&& content.contains("// line2")
&& content.contains("// line3"),
"All lines should be commented. Got: {:?}",
content
);
harness
.send_key(KeyCode::Char('a'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
run_command(&mut harness, "Toggle Comment");
let content = harness.get_buffer_content().unwrap();
assert_eq!(
content, original_content,
"After comment/uncomment roundtrip, content should match original. Got: {:?}",
content
);
}
#[test]
fn test_toggle_comment_single_line_no_newline() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("test.c");
std::fs::write(&file_path, "int main() {}").unwrap();
let config = Config::default();
let mut harness =
EditorTestHarness::create(80, 24, HarnessOptions::new().with_config(config)).unwrap();
harness.open_file(&file_path).unwrap();
harness.render().unwrap();
harness
.send_key(KeyCode::Char('a'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
let cursor = *harness.editor().active_state().cursors.primary();
assert!(
cursor.selection_range().is_some(),
"Should have selection after Ctrl+A"
);
run_command(&mut harness, "Toggle Comment");
let content = harness.get_buffer_content().unwrap();
assert!(
content.starts_with("// int main()"),
"C file should be commented with //. Got: {:?}",
content
);
}
#[test]
fn test_toggle_comment_yaml_prefix() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("test.yaml");
std::fs::write(&file_path, "key: value\nnested:\n child: 123").unwrap();
let config = Config::default();
let mut harness =
EditorTestHarness::create(80, 24, HarnessOptions::new().with_config(config)).unwrap();
harness.open_file(&file_path).unwrap();
harness.render().unwrap();
run_command(&mut harness, "Toggle Comment");
let content = harness.get_buffer_content().unwrap();
assert!(
content.starts_with("# key: value"),
"YAML files should use # for comments. Got: {:?}",
content
);
}
#[test]
fn test_toggle_comment_yml_prefix() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("config.yml");
std::fs::write(&file_path, "server:\n port: 8080").unwrap();
let config = Config::default();
let mut harness =
EditorTestHarness::create(80, 24, HarnessOptions::new().with_config(config)).unwrap();
harness.open_file(&file_path).unwrap();
harness.render().unwrap();
run_command(&mut harness, "Toggle Comment");
let content = harness.get_buffer_content().unwrap();
assert!(
content.starts_with("# server:"),
"YML files should use # for comments. Got: {:?}",
content
);
}
#[test]
fn test_toggle_comment_selection_at_buffer_end() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("test.rs");
std::fs::write(&file_path, "fn foo() {}\nfn bar() {}").unwrap();
let config = Config::default();
let mut harness =
EditorTestHarness::create(80, 24, HarnessOptions::new().with_config(config)).unwrap();
harness.open_file(&file_path).unwrap();
harness.render().unwrap();
harness
.send_key(KeyCode::Char('a'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
run_command(&mut harness, "Toggle Comment");
let content = harness.get_buffer_content().unwrap();
assert!(
content.contains("// fn foo()") && content.contains("// fn bar()"),
"Both lines should be commented. Got: {:?}",
content
);
}