use super::*;
use crate::emacs_core::value::{ValueKind, VecLikeType};
#[test]
fn make_char_table_basic() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("syntax-table"), Value::NIL);
assert!(is_char_table(&ct));
assert!(!is_bool_vector(&ct));
}
#[test]
fn make_char_table_with_default() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("syntax-table"), Value::fixnum(42));
assert!(is_char_table(&ct));
let def = builtin_char_table_range(vec![ct, Value::NIL]).unwrap();
assert!(def.is_fixnum());
}
#[test]
fn char_table_p_predicate() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
assert!(builtin_char_table_p(vec![ct]).unwrap().is_t());
assert!(
builtin_char_table_p(vec![Value::fixnum(5)])
.unwrap()
.is_nil()
);
assert!(builtin_char_table_p(vec![Value::NIL]).unwrap().is_nil());
}
#[test]
fn set_and_get_single_char() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
builtin_set_char_table_range(vec![ct, Value::fixnum(65), Value::symbol("letter-a")]).unwrap();
let val = builtin_char_table_range(vec![ct, Value::fixnum(65)]).unwrap();
assert!(val.is_symbol_named("letter-a"));
}
#[test]
fn lookup_falls_back_to_default() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::symbol("default-val"));
let val = builtin_char_table_range(vec![ct, Value::fixnum(90)]).unwrap();
assert!(val.is_symbol_named("default-val"));
}
#[test]
fn set_range_cons() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
let range = Value::cons(Value::fixnum(65), Value::fixnum(67));
builtin_set_char_table_range(vec![ct, range, Value::symbol("abc")]).unwrap();
for ch in 65..=67 {
let val = builtin_char_table_range(vec![ct, Value::fixnum(ch)]).unwrap();
assert!(val.is_symbol_named("abc"));
}
let val = builtin_char_table_range(vec![ct, Value::fixnum(68)]).unwrap();
assert!(val.is_nil());
}
#[test]
fn set_default_via_range_nil() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
builtin_set_char_table_range(vec![ct, Value::NIL, Value::fixnum(999)]).unwrap();
let def = builtin_char_table_range(vec![ct, Value::NIL]).unwrap();
assert!(def.is_fixnum());
}
#[test]
fn set_range_t_sets_default_value() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::fixnum(0));
builtin_set_char_table_range(vec![ct, Value::T, Value::fixnum(5)]).unwrap();
let a = builtin_char_table_range(vec![ct, Value::fixnum('a' as i64)]).unwrap();
let b = builtin_char_table_range(vec![ct, Value::fixnum('b' as i64)]).unwrap();
let def = builtin_char_table_range(vec![ct, Value::NIL]).unwrap();
assert!(a.is_fixnum());
assert!(b.is_fixnum());
assert!(def.is_fixnum());
}
#[test]
fn set_range_t_allows_single_char_override() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::fixnum(0));
builtin_set_char_table_range(vec![ct, Value::T, Value::fixnum(5)]).unwrap();
builtin_set_char_table_range(vec![ct, Value::fixnum('a' as i64), Value::fixnum(9)]).unwrap();
let a = builtin_char_table_range(vec![ct, Value::fixnum('a' as i64)]).unwrap();
let b = builtin_char_table_range(vec![ct, Value::fixnum('b' as i64)]).unwrap();
let def = builtin_char_table_range(vec![ct, Value::NIL]).unwrap();
assert!(a.is_fixnum());
assert!(b.is_fixnum());
assert!(def.is_fixnum());
}
#[test]
fn later_t_write_overrides_prior_specific_entries() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
builtin_set_char_table_range(vec![ct, Value::fixnum('a' as i64), Value::fixnum(9)]).unwrap();
builtin_set_char_table_range(vec![
ct,
Value::cons(Value::fixnum('0' as i64), Value::fixnum('9' as i64)),
Value::fixnum(7),
])
.unwrap();
builtin_set_char_table_range(vec![ct, Value::T, Value::fixnum(5)]).unwrap();
let a = builtin_char_table_range(vec![ct, Value::fixnum('a' as i64)]).unwrap();
let five = builtin_char_table_range(vec![ct, Value::fixnum('5' as i64)]).unwrap();
let def = builtin_char_table_range(vec![ct, Value::NIL]).unwrap();
assert!(a.is_fixnum());
assert!(five.is_fixnum());
assert!(def.is_nil());
}
#[test]
fn parent_chain_lookup() {
crate::test_utils::init_test_tracing();
let parent = make_char_table_value(Value::symbol("test"), Value::NIL);
builtin_set_char_table_range(vec![
parent,
Value::fixnum(65),
Value::symbol("from-parent"),
])
.unwrap();
let child = make_char_table_value(Value::symbol("test"), Value::NIL);
builtin_set_char_table_parent(vec![child, parent]).unwrap();
let val = builtin_char_table_range(vec![child, Value::fixnum(65)]).unwrap();
assert!(val.is_symbol_named("from-parent"));
builtin_set_char_table_range(vec![child, Value::fixnum(65), Value::symbol("child-val")])
.unwrap();
let val = builtin_char_table_range(vec![child, Value::fixnum(65)]).unwrap();
assert!(val.is_symbol_named("child-val"));
}
#[test]
fn char_table_parent_get_set() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
let p = builtin_char_table_parent(vec![ct]).unwrap();
assert!(p.is_nil());
let parent = make_char_table_value(Value::symbol("parent"), Value::NIL);
builtin_set_char_table_parent(vec![ct, parent]).unwrap();
let p = builtin_char_table_parent(vec![ct]).unwrap();
assert!(is_char_table(&p));
}
#[test]
fn set_char_table_parent_nil() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
let parent = make_char_table_value(Value::symbol("parent"), Value::NIL);
builtin_set_char_table_parent(vec![ct, parent]).unwrap();
builtin_set_char_table_parent(vec![ct, Value::NIL]).unwrap();
let p = builtin_char_table_parent(vec![ct]).unwrap();
assert!(p.is_nil());
}
#[test]
fn set_char_table_parent_wrong_type() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
let result = builtin_set_char_table_parent(vec![ct, Value::fixnum(5)]);
assert!(result.is_err());
}
#[test]
fn char_table_extra_slot_basic() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
let result = builtin_char_table_extra_slot(vec![ct, Value::fixnum(0)]);
assert!(result.is_err());
let set_result =
builtin_set_char_table_extra_slot(vec![ct, Value::fixnum(0), Value::symbol("extra0")]);
assert!(set_result.is_err());
}
#[test]
fn char_table_extra_slot_preserves_data() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
builtin_set_char_table_range(vec![ct, Value::fixnum(65), Value::symbol("a-val")]).unwrap();
assert!(
builtin_set_char_table_extra_slot(vec![ct, Value::fixnum(0), Value::symbol("e0")]).is_err()
);
let val = builtin_char_table_range(vec![ct, Value::fixnum(65)]).unwrap();
assert!(val.is_symbol_named("a-val"));
assert!(builtin_char_table_extra_slot(vec![ct, Value::fixnum(0)]).is_err());
}
#[test]
fn char_table_subtype() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("syntax-table"), Value::NIL);
let st = builtin_char_table_subtype(vec![ct]).unwrap();
assert!(st.is_symbol_named("syntax-table"));
}
#[test]
fn char_table_overwrite_entry() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
builtin_set_char_table_range(vec![ct, Value::fixnum(65), Value::fixnum(1)]).unwrap();
builtin_set_char_table_range(vec![ct, Value::fixnum(65), Value::fixnum(2)]).unwrap();
let val = builtin_char_table_range(vec![ct, Value::fixnum(65)]).unwrap();
assert!(val.is_fixnum());
}
#[test]
fn later_range_overrides_earlier_single_entry() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
builtin_set_char_table_range(vec![ct, Value::fixnum('M' as i64), Value::symbol("single")])
.unwrap();
builtin_set_char_table_range(vec![
ct,
Value::cons(Value::fixnum('A' as i64), Value::fixnum('Z' as i64)),
Value::symbol("range"),
])
.unwrap();
let val = builtin_char_table_range(vec![ct, Value::fixnum('M' as i64)]).unwrap();
assert!(val.is_symbol_named("range"));
}
#[test]
fn explicit_nil_entry_inherits_from_parent() {
crate::test_utils::init_test_tracing();
let parent = make_char_table_value(Value::symbol("test"), Value::NIL);
builtin_set_char_table_range(vec![
parent,
Value::fixnum('a' as i64),
Value::symbol("parent-a"),
])
.unwrap();
let child = make_char_table_value(Value::symbol("test"), Value::NIL);
builtin_set_char_table_parent(vec![child, parent]).unwrap();
builtin_set_char_table_range(vec![child, Value::fixnum('a' as i64), Value::NIL]).unwrap();
let val = builtin_char_table_range(vec![child, Value::fixnum('a' as i64)]).unwrap();
assert!(val.is_symbol_named("parent-a"));
}
#[test]
fn set_char_table_parent_rejects_cycles() {
crate::test_utils::init_test_tracing();
let parent = make_char_table_value(Value::symbol("test"), Value::NIL);
let child = make_char_table_value(Value::symbol("test"), Value::NIL);
builtin_set_char_table_parent(vec![child, parent]).unwrap();
let result = builtin_set_char_table_parent(vec![parent, child]);
assert!(result.is_err());
}
#[test]
fn map_char_table_coalesces_ranges_after_single_override() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
builtin_set_char_table_range(vec![
ct,
Value::cons(Value::fixnum('A' as i64), Value::fixnum('Z' as i64)),
Value::symbol("upper"),
])
.unwrap();
builtin_set_char_table_range(vec![ct, Value::fixnum('M' as i64), Value::symbol("middle")])
.unwrap();
let entries = ct_resolved_entries(&ct);
assert_eq!(entries.len(), 3);
assert_eq!(
entries,
vec![
(
Value::cons(Value::fixnum('A' as i64), Value::fixnum('L' as i64)),
Value::symbol("upper"),
),
(Value::fixnum('M' as i64), Value::symbol("middle")),
(
Value::cons(Value::fixnum('N' as i64), Value::fixnum('Z' as i64)),
Value::symbol("upper"),
),
]
);
}
#[test]
fn char_table_p_on_plain_vector() {
crate::test_utils::init_test_tracing();
let v = Value::vector(vec![Value::fixnum(1), Value::fixnum(2)]);
assert!(!is_char_table(&v));
}
#[test]
fn char_table_wrong_type_signals() {
crate::test_utils::init_test_tracing();
let result = builtin_char_table_range(vec![Value::fixnum(5), Value::fixnum(65)]);
assert!(result.is_err());
let result =
builtin_set_char_table_range(vec![Value::NIL, Value::fixnum(65), Value::fixnum(1)]);
assert!(result.is_err());
let result = builtin_char_table_parent(vec![Value::string("not-a-table")]);
assert!(result.is_err());
}
#[test]
fn char_table_wrong_arg_count() {
crate::test_utils::init_test_tracing();
assert!(builtin_char_table_p(vec![]).is_err());
assert!(builtin_char_table_range(vec![Value::NIL]).is_err());
assert!(builtin_set_char_table_range(vec![Value::NIL, Value::NIL]).is_err());
}
#[test]
fn char_table_char_key() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
builtin_set_char_table_range(vec![ct, Value::char('Z'), Value::symbol("zee")]).unwrap();
let val = builtin_char_table_range(vec![ct, Value::fixnum('Z' as i64)]).unwrap();
assert!(val.is_symbol_named("zee"));
}
#[test]
fn parent_default_fallback() {
crate::test_utils::init_test_tracing();
let parent = make_char_table_value(Value::symbol("test"), Value::symbol("parent-default"));
let child = make_char_table_value(Value::symbol("test"), Value::NIL);
builtin_set_char_table_parent(vec![child, parent]).unwrap();
let val = builtin_char_table_range(vec![child, Value::fixnum(100)]).unwrap();
assert!(val.is_symbol_named("parent-default"));
}
#[test]
fn non_nil_child_default_overrides_parent_lookup() {
crate::test_utils::init_test_tracing();
let parent = make_char_table_value(Value::symbol("test"), Value::fixnum(8));
let child = make_char_table_value(Value::symbol("test"), Value::fixnum(0));
builtin_set_char_table_parent(vec![child, parent]).unwrap();
let val = builtin_char_table_range(vec![child, Value::fixnum('a' as i64)]).unwrap();
assert!(val.is_fixnum());
}
#[test]
fn make_bool_vector_basic() {
crate::test_utils::init_test_tracing();
let bv = builtin_make_bool_vector(vec![Value::fixnum(5), Value::NIL]).unwrap();
assert!(is_bool_vector(&bv));
assert!(!is_char_table(&bv));
}
#[test]
fn bool_vector_constructor_from_rest_args() {
crate::test_utils::init_test_tracing();
let bv = builtin_bool_vector(vec![
Value::T,
Value::NIL,
Value::fixnum(0),
Value::symbol("x"),
])
.unwrap();
assert!(is_bool_vector(&bv));
assert_bv_bits(&bv, &[true, false, true, true]);
let empty = builtin_bool_vector(vec![]).unwrap();
assert!(is_bool_vector(&empty));
assert_bv_bits(&empty, &[]);
}
#[test]
fn make_bool_vector_all_true() {
crate::test_utils::init_test_tracing();
let bv = builtin_make_bool_vector(vec![Value::fixnum(4), Value::T]).unwrap();
let count = builtin_bool_vector_count_population(vec![bv]).unwrap();
assert!(count.is_fixnum());
}
#[test]
fn make_bool_vector_all_false() {
crate::test_utils::init_test_tracing();
let bv = builtin_make_bool_vector(vec![Value::fixnum(4), Value::NIL]).unwrap();
let count = builtin_bool_vector_count_population(vec![bv]).unwrap();
assert!(count.is_fixnum());
}
#[test]
fn bool_vector_p_predicate() {
crate::test_utils::init_test_tracing();
let bv = builtin_make_bool_vector(vec![Value::fixnum(3), Value::NIL]).unwrap();
assert!(builtin_bool_vector_p(vec![bv]).unwrap().is_t());
assert!(
builtin_bool_vector_p(vec![Value::fixnum(0)])
.unwrap()
.is_nil()
);
}
#[test]
fn bool_vector_intersection() {
crate::test_utils::init_test_tracing();
let a = make_bv(&[true, true, false, false]);
let b = make_bv(&[true, false, true, false]);
let result = builtin_bool_vector_intersection(vec![a, b]).unwrap();
assert_bv_bits(&result, &[true, false, false, false]);
}
#[test]
fn bool_vector_union() {
crate::test_utils::init_test_tracing();
let a = make_bv(&[true, true, false, false]);
let b = make_bv(&[true, false, true, false]);
let result = builtin_bool_vector_union(vec![a, b]).unwrap();
assert_bv_bits(&result, &[true, true, true, false]);
}
#[test]
fn bool_vector_exclusive_or() {
crate::test_utils::init_test_tracing();
let a = make_bv(&[true, true, false, false]);
let b = make_bv(&[true, false, true, false]);
let result = builtin_bool_vector_exclusive_or(vec![a, b]).unwrap();
assert_bv_bits(&result, &[false, true, true, false]);
}
#[test]
fn bool_vector_not() {
crate::test_utils::init_test_tracing();
let a = make_bv(&[true, false, true, false]);
let result = builtin_bool_vector_not(vec![a]).unwrap();
assert_bv_bits(&result, &[false, true, false, true]);
}
#[test]
fn bool_vector_not_into_dest() {
crate::test_utils::init_test_tracing();
let a = make_bv(&[false, false, true]);
let dest = make_bv(&[false, false, false]);
let result = builtin_bool_vector_not(vec![a, dest]).unwrap();
assert_eq!(result, dest);
assert_bv_bits(&dest, &[true, true, false]);
}
#[test]
fn bool_vector_set_difference() {
crate::test_utils::init_test_tracing();
let a = make_bv(&[true, true, false, true]);
let b = make_bv(&[false, true, true, false]);
let result = builtin_bool_vector_set_difference(vec![a, b]).unwrap();
assert_bv_bits(&result, &[true, false, false, true]);
}
#[test]
fn bool_vector_count_consecutive() {
crate::test_utils::init_test_tracing();
let bv = make_bv(&[true, true, false, false, true, true]);
let count_true_start =
builtin_bool_vector_count_consecutive(vec![bv, Value::T, Value::fixnum(0)]).unwrap();
let count_false_middle =
builtin_bool_vector_count_consecutive(vec![bv, Value::NIL, Value::fixnum(2)]).unwrap();
let count_true_mismatch =
builtin_bool_vector_count_consecutive(vec![bv, Value::T, Value::fixnum(2)]).unwrap();
assert!(count_true_start.is_fixnum());
assert!(count_false_middle.is_fixnum());
assert!(count_true_mismatch.is_fixnum());
}
#[test]
fn bool_vector_subsetp_true() {
crate::test_utils::init_test_tracing();
let a = make_bv(&[true, false, false]);
let b = make_bv(&[true, true, false]);
let result = builtin_bool_vector_subsetp(vec![a, b]).unwrap();
assert!(result.is_t());
}
#[test]
fn bool_vector_subsetp_false() {
crate::test_utils::init_test_tracing();
let a = make_bv(&[true, false, true]);
let b = make_bv(&[true, true, false]);
let result = builtin_bool_vector_subsetp(vec![a, b]).unwrap();
assert!(result.is_nil());
}
#[test]
fn bool_vector_count_population_mixed() {
crate::test_utils::init_test_tracing();
let bv = make_bv(&[true, false, true, true, false]);
let count = builtin_bool_vector_count_population(vec![bv]).unwrap();
assert!(count.is_fixnum());
}
#[test]
fn bool_vector_empty() {
crate::test_utils::init_test_tracing();
let bv = builtin_make_bool_vector(vec![Value::fixnum(0), Value::NIL]).unwrap();
assert!(is_bool_vector(&bv));
let count = builtin_bool_vector_count_population(vec![bv]).unwrap();
assert!(count.is_fixnum());
}
#[test]
fn bool_vector_negative_length() {
crate::test_utils::init_test_tracing();
let result = builtin_make_bool_vector(vec![Value::fixnum(-1), Value::NIL]);
assert!(result.is_err());
}
#[test]
fn bool_vector_wrong_type_signals() {
crate::test_utils::init_test_tracing();
let result = builtin_bool_vector_count_population(vec![Value::fixnum(0)]);
assert!(result.is_err());
}
#[test]
fn bool_vector_mismatched_length() {
crate::test_utils::init_test_tracing();
let a = make_bv(&[true, false]);
let b = make_bv(&[true]);
let result = builtin_bool_vector_intersection(vec![a, b]);
assert!(result.is_err());
}
#[test]
fn bool_vector_intersection_into_dest() {
crate::test_utils::init_test_tracing();
let a = make_bv(&[true, true, false]);
let b = make_bv(&[false, true, true]);
let dest = make_bv(&[false, false, false]);
let result = builtin_bool_vector_intersection(vec![a, b, dest]).unwrap();
assert_bv_bits(&result, &[false, true, false]);
assert_bv_bits(&dest, &[false, true, false]);
}
#[test]
fn bool_vector_union_into_dest() {
crate::test_utils::init_test_tracing();
let a = make_bv(&[true, false, false]);
let b = make_bv(&[false, true, false]);
let dest = make_bv(&[false, false, false]);
builtin_bool_vector_union(vec![a, b, dest]).unwrap();
assert_bv_bits(&dest, &[true, true, false]);
}
#[test]
fn is_predicates_disjoint() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
let bv = builtin_make_bool_vector(vec![Value::fixnum(3), Value::NIL]).unwrap();
let v = Value::vector(vec![Value::fixnum(1)]);
assert!(is_char_table(&ct));
assert!(!is_bool_vector(&ct));
assert!(!is_char_table(&bv));
assert!(is_bool_vector(&bv));
assert!(!is_char_table(&v));
assert!(!is_bool_vector(&v));
}
#[test]
fn bool_vector_wrong_arg_count() {
crate::test_utils::init_test_tracing();
assert!(builtin_make_bool_vector(vec![]).is_err());
assert!(builtin_bool_vector_p(vec![]).is_err());
assert!(builtin_bool_vector_subsetp(vec![Value::NIL]).is_err());
assert!(builtin_bool_vector_not(vec![]).is_err());
assert!(builtin_bool_vector_not(vec![Value::NIL, Value::NIL, Value::NIL]).is_err());
}
#[test]
fn char_table_range_invalid_range_type() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
let result = builtin_set_char_table_range(vec![ct, Value::string("invalid"), Value::fixnum(1)]);
assert!(result.is_err());
}
#[test]
fn char_table_range_reverse_cons_errors() {
crate::test_utils::init_test_tracing();
let ct = make_char_table_value(Value::symbol("test"), Value::NIL);
let range = Value::cons(Value::fixnum(70), Value::fixnum(65)); let result = builtin_set_char_table_range(vec![ct, range, Value::fixnum(1)]);
assert!(result.is_err());
}
fn make_bv(bits: &[bool]) -> Value {
bv_from_bits(bits)
}
fn assert_bv_bits(bv: &Value, expected: &[bool]) {
assert!(bv.is_vector(), "expected a vector");
let vec = bv.as_vector_data().unwrap().clone();
let len = bv_length(&vec) as usize;
assert_eq!(len, expected.len(), "bool-vector length mismatch");
let bits = bv_bits(&vec);
assert_eq!(bits, expected);
}