rd-ast 0.0.1

Canonical, producer-agnostic AST for R's Rd (documentation) format
Documentation
use super::*;
use crate::{RdEnc, RdNode, RdPath, RdPathSegment, RdTag, producer};

fn base() -> RdPath {
    RdPath::new(vec![RdPathSegment::TopLevel(1), RdPathSegment::Child(3)])
}
fn group(nodes: Vec<RdNode>) -> RdNode {
    RdNode::group(nodes)
}
fn enc(children: Vec<RdNode>) -> RdNode {
    RdNode::tagged(RdTag::Enc, None, children)
}

#[test]
fn enc_preserves_both_sides() {
    let encoded = vec![RdNode::tagged(
        RdTag::Emph,
        None,
        vec![RdNode::Text("é".into())],
    )];
    let ascii = vec![RdNode::Text("a".into()), RdNode::Text("scii".into())];
    let node = enc(vec![group(encoded.clone()), group(ascii.clone())]);
    let view: RdEnc<'_> = node.inspect_enc(&base()).unwrap().unwrap();
    assert_eq!(view.encoded(), encoded.as_slice());
    assert_eq!(view.ascii(), ascii.as_slice());
    assert_eq!(node.enc(&base()), Some(view));
}

#[test]
fn enc_validates_only_option_arity_and_groups() {
    let option = RdNode::tagged(RdTag::Enc, Some(vec![]), vec![]);
    assert!(matches!(
        option.inspect_enc(&base()).unwrap_err().kind(),
        RdShapeErrorKind::UnexpectedOption
    ));
    for count in [0, 1, 3] {
        let node = enc((0..count).map(|_| group(vec![])).collect());
        assert!(
            matches!(node.inspect_enc(&base()).unwrap_err().kind(), RdShapeErrorKind::WrongArity { actual, .. } if *actual == count)
        );
    }
    for index in 0..2 {
        let mut children = vec![group(vec![]), group(vec![])];
        children[index] = RdNode::Text("bad".into());
        let error = enc(children).inspect_enc(&base()).unwrap_err();
        assert_eq!(error.path(), &base().with_child(index));
        assert!(matches!(
            error.kind(),
            RdShapeErrorKind::UnexpectedNode {
                expected: RdExpectedNode::Group,
                ..
            }
        ));
    }
    let raw = RdNode::Raw(producer::raw_node(
        Some("\\enc".into()),
        None,
        vec![],
        None,
        vec![],
    ));
    assert!(matches!(
        raw.inspect_enc(&base()).unwrap_err().kind(),
        RdShapeErrorKind::UnexpectedNode {
            expected: RdExpectedNode::Tagged,
            actual: RdNodeKind::Raw
        }
    ));
    let other = RdNode::tagged(RdTag::If, None, vec![]);
    assert_eq!(other.inspect_enc(&base()).unwrap(), None);
}