neovm-core 0.0.2

Core runtime structures for NeoVM
use super::*;
use crate::emacs_core::value::{ValueKind, VecLikeType};

#[test]
fn compose_region_internal_min_args() {
    crate::test_utils::init_test_tracing();
    let mut eval = super::super::eval::Context::new();
    {
        let buffer = eval.buffers.current_buffer_mut().expect("current buffer");
        buffer.insert("0123456789");
    }
    let result =
        builtin_compose_region_internal(&mut eval, vec![Value::fixnum(1), Value::fixnum(10)]);
    assert!(result.is_ok());
    assert!(result.unwrap().is_nil());
}

#[test]
fn compose_region_internal_max_args() {
    crate::test_utils::init_test_tracing();
    let mut eval = super::super::eval::Context::new();
    {
        let buffer = eval.buffers.current_buffer_mut().expect("current buffer");
        buffer.insert("0123456789");
    }
    let result = builtin_compose_region_internal(
        &mut eval,
        vec![Value::fixnum(1), Value::fixnum(10), Value::NIL, Value::NIL],
    );
    assert!(result.is_ok());
    assert!(result.unwrap().is_nil());
}

#[test]
fn compose_region_internal_too_few_args() {
    crate::test_utils::init_test_tracing();
    let mut eval = super::super::eval::Context::new();
    let result = builtin_compose_region_internal(&mut eval, vec![Value::fixnum(1)]);
    assert!(result.is_err());
}

#[test]
fn compose_region_internal_too_many_args() {
    crate::test_utils::init_test_tracing();
    let mut eval = super::super::eval::Context::new();
    let result = builtin_compose_region_internal(
        &mut eval,
        vec![
            Value::fixnum(1),
            Value::fixnum(10),
            Value::NIL,
            Value::NIL,
            Value::NIL,
        ],
    );
    assert!(result.is_err());
}

#[test]
fn compose_region_internal_rejects_non_integer_positions() {
    crate::test_utils::init_test_tracing();
    let mut eval = super::super::eval::Context::new();
    let result =
        builtin_compose_region_internal(&mut eval, vec![Value::symbol("x"), Value::fixnum(10)]);
    assert!(result.is_err());
    let result =
        builtin_compose_region_internal(&mut eval, vec![Value::fixnum(1), Value::symbol("y")]);
    assert!(result.is_err());
}

#[test]
fn compose_region_internal_eval_range_checks() {
    crate::test_utils::init_test_tracing();
    let mut eval = super::super::eval::Context::new();
    {
        let buffer = eval.buffers.current_buffer_mut().expect("current buffer");
        buffer.insert("abc");
    }
    let ok = builtin_compose_region_internal(&mut eval, vec![Value::fixnum(1), Value::fixnum(3)]);
    assert!(ok.is_ok());

    let out_of_range =
        builtin_compose_region_internal(&mut eval, vec![Value::fixnum(0), Value::fixnum(0)]);
    assert!(out_of_range.is_err());
}

#[test]
fn compose_string_internal_returns_string() {
    crate::test_utils::init_test_tracing();
    let s = Value::string("hello");
    let result = builtin_compose_string_internal(vec![s, Value::fixnum(0), Value::fixnum(5)]);
    assert!(result.is_ok());
    assert_eq!(result.unwrap().as_utf8_str(), Some("hello"));
}

#[test]
fn compose_string_internal_with_optional_args() {
    crate::test_utils::init_test_tracing();
    let s = Value::string("hello");
    let result = builtin_compose_string_internal(vec![
        s,
        Value::fixnum(0),
        Value::fixnum(5),
        Value::NIL,
        Value::NIL,
    ]);
    assert!(result.is_ok());
    assert_eq!(result.unwrap().as_utf8_str(), Some("hello"));
}

#[test]
fn compose_string_internal_too_few_args() {
    crate::test_utils::init_test_tracing();
    let result = builtin_compose_string_internal(vec![Value::string("hi"), Value::fixnum(0)]);
    assert!(result.is_err());
}

