kbvm 0.1.5

An implementation of the XKB specification
Documentation
use {
    crate::xkb::{
        code::Code,
        code_map::CodeMap,
        include::{IncludeIter, error::ParseIncludeError, parse_include},
        interner::{Interned, Interner},
        kccgst::MergeMode,
        span::SpanExt,
    },
    std::sync::Arc,
};

fn iter<'a>(map: &mut CodeMap, interner: &'a mut Interner, s: &str) -> IncludeIter<'a> {
    let code = Arc::new(s.as_bytes().to_vec());
    let code = Code::new(&code);
    let code_span = map.add(None, None, &code);
    let interned = interner.intern(&code.to_slice());
    parse_include(interner, interned.spanned2(code_span))
}

fn i(interner: &mut Interner, s: &str) -> Interned {
    let code = Arc::new(s.as_bytes().to_vec());
    let code = Code::new(&code);
    interner.intern(&code.to_slice())
}

#[test]
fn test() {
    let mut map = CodeMap::default();
    let mut interner = Interner::default();
    let abcd = i(&mut interner, "abcd");
    let ef = i(&mut interner, "ef");
    let tt = i(&mut interner, "22");
    let xx = i(&mut interner, "xx");
    let ayo = i(&mut interner, "ayo");
    let yy = i(&mut interner, "yy");
    let mut iter = iter(&mut map, &mut interner, "abcd(ef):22+xx|abcd(ayo)  +yy");

    let i = iter.next().unwrap().unwrap();
    assert_eq!(i.file.val, abcd);
    assert_eq!(i.map.unwrap().val, ef);
    assert_eq!(i.group.unwrap().group_name.val, tt);
    assert_eq!(i.group.unwrap().group.raw(), 22);
    assert_eq!(i.merge_mode, None);

    let i = iter.next().unwrap().unwrap();
    assert_eq!(i.file.val, xx);
    assert!(i.map.is_none());
    assert!(i.group.is_none());
    assert_eq!(i.merge_mode.unwrap(), MergeMode::Override);

    let i = iter.next().unwrap().unwrap();
    assert_eq!(i.file.val, abcd);
    assert_eq!(i.map.unwrap().val, ayo);
    assert!(i.group.is_none());
    assert_eq!(i.merge_mode.unwrap(), MergeMode::Augment);

    let i = iter.next().unwrap().unwrap();
    assert_eq!(i.file.val, yy);
    assert!(i.map.is_none());
    assert!(i.group.is_none());
    assert_eq!(i.merge_mode.unwrap(), MergeMode::Override);

    assert!(iter.next().is_none());
}

#[test]
fn invalid_format() {
    let mut map = CodeMap::default();
    let mut interner = Interner::default();
    let mut iter = iter(&mut map, &mut interner, "abc+");
    assert!(iter.next().unwrap().is_ok());
    let e = iter.next().unwrap().unwrap_err();
    assert_eq!(e.val, ParseIncludeError::MissingFileName);
}

#[test]
fn invalid_group() {
    let mut map = CodeMap::default();
    let mut interner = Interner::default();
    {
        let mut iter = iter(&mut map, &mut interner, "abc:9999999999999999999999");
        let e = iter.next().unwrap().unwrap_err();
        let ParseIncludeError::InvalidGroupIndex(idx) = e.val else {
            unreachable!();
        };
        assert_eq!(idx.as_bytes(), b"9999999999999999999999");
    }
    {
        let mut iter = iter(&mut map, &mut interner, "abc:33");
        let e = iter.next().unwrap().unwrap_err();
        let ParseIncludeError::InvalidGroupIndex(idx) = e.val else {
            unreachable!();
        };
        assert_eq!(idx.as_bytes(), b"33");
    }
    {
        let mut iter = iter(&mut map, &mut interner, "abc:xyz");
        let e = iter.next().unwrap().unwrap_err();
        let ParseIncludeError::InvalidGroupIndex(idx) = e.val else {
            unreachable!();
        };
        assert_eq!(idx.as_bytes(), b"x");
    }
}

#[test]
fn missing_merge_mode() {
    let mut map = CodeMap::default();
    let mut interner = Interner::default();
    let mut iter = iter(&mut map, &mut interner, "a(b)c");
    assert!(iter.next().unwrap().is_ok());
    let e = iter.next().unwrap().unwrap_err();
    assert_eq!(e.val, ParseIncludeError::MissingMergeMode);
}

#[test]
fn unterminated_map_name() {
    let mut map = CodeMap::default();
    let mut interner = Interner::default();
    let mut iter = iter(&mut map, &mut interner, "abc(def");
    let e = iter.next().unwrap().unwrap_err();
    assert_eq!(e.val, ParseIncludeError::UnterminatedMapName);
}