use super::*;
use crate::heap_types::LispString;
fn utf8_ls(text: &str) -> LispString {
LispString::from_utf8(text)
}
fn runtime_text(value: &LispString) -> String {
crate::emacs_core::string_escape::emacs_bytes_to_storage_string(
value.as_bytes(),
value.is_multibyte(),
)
}
fn runtime_opt_text(value: Option<&LispString>) -> Option<String> {
value.map(runtime_text)
}
fn assert_lisp_string_eq(value: &LispString, expected: &str) {
assert_eq!(runtime_text(value), expected);
}
#[test]
fn history_push_and_get() {
crate::test_utils::init_test_tracing();
let mut h = SearchHistory::new();
h.push(utf8_ls("hello"), false);
h.push(utf8_ls("world"), false);
assert_eq!(runtime_opt_text(h.get(0, false)), Some("world".to_string()));
assert_eq!(runtime_opt_text(h.get(1, false)), Some("hello".to_string()));
assert_eq!(runtime_opt_text(h.get(2, false)), None);
}
#[test]
fn history_push_deduplicates() {
crate::test_utils::init_test_tracing();
let mut h = SearchHistory::new();
h.push(utf8_ls("aaa"), false);
h.push(utf8_ls("bbb"), false);
h.push(utf8_ls("aaa"), false);
assert_eq!(h.len(false), 2);
assert_eq!(runtime_opt_text(h.get(0, false)), Some("aaa".to_string()));
assert_eq!(runtime_opt_text(h.get(1, false)), Some("bbb".to_string()));
}
#[test]
fn history_separate_rings() {
crate::test_utils::init_test_tracing();
let mut h = SearchHistory::new();
h.push(utf8_ls("literal"), false);
h.push(utf8_ls("re.*gex"), true);
assert_eq!(h.len(false), 1);
assert_eq!(h.len(true), 1);
assert_eq!(
runtime_opt_text(h.get(0, false)),
Some("literal".to_string())
);
assert_eq!(
runtime_opt_text(h.get(0, true)),
Some("re.*gex".to_string())
);
}
#[test]
fn history_max_length() {
crate::test_utils::init_test_tracing();
let mut h = SearchHistory::new();
for i in 0..150 {
h.push(utf8_ls(&format!("item{}", i)), false);
}
assert_eq!(h.len(false), 100);
assert_eq!(
runtime_opt_text(h.get(0, false)),
Some("item149".to_string())
);
}
#[test]
fn history_strings_accessor() {
crate::test_utils::init_test_tracing();
let mut h = SearchHistory::new();
h.push(utf8_ls("a"), false);
h.push(utf8_ls("b"), false);
let ring = h.strings(false);
assert_eq!(ring.len(), 2);
assert_lisp_string_eq(&ring[0], "b");
assert_lisp_string_eq(&ring[1], "a");
}
#[test]
fn history_preserves_raw_unibyte_entries() {
crate::test_utils::init_test_tracing();
let mut h = SearchHistory::new();
h.push(LispString::from_unibyte(vec![0xFF]), false);
let stored = h.get(0, false).expect("stored entry");
assert!(!stored.is_multibyte());
assert_eq!(stored.as_bytes(), &[0xFF]);
}
#[test]
fn isearch_begin_end_lifecycle() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
assert!(!mgr.is_active());
mgr.begin_search(SearchDirection::Forward, false, 42);
assert!(mgr.is_active());
let state = mgr.state().unwrap();
assert_eq!(state.origin, 42);
assert!(state.search_string.is_empty());
assert!(matches!(state.direction, SearchDirection::Forward));
assert!(!state.regexp);
mgr.end_search(false);
assert!(!mgr.is_active());
}
#[test]
fn isearch_abort_restores_origin() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
mgr.begin_search(SearchDirection::Forward, false, 100);
mgr.add_char('x');
let origin = mgr.abort_search();
assert_eq!(origin, 100);
assert!(!mgr.is_active());
}
#[test]
fn isearch_end_saves_to_history() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.add_char('f');
mgr.add_char('o');
mgr.add_char('o');
mgr.end_search(true);
assert_eq!(
runtime_opt_text(mgr.history.get(0, false)),
Some("foo".to_string())
);
}
#[test]
fn isearch_end_empty_string_not_saved() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.end_search(true);
assert_eq!(mgr.history.len(false), 0);
}
#[test]
fn isearch_add_delete_char() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.add_char('a');
mgr.add_char('b');
mgr.add_char('c');
assert_lisp_string_eq(&mgr.state().unwrap().search_string, "abc");
mgr.delete_char();
assert_lisp_string_eq(&mgr.state().unwrap().search_string, "ab");
}
#[test]
fn isearch_set_string() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.set_string(utf8_ls("hello world"));
assert_lisp_string_eq(&mgr.state().unwrap().search_string, "hello world");
}
#[test]
fn isearch_set_string_preserves_raw_unibyte_bytes() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.set_string(LispString::from_unibyte(vec![0xFF]));
let stored = &mgr.state().unwrap().search_string;
assert!(!stored.is_multibyte());
assert_eq!(stored.as_bytes(), &[0xFF]);
}
#[test]
fn isearch_toggle_regexp() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
mgr.begin_search(SearchDirection::Forward, false, 0);
assert!(!mgr.state().unwrap().regexp);
mgr.toggle_regexp();
assert!(mgr.state().unwrap().regexp);
mgr.toggle_regexp();
assert!(!mgr.state().unwrap().regexp);
}
#[test]
fn isearch_toggle_case_fold() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
mgr.begin_search(SearchDirection::Forward, false, 0);
assert!(mgr.state().unwrap().case_fold.is_none());
mgr.toggle_case_fold();
assert_eq!(mgr.state().unwrap().case_fold, Some(true));
mgr.toggle_case_fold();
assert_eq!(mgr.state().unwrap().case_fold, Some(false));
mgr.toggle_case_fold();
assert!(mgr.state().unwrap().case_fold.is_none());
}
#[test]
fn isearch_reverse_direction() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
mgr.begin_search(SearchDirection::Forward, false, 0);
assert!(matches!(
mgr.state().unwrap().direction,
SearchDirection::Forward
));
mgr.reverse_direction();
assert!(matches!(
mgr.state().unwrap().direction,
SearchDirection::Backward
));
}
#[test]
fn isearch_forward_search_update_finds_match() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "hello world hello";
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.set_string(utf8_ls("world"));
let result = mgr.search_update(text);
assert_eq!(result, Some((6, 11)));
assert!(mgr.state().unwrap().success);
}
#[test]
fn isearch_forward_search_update_no_match() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "hello world";
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.set_string(utf8_ls("zzz"));
let result = mgr.search_update(text);
assert!(result.is_none());
assert!(!mgr.state().unwrap().success);
}
#[test]
fn isearch_forward_search_next_advances() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "aaa bbb aaa bbb";
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.set_string(utf8_ls("aaa"));
let r1 = mgr.search_update(text);
assert_eq!(r1, Some((0, 3)));
let r2 = mgr.search_next(text);
assert_eq!(r2, Some((8, 11)));
}
#[test]
fn isearch_backward_search_update() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "aaa bbb aaa";
mgr.begin_search(SearchDirection::Backward, false, text.len());
mgr.set_string(utf8_ls("aaa"));
let result = mgr.search_update(text);
assert_eq!(result, Some((8, 11)));
}
#[test]
fn isearch_backward_search_next() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "aaa bbb aaa";
mgr.begin_search(SearchDirection::Backward, false, text.len());
mgr.set_string(utf8_ls("aaa"));
let r1 = mgr.search_update(text);
assert_eq!(r1, Some((8, 11)));
let r2 = mgr.search_next(text);
assert_eq!(r2, Some((0, 3)));
}
#[test]
fn isearch_forward_wraps() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "aaa bbb ccc";
mgr.begin_search(SearchDirection::Forward, false, 8);
mgr.set_string(utf8_ls("aaa"));
let result = mgr.search_update(text);
assert_eq!(result, Some((0, 3)));
assert!(mgr.state().unwrap().wrapped);
}
#[test]
fn isearch_backward_wraps() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "aaa bbb ccc";
mgr.begin_search(SearchDirection::Backward, false, 0);
mgr.set_string(utf8_ls("ccc"));
let result = mgr.search_update(text);
assert_eq!(result, Some((8, 11)));
assert!(mgr.state().unwrap().wrapped);
}
#[test]
fn case_fold_auto_lowercase_folds() {
crate::test_utils::init_test_tracing();
assert!(resolve_case_fold(None, "hello"));
}
#[test]
fn case_fold_auto_uppercase_exact() {
crate::test_utils::init_test_tracing();
assert!(!resolve_case_fold(None, "Hello"));
}
#[test]
fn case_fold_override_true() {
crate::test_utils::init_test_tracing();
assert!(resolve_case_fold(Some(true), "Hello"));
}
#[test]
fn case_fold_override_false() {
crate::test_utils::init_test_tracing();
assert!(!resolve_case_fold(Some(false), "hello"));
}
#[test]
fn isearch_case_fold_auto() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "Hello World hello world";
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.set_string(utf8_ls("hello"));
let result = mgr.search_update(text);
assert_eq!(result, Some((0, 5)));
}
#[test]
fn isearch_case_fold_auto_uppercase_exact() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "hello world Hello World";
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.set_string(utf8_ls("Hello"));
let result = mgr.search_update(text);
assert_eq!(result, Some((12, 17)));
}
#[test]
fn isearch_regexp_forward() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "foo 123 bar 456";
mgr.begin_search(SearchDirection::Forward, true, 0);
mgr.set_string(utf8_ls("[0-9]+"));
let result = mgr.search_update(text);
assert_eq!(result, Some((4, 7)));
}
#[test]
fn isearch_regexp_backward() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "foo 123 bar 456";
mgr.begin_search(SearchDirection::Backward, true, text.len());
mgr.set_string(utf8_ls("[0-9]+"));
let result = mgr.search_update(text);
assert_eq!(result, Some((12, 15)));
}
#[test]
fn compute_lazy_matches_literal() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "aa bb aa cc aa";
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.set_string(utf8_ls("aa"));
mgr.compute_lazy_matches(text, 0, text.len());
let matches = &mgr.state().unwrap().lazy_matches;
assert_eq!(matches.len(), 3);
assert_eq!(matches[0], (0, 2));
assert_eq!(matches[1], (6, 8));
assert_eq!(matches[2], (12, 14));
}
#[test]
fn compute_lazy_matches_regexp() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "abc 123 def 456 ghi";
mgr.begin_search(SearchDirection::Forward, true, 0);
mgr.set_string(utf8_ls("[0-9]+"));
mgr.compute_lazy_matches(text, 0, text.len());
let matches = &mgr.state().unwrap().lazy_matches;
assert_eq!(matches.len(), 2);
assert_eq!(matches[0], (4, 7));
assert_eq!(matches[1], (12, 15));
}
#[test]
fn compute_lazy_matches_visible_region() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "aaa bbb aaa ccc aaa";
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.set_string(utf8_ls("aaa"));
mgr.compute_lazy_matches(text, 4, 15);
let matches = &mgr.state().unwrap().lazy_matches;
assert_eq!(matches.len(), 1);
assert_eq!(matches[0], (8, 11));
}
#[test]
fn compute_lazy_matches_empty_string() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "hello world";
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.set_string(utf8_ls(""));
mgr.compute_lazy_matches(text, 0, text.len());
assert!(mgr.state().unwrap().lazy_matches.is_empty());
}
#[test]
fn isearch_history_navigation() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.set_string(utf8_ls("first"));
mgr.end_search(true);
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.set_string(utf8_ls("second"));
mgr.end_search(true);
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.history_previous();
assert_lisp_string_eq(&mgr.state().unwrap().search_string, "second");
mgr.history_previous();
assert_lisp_string_eq(&mgr.state().unwrap().search_string, "first");
mgr.history_next();
assert_lisp_string_eq(&mgr.state().unwrap().search_string, "second");
mgr.history_next();
assert!(mgr.state().unwrap().search_string.is_empty());
}
#[test]
fn isearch_yank_word() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "hello world";
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.yank_word_or_char(text, 0);
assert_lisp_string_eq(&mgr.state().unwrap().search_string, "hello");
}
#[test]
fn isearch_yank_nonword_char() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = " hello";
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.yank_word_or_char(text, 0);
assert_lisp_string_eq(&mgr.state().unwrap().search_string, " ");
}
#[test]
fn isearch_yank_at_end() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
let text = "hi";
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.yank_word_or_char(text, 2);
assert!(mgr.state().unwrap().search_string.is_empty());
}
#[test]
fn isearch_prompt_basic() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
mgr.begin_search(SearchDirection::Forward, false, 0);
mgr.set_string(utf8_ls("test"));
let prompt = mgr.prompt();
assert!(prompt.contains("I-search"));
assert!(prompt.contains("test"));
assert!(!prompt.contains("Regexp"));
}
#[test]
fn isearch_prompt_regexp_backward_failing() {
crate::test_utils::init_test_tracing();
let mut mgr = IsearchManager::new();
mgr.begin_search(SearchDirection::Backward, true, 0);
mgr.set_string(utf8_ls("pat"));
let _ = mgr.search_update("no match here");
let prompt = mgr.prompt();
assert!(prompt.contains("Failing"));
assert!(prompt.contains("Regexp"));
assert!(prompt.contains("I-search backward"));
}
#[test]
fn query_replace_begin_end() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
assert!(!mgr.is_active());
mgr.begin(utf8_ls("foo"), utf8_ls("bar"), false);
assert!(mgr.is_active());
let state = mgr.state().unwrap();
assert_lisp_string_eq(&state.from_string, "foo");
assert_lisp_string_eq(&state.to_string, "bar");
assert!(!state.regexp);
assert!(state.region_start.is_none());
let summary = mgr.finish();
assert_eq!(summary.replaced, 0);
assert_eq!(summary.skipped, 0);
assert!(!mgr.is_active());
}
#[test]
fn query_replace_begin_in_region() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
mgr.begin_in_region(utf8_ls("x"), utf8_ls("y"), false, 10, 50);
let state = mgr.state().unwrap();
assert_eq!(state.region_start, Some(10));
assert_eq!(state.region_end, Some(50));
}
#[test]
fn query_replace_begin_preserves_raw_unibyte_strings() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
mgr.begin(
LispString::from_unibyte(vec![0xFF]),
LispString::from_unibyte(vec![0xFE]),
false,
);
let state = mgr.state().unwrap();
assert!(!state.from_string.is_multibyte());
assert_eq!(state.from_string.as_bytes(), &[0xFF]);
assert!(!state.to_string.is_multibyte());
assert_eq!(state.to_string.as_bytes(), &[0xFE]);
}
#[test]
fn query_replace_find_next_basic() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
let text = "foo bar foo baz foo";
mgr.begin(utf8_ls("foo"), utf8_ls("qux"), false);
let r1 = mgr.find_next(text, 0);
assert_eq!(r1, Some((0, 3)));
let r2 = mgr.find_next(text, 3);
assert_eq!(r2, Some((8, 11)));
let r3 = mgr.find_next(text, 11);
assert_eq!(r3, Some((16, 19)));
let r4 = mgr.find_next(text, 19);
assert!(r4.is_none());
}
#[test]
fn query_replace_find_next_in_region() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
let text = "foo bar foo baz foo";
mgr.begin_in_region(utf8_ls("foo"), utf8_ls("qux"), false, 4, 15);
let r1 = mgr.find_next(text, 0);
assert_eq!(r1, Some((8, 11)));
let r2 = mgr.find_next(text, 11);
assert!(r2.is_none());
}
#[test]
fn query_replace_find_next_regexp() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
let text = "abc 123 def 456";
mgr.begin(utf8_ls("[0-9]+"), utf8_ls("NUM"), true);
let r1 = mgr.find_next(text, 0);
assert_eq!(r1, Some((4, 7)));
let r2 = mgr.find_next(text, 7);
assert_eq!(r2, Some((12, 15)));
}
#[test]
fn query_replace_respond_yes() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
let text = "foo bar";
mgr.begin(utf8_ls("foo"), utf8_ls("baz"), false);
let _ = mgr.find_next(text, 0);
let action = mgr.respond(QueryReplaceResponse::Yes);
match action {
QueryReplaceAction::Replace(start, end, repl) => {
assert_eq!(start, 0);
assert_eq!(end, 3);
assert_lisp_string_eq(&repl, "baz");
}
_ => panic!("expected Replace action"),
}
assert_eq!(mgr.state().unwrap().replaced_count, 1);
}
#[test]
fn query_replace_respond_no() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
let text = "foo bar";
mgr.begin(utf8_ls("foo"), utf8_ls("baz"), false);
let _ = mgr.find_next(text, 0);
let action = mgr.respond(QueryReplaceResponse::No);
assert!(matches!(action, QueryReplaceAction::Skip));
assert_eq!(mgr.state().unwrap().skipped_count, 1);
}
#[test]
fn query_replace_respond_quit() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
let text = "foo bar foo";
mgr.begin(utf8_ls("foo"), utf8_ls("baz"), false);
let _ = mgr.find_next(text, 0);
mgr.respond(QueryReplaceResponse::Yes);
let _ = mgr.find_next(text, 3);
let action = mgr.respond(QueryReplaceResponse::Quit);
match action {
QueryReplaceAction::Done(summary) => {
assert_eq!(summary.replaced, 1);
assert_eq!(summary.skipped, 0);
}
_ => panic!("expected Done action"),
}
assert!(!mgr.is_active());
}
#[test]
fn query_replace_respond_delete() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
let text = "foo bar";
mgr.begin(utf8_ls("foo"), utf8_ls("baz"), false);
let _ = mgr.find_next(text, 0);
let action = mgr.respond(QueryReplaceResponse::Delete);
match action {
QueryReplaceAction::Replace(start, end, repl) => {
assert_eq!(start, 0);
assert_eq!(end, 3);
assert!(repl.is_empty());
}
_ => panic!("expected Replace with empty string"),
}
}
#[test]
fn query_replace_respond_help() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
mgr.begin(utf8_ls("foo"), utf8_ls("bar"), false);
let action = mgr.respond(QueryReplaceResponse::Help);
match action {
QueryReplaceAction::ShowHelp(text) => {
assert!(text.contains("replace this match"));
assert!(text.contains("skip this match"));
}
_ => panic!("expected ShowHelp action"),
}
}
#[test]
fn query_replace_respond_edit() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
mgr.begin(utf8_ls("foo"), utf8_ls("bar"), false);
let action = mgr.respond(QueryReplaceResponse::Edit);
assert!(matches!(action, QueryReplaceAction::NeedInput));
}
#[test]
fn query_replace_undo() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
let text = "foo bar foo";
mgr.begin(utf8_ls("foo"), utf8_ls("baz"), false);
let _ = mgr.find_next(text, 0);
mgr.respond(QueryReplaceResponse::Yes);
assert_eq!(mgr.state().unwrap().replaced_count, 1);
let undo = mgr.undo_last();
assert!(undo.is_some());
let undo = undo.unwrap();
assert_eq!(undo.position, 0);
assert_lisp_string_eq(&undo.replacement, "baz");
assert_eq!(mgr.state().unwrap().replaced_count, 0);
}
#[test]
fn query_replace_undo_empty_stack() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
mgr.begin(utf8_ls("foo"), utf8_ls("bar"), false);
assert!(mgr.undo_last().is_none());
}
#[test]
fn query_replace_compute_replacement_lower() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
mgr.begin(utf8_ls("foo"), utf8_ls("bar"), false);
assert_lisp_string_eq(&mgr.compute_replacement("foo"), "bar");
}
#[test]
fn query_replace_compute_replacement_upper() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
mgr.begin(utf8_ls("foo"), utf8_ls("bar"), false);
assert_lisp_string_eq(&mgr.compute_replacement("FOO"), "BAR");
}
#[test]
fn query_replace_compute_replacement_capitalized() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
mgr.begin(utf8_ls("foo"), utf8_ls("bar"), false);
assert_lisp_string_eq(&mgr.compute_replacement("Foo"), "Bar");
}
#[test]
fn query_replace_prompt() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
mgr.begin(utf8_ls("old"), utf8_ls("new"), false);
let prompt = mgr.prompt();
assert!(prompt.contains("Query replacing"));
assert!(prompt.contains("old"));
assert!(prompt.contains("new"));
assert!(!prompt.contains("regexp"));
}
#[test]
fn query_replace_prompt_regexp() {
crate::test_utils::init_test_tracing();
let mut mgr = QueryReplaceManager::new();
mgr.begin(utf8_ls("[0-9]+"), utf8_ls("NUM"), true);
let prompt = mgr.prompt();
assert!(prompt.contains("regexp"));
}
#[test]
fn preserve_case_all_lower() {
crate::test_utils::init_test_tracing();
assert_eq!(preserve_case("bar", "foo"), "bar");
}
#[test]
fn preserve_case_all_upper() {
crate::test_utils::init_test_tracing();
assert_eq!(preserve_case("bar", "FOO"), "BAR");
}
#[test]
fn preserve_case_capitalized() {
crate::test_utils::init_test_tracing();
assert_eq!(preserve_case("bar", "Foo"), "Bar");
}
#[test]
fn preserve_case_mixed() {
crate::test_utils::init_test_tracing();
assert_eq!(preserve_case("bar", "fOo"), "bar");
}
#[test]
fn preserve_case_empty_matched() {
crate::test_utils::init_test_tracing();
assert_eq!(preserve_case("bar", ""), "bar");
}
#[test]
fn preserve_case_empty_replacement() {
crate::test_utils::init_test_tracing();
assert_eq!(preserve_case("", "FOO"), "");
}
#[test]
fn preserve_case_non_alpha_upper() {
crate::test_utils::init_test_tracing();
assert_eq!(preserve_case("bar", "123"), "bar");
}
#[test]
fn find_match_literal_forward() {
crate::test_utils::init_test_tracing();
let text = "hello world hello";
let result = find_match(text, "hello", 0, true, false, false);
assert_eq!(result, Some((0, 5)));
}
#[test]
fn find_match_literal_forward_from_offset() {
crate::test_utils::init_test_tracing();
let text = "hello world hello";
let result = find_match(text, "hello", 1, true, false, false);
assert_eq!(result, Some((12, 17)));
}
#[test]
fn find_match_literal_backward() {
crate::test_utils::init_test_tracing();
let text = "hello world hello";
let result = find_match(text, "hello", text.len(), false, false, false);
assert_eq!(result, Some((12, 17)));
}
#[test]
fn find_match_literal_backward_from_middle() {
crate::test_utils::init_test_tracing();
let text = "hello world hello";
let result = find_match(text, "hello", 10, false, false, false);
assert_eq!(result, Some((0, 5)));
}
#[test]
fn find_match_case_fold() {
crate::test_utils::init_test_tracing();
let text = "Hello World";
let result = find_match(text, "hello", 0, true, false, true);
assert_eq!(result, Some((0, 5)));
}
#[test]
fn find_match_case_sensitive() {
crate::test_utils::init_test_tracing();
let text = "Hello World";
let result = find_match(text, "hello", 0, true, false, false);
assert!(result.is_none());
}
#[test]
fn find_match_regexp_forward() {
crate::test_utils::init_test_tracing();
let text = "foo 123 bar";
let result = find_match(text, "[0-9]+", 0, true, true, false);
assert_eq!(result, Some((4, 7)));
}
#[test]
fn find_match_regexp_backward() {
crate::test_utils::init_test_tracing();
let text = "foo 123 bar 456";
let result = find_match(text, "[0-9]+", text.len(), false, true, false);
assert_eq!(result, Some((12, 15)));
}
#[test]
fn find_match_empty_pattern() {
crate::test_utils::init_test_tracing();
let text = "hello";
assert!(find_match(text, "", 0, true, false, false).is_none());
}
#[test]
fn find_match_no_match() {
crate::test_utils::init_test_tracing();
let text = "hello world";
assert!(find_match(text, "zzz", 0, true, false, false).is_none());
}
#[test]
fn find_match_at_boundary() {
crate::test_utils::init_test_tracing();
let text = "abcdef";
let result = find_match(text, "def", 3, true, false, false);
assert_eq!(result, Some((3, 6)));
}
#[test]
fn delimited_match_rejects_embedded_word() {
crate::test_utils::init_test_tracing();
let text = "foo1 1foo foo";
assert!(!is_delimited_match(text, 0, 3));
assert!(!is_delimited_match(text, 5, 8));
assert!(is_delimited_match(text, 10, 13));
}
#[test]
fn delimited_match_treats_underscore_as_delimiter() {
crate::test_utils::init_test_tracing();
let text = "foo_foo";
assert!(is_delimited_match(text, 0, 3));
assert!(is_delimited_match(text, 4, 7));
}
#[test]
fn builtin_isearch_forward_signals_batch_buffer_error() {
crate::test_utils::init_test_tracing();
let result = builtin_isearch_forward(vec![]);
assert!(matches!(
result,
Err(Flow::Signal(sig))
if sig.symbol_name() == "error"
&& sig.data == vec![Value::string("move-to-window-line called from unrelated buffer")]
));
}
#[test]
fn builtin_isearch_backward_signals_batch_buffer_error() {
crate::test_utils::init_test_tracing();
let result = builtin_isearch_backward(vec![]);
assert!(matches!(
result,
Err(Flow::Signal(sig))
if sig.symbol_name() == "error"
&& sig.data == vec![Value::string("move-to-window-line called from unrelated buffer")]
));
}
#[test]
fn builtin_isearch_forward_rejects_too_many_args() {
crate::test_utils::init_test_tracing();
let result = builtin_isearch_forward(vec![Value::NIL, Value::NIL, Value::NIL]);
assert!(matches!(
result,
Err(Flow::Signal(sig))
if sig.symbol_name() == "wrong-number-of-arguments"
));
}
#[test]
fn builtin_isearch_backward_rejects_too_many_args() {
crate::test_utils::init_test_tracing();
let result = builtin_isearch_backward(vec![Value::NIL, Value::NIL, Value::NIL]);
assert!(matches!(
result,
Err(Flow::Signal(sig))
if sig.symbol_name() == "wrong-number-of-arguments"
));
}
#[test]
fn replace_string_and_regexp_preserve_unibyte_raw_bytes() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
{
let buf = eval.buffers.current_buffer_mut().expect("current buffer");
buf.set_multibyte_value(false);
buf.insert_lisp_string(&crate::heap_types::LispString::from_unibyte(vec![
0xFF, 0xFF,
]));
buf.goto_byte(0);
}
let raw_ff = Value::heap_string(crate::heap_types::LispString::from_unibyte(vec![0xFF]));
let raw_fe = Value::heap_string(crate::heap_types::LispString::from_unibyte(vec![0xFE]));
builtin_replace_string(&mut eval, vec![raw_ff, raw_fe]).unwrap();
let current_id = {
let buf = eval.buffers.current_buffer().expect("current buffer");
let text = buf.buffer_substring_lisp_string(buf.point_min(), buf.point_max());
assert_eq!(text.as_bytes(), &[0xFE, 0xFE]);
buf.id
};
let _ = eval.buffers.replace_buffer_contents_lisp_string(
current_id,
&crate::heap_types::LispString::from_unibyte(vec![0xFF]),
);
let _ = eval.buffers.goto_buffer_byte(current_id, 0);
builtin_replace_regexp(
&mut eval,
vec![
Value::string("."),
Value::heap_string(crate::heap_types::LispString::from_unibyte(vec![0xFE])),
],
)
.unwrap();
let buf = eval.buffers.current_buffer().expect("current buffer");
let text = buf.buffer_substring_lisp_string(buf.point_min(), buf.point_max());
assert_eq!(text.as_bytes(), &[0xFE]);
}
#[test]
fn keep_and_flush_lines_preserve_unibyte_raw_bytes() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
let current_id = eval.buffers.current_buffer().expect("current buffer").id;
{
let buf = eval.buffers.current_buffer_mut().expect("current buffer");
buf.set_multibyte_value(false);
buf.insert_lisp_string(&crate::heap_types::LispString::from_unibyte(vec![
0xFF, b'\n', b'a', b'\n', 0xFF, b'\n',
]));
buf.goto_byte(0);
}
let raw_ff = Value::heap_string(crate::heap_types::LispString::from_unibyte(vec![0xFF]));
builtin_keep_lines(&mut eval, vec![raw_ff]).unwrap();
let buf = eval.buffers.current_buffer().expect("current buffer");
let kept = buf.buffer_substring_lisp_string(buf.point_min(), buf.point_max());
assert_eq!(kept.as_bytes(), &[0xFF, b'\n', 0xFF, b'\n']);
let _ = eval.buffers.replace_buffer_contents_lisp_string(
current_id,
&crate::heap_types::LispString::from_unibyte(vec![0xFF, b'\n', b'a', b'\n']),
);
let _ = eval.buffers.goto_buffer_byte(current_id, 0);
builtin_flush_lines(
&mut eval,
vec![Value::heap_string(
crate::heap_types::LispString::from_unibyte(vec![0xFF]),
)],
)
.unwrap();
let buf = eval.buffers.current_buffer().expect("current buffer");
let flushed = buf.buffer_substring_lisp_string(buf.point_min(), buf.point_max());
assert_eq!(flushed.as_bytes(), b"a\n");
}
#[test]
fn count_matches_and_how_many_preserve_unibyte_raw_bytes() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
{
let buf = eval.buffers.current_buffer_mut().expect("current buffer");
buf.set_multibyte_value(false);
buf.insert_lisp_string(&crate::heap_types::LispString::from_unibyte(vec![
0xFF, b'a', 0xFF,
]));
buf.goto_byte(0);
}
let raw_ff = Value::heap_string(crate::heap_types::LispString::from_unibyte(vec![0xFF]));
let count = builtin_count_matches(&mut eval, vec![raw_ff]).unwrap();
assert_eq!(count, Value::fixnum(2));
let how_many = builtin_how_many(
&mut eval,
vec![Value::heap_string(
crate::heap_types::LispString::from_unibyte(vec![0xFF]),
)],
)
.unwrap();
assert_eq!(how_many, Value::fixnum(2));
let empty_count = builtin_count_matches(&mut eval, vec![Value::string("")]).unwrap();
assert_eq!(empty_count, Value::fixnum(3));
}