#[test]
fn compose_string_internal_type_checks() {
    crate::test_utils::init_test_tracing();
    let non_string =
        builtin_compose_string_internal(vec![Value::fixnum(1), Value::fixnum(0), Value::fixnum(1)]);
    assert!(non_string.is_err());
    let bad_start = builtin_compose_string_internal(vec![
        Value::string("abc"),
        Value::symbol("x"),
        Value::fixnum(1),
    ]);
    assert!(bad_start.is_err());
    let bad_end = builtin_compose_string_internal(vec![
        Value::string("abc"),
        Value::fixnum(0),
        Value::symbol("y"),
    ]);
    assert!(bad_end.is_err());
}

#[test]
fn compose_string_internal_range_checks() {
    crate::test_utils::init_test_tracing();
    let ok = builtin_compose_string_internal(vec![
        Value::string("abc"),
        Value::fixnum(0),
        Value::fixnum(0),
    ]);
    assert!(ok.is_ok());

    let start_gt_end = builtin_compose_string_internal(vec![
        Value::string("abc"),
        Value::fixnum(2),
        Value::fixnum(1),
    ]);
    assert!(start_gt_end.is_err());

    let end_oob = builtin_compose_string_internal(vec![
        Value::string("abc"),
        Value::fixnum(0),
        Value::fixnum(4),
    ]);
    assert!(end_oob.is_err());

    let start_neg = builtin_compose_string_internal(vec![
        Value::string("abc"),
        Value::fixnum(-1),
        Value::fixnum(1),
    ]);
    assert!(start_neg.is_err());
}

#[test]
fn compose_string_internal_accepts_raw_unibyte_ranges() {
    crate::test_utils::init_test_tracing();
    let raw = Value::heap_string(crate::heap_types::LispString::from_unibyte(vec![0xFF]));
    let result = builtin_compose_string_internal(vec![raw, Value::fixnum(0), Value::fixnum(1)]);
    assert!(result.is_ok());
    let value = result.unwrap();
    let string = value
        .as_lisp_string()
        .expect("compose-string-internal string");
    assert!(!string.is_multibyte());
    assert_eq!(string.as_bytes(), &[0xFF]);
}

#[test]
fn find_composition_internal_returns_nil() {
    crate::test_utils::init_test_tracing();
    let result = builtin_find_composition_internal(vec![
        Value::fixnum(1),
        Value::fixnum(100),
        Value::NIL,
        Value::NIL,
    ]);
    assert!(result.is_ok());
    assert!(result.unwrap().is_nil());
}

#[test]
fn find_composition_internal_wrong_arity() {
    crate::test_utils::init_test_tracing();
    let result = builtin_find_composition_internal(vec![Value::fixnum(1)]);
    assert!(result.is_err());
}

#[test]
fn find_composition_internal_type_checks() {
    crate::test_utils::init_test_tracing();
    let bad_pos = builtin_find_composition_internal(vec![
        Value::symbol("x"),
        Value::fixnum(10),
        Value::NIL,
        Value::NIL,
    ]);
    assert!(bad_pos.is_err());

    let bad_limit = builtin_find_composition_internal(vec![
        Value::fixnum(1),
        Value::symbol("y"),
        Value::NIL,
        Value::NIL,
    ]);
    assert!(bad_limit.is_err());

    let bad_string = builtin_find_composition_internal(vec![
        Value::fixnum(1),
        Value::NIL,
        Value::fixnum(1),
        Value::NIL,
    ]);
    assert!(bad_string.is_err());
}

#[test]
fn find_composition_internal_position_range_checks() {
    crate::test_utils::init_test_tracing();
    let zero = builtin_find_composition_internal(vec![
        Value::fixnum(0),
        Value::NIL,
        Value::NIL,
        Value::NIL,
    ]);
    assert!(zero.is_err());

    let negative = builtin_find_composition_internal(vec![
        Value::fixnum(-1),
        Value::NIL,
        Value::NIL,
        Value::NIL,
    ]);
    assert!(negative.is_err());
}

#[test]
fn composition_get_gstring_returns_vector_shape() {
    crate::test_utils::init_test_tracing();
    let result = builtin_composition_get_gstring(vec![
        Value::fixnum(0),
        Value::fixnum(1),
        Value::NIL,
        Value::string("ab"),
    ]);
    let result = result.unwrap();
    if !result.is_vector() {
        panic!("expected vector gstring");
    };
    let gs = result.as_vector_data().unwrap().clone();
    assert!(!gs.is_empty());
    assert!(gs[0].is_vector());
}

