use super::*;
use crate::buffer::BufferId;
#[test]
fn normalize_symbol_reader_default_uses_list_head_and_symbol_name() {
crate::test_utils::init_test_tracing();
assert_eq!(
normalize_symbol_reader_default(Value::list(vec![
Value::symbol("forward-char"),
Value::symbol("backward-char"),
])),
Value::string("forward-char")
);
assert_eq!(
normalize_symbol_reader_default(Value::symbol("fill-column")),
Value::string("fill-column")
);
}
#[test]
fn normalize_buffer_reader_default_uses_list_head_and_live_buffer_name() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
let buf_id = eval.buffers.create_buffer(" minibuffer-default ");
assert_eq!(
normalize_buffer_reader_default(
&eval.buffers,
Value::list(vec![Value::make_buffer(buf_id), Value::string("fallback")]),
),
Value::string(" minibuffer-default ")
);
assert_eq!(
normalize_buffer_reader_default(&eval.buffers, Value::make_buffer(buf_id)),
Value::string(" minibuffer-default ")
);
}
#[test]
fn read_buffer_completing_args_use_live_buffer_names_and_normalized_default() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
let buf_id = eval.buffers.create_buffer(" target-buffer ");
let args = read_buffer_completing_args(
&eval.buffers,
&[
Value::string("Buffer: "),
Value::list(vec![Value::make_buffer(buf_id), Value::string("fallback")]),
Value::T,
Value::symbol("predicate"),
],
);
assert_eq!(args[0], Value::string("Buffer: "));
assert_eq!(args[2], Value::symbol("predicate"));
assert_eq!(args[3], Value::T);
assert_eq!(args[6], Value::string(" target-buffer "));
let names = super::value_to_string_list(&args[1]);
assert!(names.contains(&" target-buffer ".to_string()));
}
#[test]
fn finish_read_command_with_minibuffer_normalizes_default_and_interns_result() {
crate::test_utils::init_test_tracing();
let result = finish_read_command_with_minibuffer(
&[
Value::string("Command: "),
Value::list(vec![
Value::symbol("forward-char"),
Value::symbol("backward-char"),
]),
],
|minibuffer_args| {
assert_eq!(
minibuffer_args,
&[
Value::string("Command: "),
Value::NIL,
Value::NIL,
Value::NIL,
Value::NIL,
Value::string("forward-char"),
]
);
Ok(Value::string("next-line"))
},
)
.unwrap();
assert_eq!(result, Value::symbol("next-line"));
}
#[test]
fn finish_read_variable_with_minibuffer_normalizes_default_and_interns_result() {
crate::test_utils::init_test_tracing();
let result = finish_read_variable_with_minibuffer(
&[Value::string("Variable: "), Value::symbol("fill-column")],
|minibuffer_args| {
assert_eq!(
minibuffer_args,
&[
Value::string("Variable: "),
Value::NIL,
Value::NIL,
Value::NIL,
Value::NIL,
Value::string("fill-column"),
]
);
Ok(Value::string("tab-width"))
},
)
.unwrap();
assert_eq!(result, Value::symbol("tab-width"));
}
#[test]
fn prefix_match_basic() {
crate::test_utils::init_test_tracing();
let candidates = vec![
"apple".into(),
"application".into(),
"banana".into(),
"apply".into(),
];
let result = prefix_match("app", &candidates);
assert_eq!(result.len(), 3);
assert!(result.contains(&"apple".to_string()));
assert!(result.contains(&"application".to_string()));
assert!(result.contains(&"apply".to_string()));
}
#[test]
fn prefix_match_case_insensitive() {
crate::test_utils::init_test_tracing();
let candidates = vec!["Apple".into(), "APPLY".into(), "banana".into()];
let result = prefix_match("app", &candidates);
assert_eq!(result.len(), 2);
}
#[test]
fn prefix_match_empty_input() {
crate::test_utils::init_test_tracing();
let candidates = vec!["a".into(), "b".into(), "c".into()];
let result = prefix_match("", &candidates);
assert_eq!(result.len(), 3);
}
#[test]
fn prefix_match_no_matches() {
crate::test_utils::init_test_tracing();
let candidates = vec!["apple".into(), "banana".into()];
let result = prefix_match("zz", &candidates);
assert!(result.is_empty());
}
#[test]
fn substring_match_basic() {
crate::test_utils::init_test_tracing();
let candidates = vec![
"foobar".into(),
"bazfoo".into(),
"hello".into(),
"food".into(),
];
let result = substring_match("foo", &candidates);
assert_eq!(result.len(), 3);
assert!(result.contains(&"foobar".to_string()));
assert!(result.contains(&"bazfoo".to_string()));
assert!(result.contains(&"food".to_string()));
}
#[test]
fn flex_match_basic() {
crate::test_utils::init_test_tracing();
let candidates = vec![
"find-file".into(),
"flycheck".into(),
"first-foo".into(),
"hello".into(),
];
let result = flex_match("ff", &candidates);
assert!(result.contains(&"find-file".to_string()));
assert!(result.contains(&"first-foo".to_string()));
assert!(!result.contains(&"hello".to_string()));
}
#[test]
fn flex_match_all_chars_in_order() {
crate::test_utils::init_test_tracing();
let candidates = vec!["abcdef".into(), "axbycz".into(), "zzz".into()];
let result = flex_match("abc", &candidates);
assert_eq!(result.len(), 2);
assert!(result.contains(&"abcdef".to_string()));
assert!(result.contains(&"axbycz".to_string()));
}
#[test]
fn flex_match_case_insensitive() {
crate::test_utils::init_test_tracing();
let candidates = vec!["FindFile".into()];
let result = flex_match("ff", &candidates);
assert_eq!(result.len(), 1);
}
#[test]
fn basic_match_case_sensitive() {
crate::test_utils::init_test_tracing();
let candidates = vec!["Apple".into(), "apple".into(), "application".into()];
let result = basic_match("app", &candidates);
assert_eq!(result.len(), 2);
assert!(result.contains(&"apple".to_string()));
assert!(result.contains(&"application".to_string()));
assert!(!result.contains(&"Apple".to_string()));
}
#[test]
fn common_prefix_empty() {
crate::test_utils::init_test_tracing();
assert!(compute_common_prefix(&[]).is_none());
}
#[test]
fn common_prefix_single() {
crate::test_utils::init_test_tracing();
let strings = vec!["hello".to_string()];
assert_eq!(compute_common_prefix(&strings), Some("hello".to_string()));
}
#[test]
fn common_prefix_multiple() {
crate::test_utils::init_test_tracing();
let strings = vec![
"application".to_string(),
"apple".to_string(),
"apply".to_string(),
];
assert_eq!(compute_common_prefix(&strings), Some("appl".to_string()));
}
#[test]
fn common_prefix_no_overlap() {
crate::test_utils::init_test_tracing();
let strings = vec!["abc".to_string(), "xyz".to_string()];
assert_eq!(compute_common_prefix(&strings), Some(String::new()));
}
#[test]
fn common_prefix_identical() {
crate::test_utils::init_test_tracing();
let strings = vec!["test".to_string(), "test".to_string()];
assert_eq!(compute_common_prefix(&strings), Some("test".to_string()));
}
#[test]
fn history_navigation() {
crate::test_utils::init_test_tracing();
let mut mgr = MinibufferManager::new();
mgr.add_to_history("test-history", "first", 100);
mgr.add_to_history("test-history", "second", 100);
mgr.add_to_history("test-history", "third", 100);
mgr.read_from_minibuffer(BufferId(1), "prompt: ", None, Some("test-history"))
.unwrap();
let prev = mgr.history_previous();
assert_eq!(prev, Some("third".to_string()));
let prev = mgr.history_previous();
assert_eq!(prev, Some("second".to_string()));
let next = mgr.history_next();
assert_eq!(next, Some("third".to_string()));
let next = mgr.history_next();
assert_eq!(next, Some(String::new()));
let next = mgr.history_next();
assert_eq!(next, None);
mgr.exit_minibuffer();
}
#[test]
fn history_dedup() {
crate::test_utils::init_test_tracing();
let mut mgr = MinibufferManager::new();
mgr.add_to_history("h", "same", 100);
mgr.add_to_history("h", "same", 100);
mgr.add_to_history("h", "same", 100);
assert_eq!(mgr.history.get("h").len(), 1);
mgr.add_to_history("h", "different", 100);
assert_eq!(mgr.history.get("h").len(), 2);
assert_eq!(mgr.history.get("h")[0], "different");
assert_eq!(mgr.history.get("h")[1], "same");
}
#[test]
fn recursive_depth() {
crate::test_utils::init_test_tracing();
let mut mgr = MinibufferManager::new();
assert_eq!(mgr.depth(), 0);
assert!(!mgr.is_active());
mgr.read_from_minibuffer(BufferId(1), "1: ", None, None)
.unwrap();
assert_eq!(mgr.depth(), 1);
assert!(mgr.is_active());
mgr.read_from_minibuffer(BufferId(2), "2: ", None, None)
.unwrap();
assert_eq!(mgr.depth(), 2);
mgr.exit_minibuffer();
assert_eq!(mgr.depth(), 1);
mgr.exit_minibuffer();
assert_eq!(mgr.depth(), 0);
assert!(!mgr.is_active());
}
#[test]
fn recursive_depth_limit() {
crate::test_utils::init_test_tracing();
let mut mgr = MinibufferManager::new();
mgr.max_depth = 2;
mgr.read_from_minibuffer(BufferId(1), "1: ", None, None)
.unwrap();
mgr.read_from_minibuffer(BufferId(2), "2: ", None, None)
.unwrap();
let result = mgr.read_from_minibuffer(BufferId(3), "3: ", None, None);
assert!(result.is_err());
}
#[test]
fn recursive_disabled() {
crate::test_utils::init_test_tracing();
let mut mgr = MinibufferManager::new();
mgr.set_enable_recursive(false);
mgr.read_from_minibuffer(BufferId(1), "1: ", None, None)
.unwrap();
let result = mgr.read_from_minibuffer(BufferId(2), "2: ", None, None);
assert!(result.is_err());
}
#[test]
fn enter_exit_lifecycle() {
crate::test_utils::init_test_tracing();
let mut mgr = MinibufferManager::new();
{
let state = mgr
.read_from_minibuffer(BufferId(1), "Enter: ", Some("init"), None)
.unwrap();
assert_eq!(state.prompt, "Enter: ");
assert_eq!(state.content, "init");
assert!(state.active);
assert_eq!(state.depth, 1);
}
{
let state = mgr.current_mut().unwrap();
state.content = "modified".to_string();
}
let result = mgr.exit_minibuffer();
assert_eq!(result, Some("modified".to_string()));
assert_eq!(mgr.depth(), 0);
}
#[test]
fn exit_with_default() {
crate::test_utils::init_test_tracing();
let mut mgr = MinibufferManager::new();
{
let state = mgr
.read_from_minibuffer(BufferId(1), "Enter: ", None, None)
.unwrap();
state.default_value = Some("fallback".to_string());
}
let result = mgr.exit_minibuffer();
assert_eq!(result, Some("fallback".to_string()));
}
#[test]
fn abort_minibuffer_clears_state() {
crate::test_utils::init_test_tracing();
let mut mgr = MinibufferManager::new();
mgr.read_from_minibuffer(BufferId(1), "Enter: ", None, None)
.unwrap();
assert_eq!(mgr.depth(), 1);
mgr.abort_minibuffer();
assert_eq!(mgr.depth(), 0);
assert!(!mgr.is_active());
}
#[test]
fn exit_empty_stack() {
crate::test_utils::init_test_tracing();
let mut mgr = MinibufferManager::new();
assert_eq!(mgr.exit_minibuffer(), None);
}
#[test]
fn try_complete_with_table() {
crate::test_utils::init_test_tracing();
let mut mgr = MinibufferManager::new();
{
let state = mgr
.read_from_minibuffer(BufferId(1), "M-x ", Some("find"), None)
.unwrap();
state.completion_table = Some(CompletionTable::List(vec![
"find-file".into(),
"find-file-other-window".into(),
"find-tag".into(),
"forward-char".into(),
]));
}
let state = mgr.current().unwrap();
let result = mgr.try_complete(state);
assert_eq!(result.matches.len(), 3); assert_eq!(result.common_prefix, Some("find-".to_string()));
mgr.exit_minibuffer();
}
#[test]
fn test_completion_exact_match() {
crate::test_utils::init_test_tracing();
let mgr = MinibufferManager::new();
let table = CompletionTable::List(vec!["apple".into(), "banana".into(), "cherry".into()]);
assert!(mgr.test_completion("apple", &table));
assert!(mgr.test_completion("banana", &table));
assert!(!mgr.test_completion("app", &table));
assert!(!mgr.test_completion("APPLE", &table));
}
#[test]
fn try_completion_string_result() {
crate::test_utils::init_test_tracing();
let mgr = MinibufferManager::new();
let table = CompletionTable::List(vec!["application".into(), "apple".into(), "apply".into()]);
let result = mgr.try_completion_string("app", &table);
assert_eq!(result, Some("appl".to_string()));
}
#[test]
fn all_completions_empty() {
crate::test_utils::init_test_tracing();
let mgr = MinibufferManager::new();
let table = CompletionTable::List(vec!["foo".into(), "bar".into()]);
let result = mgr.all_completions("zzz", &table);
assert!(result.is_empty());
}
#[test]
fn completion_style_substring() {
crate::test_utils::init_test_tracing();
let mut mgr = MinibufferManager::new();
mgr.set_completion_style(CompletionStyle::Substring);
let table = CompletionTable::List(vec![
"find-file".into(),
"describe-file".into(),
"file-name".into(),
]);
let result = mgr.all_completions("file", &table);
assert_eq!(result.len(), 3); }
#[test]
fn completion_style_flex() {
crate::test_utils::init_test_tracing();
let mut mgr = MinibufferManager::new();
mgr.set_completion_style(CompletionStyle::Flex);
let table = CompletionTable::List(vec![
"find-file".into(),
"forward-char".into(),
"flycheck".into(),
]);
let result = mgr.all_completions("ff", &table);
assert!(result.contains(&"find-file".to_string()));
assert!(!result.contains(&"flycheck".to_string()));
}
#[test]
fn completion_style_basic_case_sensitive() {
crate::test_utils::init_test_tracing();
let mut mgr = MinibufferManager::new();
mgr.set_completion_style(CompletionStyle::Basic);
let table = CompletionTable::List(vec!["Apple".into(), "apple".into(), "application".into()]);
let result = mgr.all_completions("app", &table);
assert_eq!(result.len(), 2);
assert!(result.contains(&"apple".to_string()));
assert!(result.contains(&"application".to_string()));
}
#[test]
fn alist_completion() {
crate::test_utils::init_test_tracing();
let mgr = MinibufferManager::new();
let table = CompletionTable::Alist(vec![
("alpha".into(), Value::fixnum(1)),
("beta".into(), Value::fixnum(2)),
("alphabetical".into(), Value::fixnum(3)),
]);
let result = mgr.all_completions("alph", &table);
assert_eq!(result.len(), 2);
}
#[test]
fn builtin_try_completion_unique_exact() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
let coll = Value::list(vec![Value::string("unique"), Value::string("other")]);
let result = builtin_try_completion(&mut eval, vec![Value::string("unique"), coll]).unwrap();
assert!(result.is_t());
}
#[test]
fn builtin_try_completion_common_prefix() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
let coll = Value::list(vec![Value::string("application"), Value::string("apple")]);
let result = builtin_try_completion(&mut eval, vec![Value::string("app"), coll]).unwrap();
assert!(result.as_str().unwrap() == "appl");
}
#[test]
fn builtin_try_completion_no_match() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
let coll = Value::list(vec![Value::string("foo"), Value::string("bar")]);
let result = builtin_try_completion(&mut eval, vec![Value::string("zzz"), coll]).unwrap();
assert!(result.is_nil());
}
#[test]
fn builtin_try_completion_rejects_more_than_three_args() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
let coll = Value::list(vec![Value::string("a")]);
let result = builtin_try_completion(
&mut eval,
vec![Value::string(""), coll, Value::NIL, Value::NIL],
);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-number-of-arguments"
));
}
#[test]
fn builtin_all_completions_returns_list() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
let coll = Value::list(vec![
Value::string("apple"),
Value::string("application"),
Value::string("banana"),
]);
let result = builtin_all_completions(&mut eval, vec![Value::string("app"), coll]).unwrap();
let items = super::super::value::list_to_vec(&result).unwrap();
assert_eq!(items.len(), 2);
}
#[test]
fn builtin_all_completions_rejects_more_than_four_args() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
let coll = Value::list(vec![Value::string("a")]);
let result = builtin_all_completions(
&mut eval,
vec![Value::string(""), coll, Value::NIL, Value::NIL, Value::NIL],
);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-number-of-arguments"
));
}
#[test]
fn builtin_test_completion_match() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
let coll = Value::list(vec![Value::string("alpha"), Value::string("beta")]);
let result = builtin_test_completion(&mut eval, vec![Value::string("alpha"), coll]).unwrap();
assert!(result.is_t());
}
#[test]
fn builtin_test_completion_no_match() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
let coll = Value::list(vec![Value::string("alpha"), Value::string("beta")]);
let result = builtin_test_completion(&mut eval, vec![Value::string("alp"), coll]).unwrap();
assert!(result.is_nil());
}
#[test]
fn builtin_test_completion_rejects_more_than_three_args() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
let coll = Value::list(vec![Value::string("a")]);
let result = builtin_test_completion(
&mut eval,
vec![Value::string(""), coll, Value::NIL, Value::NIL],
);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-number-of-arguments"
));
}
#[test]
fn builtin_minibuffer_depth_returns_zero() {
crate::test_utils::init_test_tracing();
let result = builtin_minibuffer_depth(vec![]).unwrap();
assert!(result.is_fixnum());
}
#[test]
fn builtin_minibufferp_returns_nil() {
crate::test_utils::init_test_tracing();
let result = builtin_minibufferp(vec![]).unwrap();
assert!(result.is_nil());
}
#[test]
fn eval_minibuffer_runtime_state_tracks_active_prompt_and_contents() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
let minibuf_id = eval.buffers.create_buffer(" *Minibuf-1*");
{
let buf = eval.buffers.get_mut(minibuf_id).expect("minibuffer buffer");
buf.text.insert_str(0, "Prompt: value");
buf.goto_byte(buf.text.len());
}
eval.buffers.set_current(minibuf_id);
eval.minibuffers
.read_from_minibuffer(minibuf_id, "Prompt: ", Some("value"), None)
.expect("enter minibuffer");
assert_eq!(
builtin_minibuffer_prompt_ctx(&mut eval, vec![]).unwrap(),
Value::string("Prompt: ")
);
assert_eq!(
builtin_minibuffer_contents_ctx(&mut eval, vec![]).unwrap(),
Value::string("value")
);
assert_eq!(
builtin_minibuffer_contents_no_properties_ctx(&mut eval, vec![]).unwrap(),
Value::string("value")
);
assert_eq!(
builtin_minibuffer_depth_ctx(&mut eval, vec![]).unwrap(),
Value::fixnum(1)
);
assert_eq!(
builtin_minibufferp_ctx(&mut eval, vec![]).unwrap(),
Value::T
);
assert_eq!(
builtin_minibufferp_ctx(&mut eval, vec![Value::NIL, Value::T]).unwrap(),
Value::T
);
assert!(matches!(
builtin_abort_minibuffers_ctx(&mut eval, vec![]),
Err(Flow::Throw { tag, value }) if tag.is_symbol_named("exit") && value == Value::T
));
}
#[test]
fn builtin_minibufferp_accepts_string_and_second_arg() {
crate::test_utils::init_test_tracing();
let result = builtin_minibufferp(vec![Value::string("x"), Value::NIL]).unwrap();
assert!(result.is_nil());
}
#[test]
fn builtin_minibufferp_rejects_non_buffer_like_values() {
crate::test_utils::init_test_tracing();
let result = builtin_minibufferp(vec![Value::fixnum(1)]);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-type-argument"
));
}
#[test]
fn builtin_minibufferp_rejects_more_than_two_args() {
crate::test_utils::init_test_tracing();
let result = builtin_minibufferp(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_recursive_edit_returns_nil() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
let result = builtin_recursive_edit(&mut eval, vec![]).unwrap();
assert!(result.is_nil());
}
#[test]
fn builtin_recursive_edit_rejects_args() {
crate::test_utils::init_test_tracing();
let mut eval = crate::emacs_core::eval::Context::new();
let result = builtin_recursive_edit(&mut eval, vec![Value::NIL]);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-number-of-arguments"
));
}
#[test]
fn builtin_top_level_throws_top_level_tag() {
crate::test_utils::init_test_tracing();
let result = builtin_top_level(vec![]);
assert!(matches!(
result,
Err(Flow::Throw { tag, value })
if tag.is_symbol_named("top-level") && value.is_nil()
));
}
#[test]
fn builtin_top_level_rejects_args() {
crate::test_utils::init_test_tracing();
let result = builtin_top_level(vec![Value::NIL]);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-number-of-arguments"
));
}
#[test]
fn builtin_exit_recursive_edit_signals_user_error() {
crate::test_utils::init_test_tracing();
let mut eval = super::super::eval::Context::new();
let result = builtin_exit_recursive_edit(&mut eval, vec![]);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "user-error"
));
}
#[test]
fn builtin_exit_recursive_edit_rejects_args() {
crate::test_utils::init_test_tracing();
let mut eval = super::super::eval::Context::new();
let result = builtin_exit_recursive_edit(&mut eval, vec![Value::NIL]);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-number-of-arguments"
));
}
#[test]
fn builtin_minibuffer_contents_returns_current_buffer_text() {
crate::test_utils::init_test_tracing();
let mut eval = super::super::eval::Context::new();
eval.buffers
.current_buffer_mut()
.expect("scratch buffer")
.insert("probe");
let result = builtin_minibuffer_contents_ctx(&mut eval, vec![]).unwrap();
assert!(result.as_str().unwrap() == "probe");
}
#[test]
fn builtin_minibuffer_contents_no_properties_returns_current_buffer_text() {
crate::test_utils::init_test_tracing();
let mut eval = super::super::eval::Context::new();
eval.buffers
.current_buffer_mut()
.expect("scratch buffer")
.insert("probe");
let result = builtin_minibuffer_contents_no_properties_ctx(&mut eval, vec![]).unwrap();
assert!(result.as_str().unwrap() == "probe");
}
#[test]
fn builtin_minibuffer_contents_no_properties_rejects_args() {
crate::test_utils::init_test_tracing();
let mut eval = super::super::eval::Context::new();
let result = builtin_minibuffer_contents_no_properties_ctx(&mut eval, vec![Value::NIL]);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-number-of-arguments"
));
}
#[test]
fn builtin_exit_minibuffer_throws_exit_tag() {
crate::test_utils::init_test_tracing();
let result = builtin_exit_minibuffer(vec![]);
assert!(matches!(
result,
Err(Flow::Throw { tag, value })
if tag.is_symbol_named("exit") && value.is_nil()
));
}
#[test]
fn builtin_abort_minibuffers_signals_not_in_minibuffer_error() {
crate::test_utils::init_test_tracing();
let result = builtin_abort_minibuffers(vec![]);
assert!(matches!(
result,
Err(Flow::Signal(sig))
if sig.symbol_name() == "error"
&& matches!(sig.data.as_slice(), [val] if val.as_str().map(|s| s == "Not in a minibuffer").unwrap_or(false))
));
}
#[test]
fn builtin_abort_minibuffers_rejects_args() {
crate::test_utils::init_test_tracing();
let result = builtin_abort_minibuffers(vec![Value::NIL]);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-number-of-arguments"
));
}
#[test]
fn builtin_abort_recursive_edit_signals_user_error() {
crate::test_utils::init_test_tracing();
let mut eval = super::super::eval::Context::new();
let result = builtin_abort_recursive_edit(&mut eval, vec![]);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "user-error"
));
}
#[test]
fn builtin_abort_recursive_edit_rejects_args() {
crate::test_utils::init_test_tracing();
let mut eval = super::super::eval::Context::new();
let result = builtin_abort_recursive_edit(&mut eval, vec![Value::NIL]);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-number-of-arguments"
));
}
#[test]
fn builtin_read_file_name_signals_end_of_file() {
crate::test_utils::init_test_tracing();
let mut eval = super::super::eval::Context::new();
let result = builtin_read_file_name(
&mut eval,
vec![
Value::string("File: "),
Value::NIL,
Value::NIL,
Value::NIL,
Value::string("/tmp/test.txt"),
],
);
assert!(matches!(
result,
Err(Flow::Signal(sig))
if sig.symbol_name() == "end-of-file"
&& matches!(sig.data.as_slice(), [val] if val.as_str().map(|s| s == "Error reading from stdin").unwrap_or(false))
));
}
#[test]
fn builtin_read_file_name_validates_dir_default_and_initial() {
crate::test_utils::init_test_tracing();
let mut eval = super::super::eval::Context::new();
let bad_dir =
builtin_read_file_name(&mut eval, vec![Value::string("File: "), Value::fixnum(1)]);
assert!(matches!(
bad_dir,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-type-argument"
));
let bad_default = builtin_read_file_name(
&mut eval,
vec![Value::string("File: "), Value::NIL, Value::fixnum(1)],
);
assert!(matches!(
bad_default,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-type-argument"
));
let bad_initial = builtin_read_file_name(
&mut eval,
vec![
Value::string("File: "),
Value::NIL,
Value::NIL,
Value::NIL,
Value::fixnum(1),
],
);
assert!(matches!(
bad_initial,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-type-argument"
));
}
#[test]
fn builtin_read_file_name_rejects_more_than_six_args() {
crate::test_utils::init_test_tracing();
let mut eval = super::super::eval::Context::new();
let result = builtin_read_file_name(
&mut eval,
vec![
Value::string("File: "),
Value::NIL,
Value::NIL,
Value::NIL,
Value::NIL,
Value::NIL,
Value::NIL,
],
);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-number-of-arguments"
));
}
#[test]
fn builtin_read_buffer_signals_end_of_file() {
crate::test_utils::init_test_tracing();
let mut eval = super::super::eval::Context::new();
let result = builtin_read_buffer(
&mut eval,
vec![Value::string("Buffer: "), Value::string("*scratch*")],
);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "end-of-file"
));
}
#[test]
fn builtin_read_directory_name_rejects_more_than_five_args() {
crate::test_utils::init_test_tracing();
let mut eval = super::super::eval::Context::new();
let result = builtin_read_directory_name(
&mut eval,
vec![
Value::string("Directory: "),
Value::NIL,
Value::NIL,
Value::NIL,
Value::NIL,
Value::NIL,
],
);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-number-of-arguments"
));
}
#[test]
fn builtin_read_directory_name_validates_dir_default_and_initial() {
crate::test_utils::init_test_tracing();
let mut eval = super::super::eval::Context::new();
let bad_dir = builtin_read_directory_name(
&mut eval,
vec![Value::string("Directory: "), Value::fixnum(1)],
);
assert!(matches!(
bad_dir,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-type-argument"
));
let bad_default = builtin_read_directory_name(
&mut eval,
vec![Value::string("Directory: "), Value::NIL, Value::fixnum(1)],
);
assert!(matches!(
bad_default,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-type-argument"
));
let bad_initial = builtin_read_directory_name(
&mut eval,
vec![
Value::string("Directory: "),
Value::NIL,
Value::NIL,
Value::NIL,
Value::fixnum(1),
],
);
assert!(matches!(
bad_initial,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-type-argument"
));
}
#[test]
fn builtin_read_buffer_rejects_more_than_four_args() {
crate::test_utils::init_test_tracing();
let mut eval = super::super::eval::Context::new();
let result = builtin_read_buffer(
&mut eval,
vec![
Value::string("Buffer: "),
Value::NIL,
Value::NIL,
Value::NIL,
Value::NIL,
],
);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-number-of-arguments"
));
}
#[test]
fn builtin_read_command_rejects_more_than_two_args() {
crate::test_utils::init_test_tracing();
let mut eval = super::super::eval::Context::new();
let result = builtin_read_command(
&mut eval,
vec![Value::string("Command: "), Value::NIL, Value::NIL],
);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-number-of-arguments"
));
}
#[test]
fn builtin_read_variable_rejects_more_than_two_args() {
crate::test_utils::init_test_tracing();
let mut eval = super::super::eval::Context::new();
let result = builtin_read_variable(
&mut eval,
vec![Value::string("Variable: "), Value::NIL, Value::NIL],
);
assert!(matches!(
result,
Err(Flow::Signal(sig)) if sig.symbol_name() == "wrong-number-of-arguments"
));
}
#[test]
fn value_to_string_list_from_list() {
crate::test_utils::init_test_tracing();
let list = Value::list(vec![
Value::string("foo"),
Value::string("bar"),
Value::string("baz"),
]);
let result = value_to_string_list(&list);
assert_eq!(result, vec!["foo", "bar", "baz"]);
}
#[test]
fn value_to_string_list_from_alist() {
crate::test_utils::init_test_tracing();
let alist = Value::list(vec![
Value::cons(Value::string("key1"), Value::fixnum(1)),
Value::cons(Value::string("key2"), Value::fixnum(2)),
]);
let result = value_to_string_list(&alist);
assert_eq!(result, vec!["key1", "key2"]);
}
#[test]
fn value_to_string_list_from_nil() {
crate::test_utils::init_test_tracing();
let result = value_to_string_list(&Value::NIL);
assert!(result.is_empty());
}
#[test]
fn value_to_string_list_from_vector() {
crate::test_utils::init_test_tracing();
let vec = Value::vector(vec![Value::string("a"), Value::string("b")]);
let result = value_to_string_list(&vec);
assert_eq!(result, vec!["a", "b"]);
}