mod common;
use common::{Kind, Shape, build, leaf_count};
use proptest::prelude::*;
use syntax_lang::Node;
fn shape() -> impl Strategy<Value = Shape> {
let leaf = (any::<bool>(), 1u32..6).prop_map(|(trivia, len)| {
let kind = if trivia { Kind::Space } else { Kind::Word };
Shape::Leaf(kind, len)
});
leaf.prop_recursive(6, 128, 4, |inner| {
prop::collection::vec(inner, 1..4).prop_map(Shape::Branch)
})
}
fn root_shape() -> impl Strategy<Value = Shape> {
prop::collection::vec(shape(), 1..4).prop_map(Shape::Branch)
}
fn concat_tokens(node: &Node<Kind>, source: &str) -> String {
let mut out = String::new();
for token in node.tokens() {
let lo = token.span().start().to_usize();
let hi = token.span().end().to_usize();
out.push_str(&source[lo..hi]);
}
out
}
proptest! {
#[test]
fn prop_root_span_covers_whole_source(shape in root_shape()) {
let (root, len) = build(&shape);
let source = "x".repeat(len as usize);
prop_assert_eq!(root.span().start().to_u32(), 0);
prop_assert_eq!(root.span().end().to_u32(), len);
prop_assert_eq!(root.text(&source), Some(source.as_str()));
}
#[test]
fn prop_tokens_reconstruct_source(shape in root_shape()) {
let (root, len) = build(&shape);
let source = "y".repeat(len as usize);
prop_assert_eq!(concat_tokens(&root, &source), source);
}
#[test]
fn prop_token_count_matches_shape(shape in root_shape()) {
let (root, _) = build(&shape);
prop_assert_eq!(root.tokens().count(), leaf_count(&shape));
}
#[test]
fn prop_covering_span_tiles_children(shape in root_shape()) {
let (root, len) = build(&shape);
let source = "z".repeat(len as usize);
for node in root.descendants() {
let sliced = node.text(&source).expect("span within source");
prop_assert_eq!(sliced, concat_tokens(node, &source));
}
}
#[test]
fn prop_tokens_tile_without_gaps(shape in root_shape()) {
let (root, _) = build(&shape);
let mut prev_end = 0u32;
for token in root.tokens() {
prop_assert_eq!(token.span().start().to_u32(), prev_end);
prev_end = token.span().end().to_u32();
}
}
#[test]
fn prop_descendant_spans_within_root(shape in root_shape()) {
let (root, _) = build(&shape);
let (lo, hi) = (root.span().start().to_u32(), root.span().end().to_u32());
for node in root.descendants() {
prop_assert!(node.span().start().to_u32() >= lo);
prop_assert!(node.span().end().to_u32() <= hi);
}
}
}