#[test]
fn composition_get_gstring_preserves_raw_unibyte_character_codes() {
    crate::test_utils::init_test_tracing();
    let raw = Value::heap_string(crate::heap_types::LispString::from_unibyte(vec![0xFF]));
    let result =
        builtin_composition_get_gstring(vec![Value::fixnum(0), Value::fixnum(1), Value::NIL, raw])
            .unwrap();
    let gs = result.as_vector_data().expect("gstring vector").clone();
    let glyph = gs[2].as_vector_data().expect("glyph entry").clone();
    assert_eq!(glyph[2], Value::fixnum(0xFF));
    assert_eq!(glyph[3], Value::fixnum(0xFF));
}

#[test]
fn composition_get_gstring_wrong_arity() {
    crate::test_utils::init_test_tracing();
    let result = builtin_composition_get_gstring(vec![Value::fixnum(0)]);
    assert!(result.is_err());
}

#[test]
fn composition_get_gstring_type_checks() {
    crate::test_utils::init_test_tracing();
    let bad_from = builtin_composition_get_gstring(vec![
        Value::symbol("x"),
        Value::fixnum(5),
        Value::NIL,
        Value::string("hello"),
    ]);
    assert!(bad_from.is_err());

    let bad_to = builtin_composition_get_gstring(vec![
        Value::fixnum(0),
        Value::symbol("y"),
        Value::NIL,
        Value::string("hello"),
    ]);
    assert!(bad_to.is_err());

    let bad_string = builtin_composition_get_gstring(vec![
        Value::fixnum(0),
        Value::fixnum(5),
        Value::NIL,
        Value::fixnum(1),
    ]);
    assert!(bad_string.is_err());
}

#[test]
fn composition_get_gstring_range_errors() {
    crate::test_utils::init_test_tracing();
    let from_gt_to = builtin_composition_get_gstring(vec![
        Value::fixnum(2),
        Value::fixnum(1),
        Value::NIL,
        Value::string("ab"),
    ]);
    assert!(from_gt_to.is_err());

    let zero_length = builtin_composition_get_gstring(vec![
        Value::fixnum(0),
        Value::fixnum(0),
        Value::NIL,
        Value::string("ab"),
    ]);
    assert!(zero_length.is_err());
}

#[test]
fn clear_composition_cache_no_args() {
    crate::test_utils::init_test_tracing();
    let result = builtin_clear_composition_cache(vec![]);
    assert!(result.is_ok());
    assert!(result.unwrap().is_nil());
}

#[test]
fn clear_composition_cache_too_many_args() {
    crate::test_utils::init_test_tracing();
    let result = builtin_clear_composition_cache(vec![Value::NIL]);
    assert!(result.is_err());
}

#[test]
fn composition_sort_rules_nil_returns_nil() {
    crate::test_utils::init_test_tracing();
    let result = builtin_composition_sort_rules(vec![Value::NIL]).unwrap();
    assert!(result.is_nil());
}

#[test]
fn composition_sort_rules_rejects_non_lists() {
    crate::test_utils::init_test_tracing();
    let result = builtin_composition_sort_rules(vec![Value::vector(vec![Value::fixnum(1)])]);
    assert!(result.is_err());
}

#[test]
fn composition_sort_rules_rejects_invalid_rules() {
    crate::test_utils::init_test_tracing();
    let rules = Value::list(vec![Value::fixnum(1), Value::fixnum(2), Value::fixnum(3)]);
    let result = builtin_composition_sort_rules(vec![rules]);
    assert!(result.is_err());
}

#[test]
fn composition_sort_rules_accepts_cons_rules() {
    crate::test_utils::init_test_tracing();
    let rules = Value::list(vec![Value::cons(Value::fixnum(1), Value::fixnum(2))]);
    let result = builtin_composition_sort_rules(vec![rules]).unwrap();
    assert_eq!(result, rules);
}

#[test]
fn composition_sort_rules_wrong_arity() {
    crate::test_utils::init_test_tracing();
    let result = builtin_composition_sort_rules(vec![]);
    assert!(result.is_err());
}