proptest reveals that dsl breaks at invalid char boundaries

This commit is contained in:
🪞👃🪞 2025-01-27 20:02:27 +01:00
parent 2e18ca96fd
commit e8e0f5646d
11 changed files with 145 additions and 51 deletions

View file

@ -13,3 +13,4 @@ default = []
[dev-dependencies]
tek_tui = { path = "../tui" }
proptest = "^1.6.0"

View file

@ -0,0 +1,7 @@
# Seeds for failure cases proptest has generated in the past. It is
# automatically read and these particular cases re-run before any
# novel cases are generated.
#
# It is recommended to check this file in to source control so that
# everyone who runs the test benefits from these saved cases.
cc bbb90b16e6106f17dbb5a4f57594f451360a2ea7e3e20c28adeb8babc98d39df # shrinks to source = "(𰀀"

View file

@ -0,0 +1,7 @@
# Seeds for failure cases proptest has generated in the past. It is
# automatically read and these particular cases re-run before any
# novel cases are generated.
#
# It is recommended to check this file in to source control so that
# everyone who runs the test benefits from these saved cases.
cc 5fb814b74ae035bdecb536817090cfb473f0a874e9acf9aaa136a4794cdb367f # shrinks to source = "", start = 10336420442936153584, length = 8110323630773398032

View file

@ -108,3 +108,20 @@ pub const fn to_digit (c: char) -> Result<usize, ParseError> {
_ => return Result::Err(Unexpected(c))
})
}
#[cfg(test)] mod test_token_iter {
use proptest::prelude::*;
proptest! {
#[test] fn proptest_source_iter (
source in "\\PC*"
) {
let mut iter = crate::SourceIter::new(&source);
let _ = iter.next();
}
#[test] fn proptest_token_iter (
source in "\\PC*"
) {
let mut iter = crate::TokenIter::new(&source);
let _ = iter.next();
}
}
}

View file

@ -35,45 +35,6 @@ pub(crate) use std::fmt::{Debug, Display, Formatter, Result as FormatResult};
}
}
}
#[cfg(test)] #[test] fn test_token () -> Result<(), Box<dyn std::error::Error>> {
let source = ":f00";
let mut token = Token { source, start: 0, length: 1, value: Sym(":") };
token = token.grow_sym();
assert_eq!(token, Token { source, start: 0, length: 2, value: Sym(":f") });
token = token.grow_sym();
assert_eq!(token, Token { source, start: 0, length: 3, value: Sym(":f0") });
token = token.grow_sym();
assert_eq!(token, Token { source, start: 0, length: 4, value: Sym(":f00") });
let src = "";
assert_eq!(None, SourceIter(src).next());
let src = " \n \r \t ";
assert_eq!(None, SourceIter(src).next());
let src = "7";
assert_eq!(Num(7), SourceIter(src).next().unwrap().0.value);
let src = " 100 ";
assert_eq!(Num(100), SourceIter(src).next().unwrap().0.value);
let src = " 9a ";
assert_eq!(Err(Unexpected('a')), SourceIter(src).next().unwrap().0.value);
let src = " :123foo ";
assert_eq!(Sym(":123foo"), SourceIter(src).next().unwrap().0.value);
let src = " \r\r\r\n\n\n@bar456\t\t\t\t\t\t";
assert_eq!(Sym("@bar456"), SourceIter(src).next().unwrap().0.value);
let src = "foo123";
assert_eq!(Key("foo123"), SourceIter(src).next().unwrap().0.value);
let src = "foo/bar";
assert_eq!(Key("foo/bar"), SourceIter(src).next().unwrap().0.value);
Ok(())
}
//#[cfg(test)] #[test] fn test_examples () -> Result<(), ParseError> {
//// Let's pretend to render some view.
//let source = include_str!("../../tek/src/view_arranger.edn");

View file

@ -41,7 +41,7 @@ impl<'a> Token<'a> {
Self { source, start, length, value }
}
pub const fn end (&self) -> usize {
self.start + self.length
self.start.saturating_add(self.length)
}
pub const fn slice (&'a self) -> &'a str {
self.slice_source(self.source)
@ -51,7 +51,7 @@ impl<'a> Token<'a> {
str_range(source, self.start, self.end())
}
pub const fn slice_source_exp <'b> (&'a self, source: &'b str) -> &'b str {
str_range(source, self.start + 1, self.end())
str_range(source, self.start.saturating_add(1), self.end())
}
pub const fn value (&self) -> Value {
self.value
@ -60,7 +60,7 @@ impl<'a> Token<'a> {
Self { value: Value::Err(error), ..self }
}
pub const fn grow (self) -> Self {
Self { length: self.length + 1, ..self }
Self { length: self.length.saturating_add(1), ..self }
}
pub const fn grow_num (self, m: usize, c: char) -> Self {
match to_digit(c) {
@ -90,7 +90,7 @@ impl<'a> Token<'a> {
pub const fn grow_in (self) -> Self {
let mut token = self.grow_exp();
if let Value::Exp(depth, source) = token.value {
token.value = Value::Exp(depth + 1, source)
token.value = Value::Exp(depth.saturating_add(1), source)
} else {
unreachable!()
}
@ -110,3 +110,60 @@ impl<'a> Token<'a> {
token
}
}
#[cfg(test)] mod test_token_prop {
use proptest::prelude::*;
proptest! {
#[test] fn test_token_prop (
source in "\\PC*",
start in usize::MIN..usize::MAX,
length in usize::MIN..usize::MAX,
) {
let token = crate::Token {
source: &source,
start,
length,
value: crate::Value::Nil
};
let _ = token.slice();
}
}
}
#[cfg(test)] #[test] fn test_token () -> Result<(), Box<dyn std::error::Error>> {
let source = ":f00";
let mut token = Token { source, start: 0, length: 1, value: Sym(":") };
token = token.grow_sym();
assert_eq!(token, Token { source, start: 0, length: 2, value: Sym(":f") });
token = token.grow_sym();
assert_eq!(token, Token { source, start: 0, length: 3, value: Sym(":f0") });
token = token.grow_sym();
assert_eq!(token, Token { source, start: 0, length: 4, value: Sym(":f00") });
let src = "";
assert_eq!(None, SourceIter(src).next());
let src = " \n \r \t ";
assert_eq!(None, SourceIter(src).next());
let src = "7";
assert_eq!(Num(7), SourceIter(src).next().unwrap().0.value);
let src = " 100 ";
assert_eq!(Num(100), SourceIter(src).next().unwrap().0.value);
let src = " 9a ";
assert_eq!(Err(Unexpected('a')), SourceIter(src).next().unwrap().0.value);
let src = " :123foo ";
assert_eq!(Sym(":123foo"), SourceIter(src).next().unwrap().0.value);
let src = " \r\r\r\n\n\n@bar456\t\t\t\t\t\t";
assert_eq!(Sym("@bar456"), SourceIter(src).next().unwrap().0.value);
let src = "foo123";
assert_eq!(Key("foo123"), SourceIter(src).next().unwrap().0.value);
let src = "foo/bar";
assert_eq!(Key("foo/bar"), SourceIter(src).next().unwrap().0.value);
Ok(())
}