use praxis_parser::{lex, parse};
use proptest::prelude::*;
fn any_text() -> impl Strategy<Value = String> {
"(?s).{0,256}"
}
fn praxis_shaped_text() -> impl Strategy<Value = String> {
let piece = prop_oneof![
Just("var "),
Just("fn f("),
Just("if "),
Just("for x in "),
Just("match "),
Just("return"),
Just("read "),
Just("=> "),
Just("{"),
Just("}"),
Just("("),
Just(")"),
Just("["),
Just("]"),
Just("."),
Just("..="),
Just(","),
Just(";"),
Just("\n"),
Just(" "),
Just("// comment\n"),
Just("/* nested /* inner */ */"),
Just("\"text\\n\""),
Just("`{x:int}`"),
Just("42"),
Just("3.14"),
Just("_"),
Just("λ"),
Just("日本語"),
Just("e\u{0301}"),
Just("→"),
Just("🦀"),
];
prop::collection::vec(piece, 0..48).prop_map(|parts| parts.concat())
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(512))]
#[test]
fn lex_never_panics(input in any_text()) {
let _ = lex(praxis_source::FileId::SYNTHETIC, &input);
}
#[test]
fn parse_never_panics_and_returns_tree(input in any_text()) {
let out = parse(praxis_source::FileId::SYNTHETIC, &input);
prop_assert_eq!(out.tree.kind(), praxis_syntax::SyntaxKind::SOURCE_FILE);
}
#[test]
fn parse_never_panics_on_praxis_shaped_input(input in praxis_shaped_text()) {
let out = parse(praxis_source::FileId::SYNTHETIC, &input);
prop_assert_eq!(out.tree.kind(), praxis_syntax::SyntaxKind::SOURCE_FILE);
}
#[test]
fn token_spans_tile_the_input(input in praxis_shaped_text()) {
let out = lex(praxis_source::FileId::SYNTHETIC, &input);
let mut at = 0usize;
for token in &out.tokens {
let (start, end) = (token.span.start().to_usize(), token.span.end().to_usize());
prop_assert_eq!(start, at, "gap or overlap before {:?}", token.kind);
prop_assert!(end >= start);
prop_assert!(
input.is_char_boundary(start) && input.is_char_boundary(end),
"token {:?} splits a scalar", token.kind
);
at = end;
}
prop_assert_eq!(at, input.len(), "tokens do not cover the input");
}
#[test]
fn the_tree_round_trips_the_source(input in praxis_shaped_text()) {
let out = parse(praxis_source::FileId::SYNTHETIC, &input);
prop_assert_eq!(out.tree.text().to_string(), input);
}
}