ltk_ritobin 0.12.0

Ritobin text format parser and writer for League Toolkit
Documentation
use ltk_hash::{HashAlgorithm, HashWidth};
use ltk_meta::PropertyKind as K;

use super::*;
use crate::rito;

#[test]
fn a_type_prints_its_ritobin_spelling() {
    let xxh3 = ScalarType::Hash(HashType::new(HashWidth::W8, HashAlgorithm::Xxh3));
    let cases = [
        (rito!(U32), "u32"),
        (rito!(Hash), "hash"),
        (rito!(Container[String]), "list[string]"),
        (rito!(UnorderedContainer[Embedded]), "list2[embed]"),
        (rito!(Optional[Vector3]), "option[vec3]"),
        (rito!(Map[Hash, Struct]), "map[hash,pointer]"),
        (RitoType::list(xxh3), "list[hash[u64,xxh3]]"),
        (RitoType::from_property_kind(K::Container), "list"),
    ];
    for (rito, text) in cases {
        assert_eq!(rito.to_string(), text);
    }
}

#[test]
fn a_map_with_one_usable_subtype_has_neither() {
    let bare = RitoType::from_property_kind(K::Map);
    assert_eq!(
        RitoType::from_parts(K::Map, [Some(K::Container), Some(K::U32)]),
        bare
    );
    assert_eq!(RitoType::from_parts(K::Map, [Some(K::U32), None]), bare);
    assert_eq!(bare.to_string(), "map");
}

#[test]
fn a_missing_subtype_matches_any_subtype() {
    let bare = RitoType::from_property_kind(K::Container);
    assert!(bare.equivalent_to(&rito!(Container[U32])));
    assert!(rito!(Container[U32]).equivalent_to(&bare));
    assert!(!rito!(Container[U32]).equivalent_to(&rito!(Container[U8])));
    assert!(!bare.equivalent_to(&RitoType::from_property_kind(K::UnorderedContainer)));
}

#[test]
fn hash_types_compare_in_full() {
    let xxh3 = ScalarType::Hash(HashType::new(HashWidth::W8, HashAlgorithm::Xxh3));
    assert!(!RitoType::from(xxh3).equivalent_to(&rito!(Hash)));
    assert!(RitoType::from(xxh3)
        .with_default_hash_types()
        .equivalent_to(&rito!(Hash)));
}

#[test]
fn a_type_from_parts_rejects_a_shape_ritobin_has_no_spelling_for() {
    use BadContainerType as C;
    use BadRitoType as R;
    let cases = [
        (
            (K::Container, [None, None]),
            R::BadScalarType(BadScalarType(K::Container)),
        ),
        (
            (K::U32, [Some(K::U8), None]),
            R::BadContainerType(C::NonContainerBase { got: K::U32 }),
        ),
        (
            (K::Container, [Some(K::Map), None]),
            R::BadContainerType(C::NonScalarSubtype {
                base: K::Container,
                got: K::Map,
            }),
        ),
        (
            (K::Optional, [Some(K::U8), Some(K::U8)]),
            R::BadContainerType(C::BadSubtypeCount {
                base: K::Optional,
                got: 2,
                expected: 1,
            }),
        ),
        (
            (K::Map, [Some(K::U32), None]),
            R::BadContainerType(C::BadSubtypeCount {
                base: K::Map,
                got: 1,
                expected: 2,
            }),
        ),
        (
            (K::Map, [Some(K::Embedded), Some(K::U32)]),
            R::BadContainerType(C::BadMapKey { got: K::Embedded }),
        ),
    ];
    for ((base, subtypes), error) in cases {
        assert_eq!(RitoType::try_from_parts(base, subtypes), Err(error));
    }
}

#[test]
fn a_type_from_parts_leaves_out_a_subtype_that_does_not_fit() {
    assert_eq!(
        RitoType::from_parts(K::Container, [Some(K::Map), None]),
        RitoType::from_property_kind(K::Container)
    );
    assert_eq!(
        RitoType::from_parts(K::U32, [Some(K::U8), None]),
        rito!(U32)
    );
}