mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
proptest reveals that dsl breaks at invalid char boundaries
This commit is contained in:
parent
2e18ca96fd
commit
e8e0f5646d
11 changed files with 145 additions and 51 deletions
13
Cargo.lock
generated
13
Cargo.lock
generated
|
|
@ -952,6 +952,17 @@ dependencies = [
|
||||||
"unarray",
|
"unarray",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proptest-derive"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4ee1c9ac207483d5e7db4940700de86a9aae46ef90c48b57f99fe7edb8345e49"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quanta"
|
name = "quanta"
|
||||||
version = "0.12.5"
|
version = "0.12.5"
|
||||||
|
|
@ -1496,6 +1507,7 @@ dependencies = [
|
||||||
"clojure-reader",
|
"clojure-reader",
|
||||||
"itertools 0.14.0",
|
"itertools 0.14.0",
|
||||||
"konst",
|
"konst",
|
||||||
|
"proptest",
|
||||||
"tek_tui",
|
"tek_tui",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -1530,6 +1542,7 @@ name = "tek_output"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proptest",
|
"proptest",
|
||||||
|
"proptest-derive",
|
||||||
"tek_edn",
|
"tek_edn",
|
||||||
"tek_tui",
|
"tek_tui",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -13,3 +13,4 @@ default = []
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tek_tui = { path = "../tui" }
|
tek_tui = { path = "../tui" }
|
||||||
|
proptest = "^1.6.0"
|
||||||
|
|
|
||||||
7
edn/proptest-regressions/iter.txt
Normal file
7
edn/proptest-regressions/iter.txt
Normal 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 = "(𰀀"
|
||||||
7
edn/proptest-regressions/token.txt
Normal file
7
edn/proptest-regressions/token.txt
Normal 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
|
||||||
|
|
@ -108,3 +108,20 @@ pub const fn to_digit (c: char) -> Result<usize, ParseError> {
|
||||||
_ => return Result::Err(Unexpected(c))
|
_ => 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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> {
|
//#[cfg(test)] #[test] fn test_examples () -> Result<(), ParseError> {
|
||||||
//// Let's pretend to render some view.
|
//// Let's pretend to render some view.
|
||||||
//let source = include_str!("../../tek/src/view_arranger.edn");
|
//let source = include_str!("../../tek/src/view_arranger.edn");
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ impl<'a> Token<'a> {
|
||||||
Self { source, start, length, value }
|
Self { source, start, length, value }
|
||||||
}
|
}
|
||||||
pub const fn end (&self) -> usize {
|
pub const fn end (&self) -> usize {
|
||||||
self.start + self.length
|
self.start.saturating_add(self.length)
|
||||||
}
|
}
|
||||||
pub const fn slice (&'a self) -> &'a str {
|
pub const fn slice (&'a self) -> &'a str {
|
||||||
self.slice_source(self.source)
|
self.slice_source(self.source)
|
||||||
|
|
@ -51,7 +51,7 @@ impl<'a> Token<'a> {
|
||||||
str_range(source, self.start, self.end())
|
str_range(source, self.start, self.end())
|
||||||
}
|
}
|
||||||
pub const fn slice_source_exp <'b> (&'a self, source: &'b str) -> &'b str {
|
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 {
|
pub const fn value (&self) -> Value {
|
||||||
self.value
|
self.value
|
||||||
|
|
@ -60,7 +60,7 @@ impl<'a> Token<'a> {
|
||||||
Self { value: Value::Err(error), ..self }
|
Self { value: Value::Err(error), ..self }
|
||||||
}
|
}
|
||||||
pub const fn grow (self) -> 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 {
|
pub const fn grow_num (self, m: usize, c: char) -> Self {
|
||||||
match to_digit(c) {
|
match to_digit(c) {
|
||||||
|
|
@ -90,7 +90,7 @@ impl<'a> Token<'a> {
|
||||||
pub const fn grow_in (self) -> Self {
|
pub const fn grow_in (self) -> Self {
|
||||||
let mut token = self.grow_exp();
|
let mut token = self.grow_exp();
|
||||||
if let Value::Exp(depth, source) = token.value {
|
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 {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
@ -110,3 +110,60 @@ impl<'a> Token<'a> {
|
||||||
token
|
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(())
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,5 @@ tek_edn = { path = "../edn" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tek_tui = { path = "../tui" }
|
tek_tui = { path = "../tui" }
|
||||||
proptest = "^1.6.0"
|
proptest = "^1"
|
||||||
|
proptest-derive = "^0.5.1"
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ impl<N: Coordinate> Area<N> for [N;4] {
|
||||||
use super::*;
|
use super::*;
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
proptest! {
|
proptest! {
|
||||||
#[test] fn test_area (
|
#[test] fn test_area_prop (
|
||||||
x in u16::MIN..u16::MAX,
|
x in u16::MIN..u16::MAX,
|
||||||
y in u16::MIN..u16::MAX,
|
y in u16::MIN..u16::MAX,
|
||||||
w in u16::MIN..u16::MAX,
|
w in u16::MIN..u16::MAX,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
#[cfg(test)] use proptest_derive::Arbitrary;
|
||||||
/// A cardinal direction.
|
/// A cardinal direction.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(test, derive(Arbitrary))]
|
||||||
pub enum Direction { North, South, East, West, Above, Below }
|
pub enum Direction { North, South, East, West, Above, Below }
|
||||||
impl Direction {
|
impl Direction {
|
||||||
pub fn split_fixed <N: Coordinate> (self, area: impl Area<N>, a: N) -> ([N;4],[N;4]) {
|
pub fn split_fixed <N: Coordinate> (self, area: impl Area<N>, a: N) -> ([N;4],[N;4]) {
|
||||||
|
|
@ -14,20 +16,23 @@ impl Direction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(test)] mod test_op_transform {
|
#[cfg(test)] mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
proptest! {
|
proptest! {
|
||||||
#[test] fn test_direction (
|
#[test] fn proptest_direction (
|
||||||
|
d in prop_oneof![
|
||||||
|
Just(North), Just(South),
|
||||||
|
Just(East), Just(West),
|
||||||
|
Just(Above), Just(Below)
|
||||||
|
],
|
||||||
x in u16::MIN..u16::MAX,
|
x in u16::MIN..u16::MAX,
|
||||||
y in u16::MIN..u16::MAX,
|
y in u16::MIN..u16::MAX,
|
||||||
w in u16::MIN..u16::MAX,
|
w in u16::MIN..u16::MAX,
|
||||||
h in u16::MIN..u16::MAX,
|
h in u16::MIN..u16::MAX,
|
||||||
a in u16::MIN..u16::MAX,
|
a in u16::MIN..u16::MAX,
|
||||||
) {
|
) {
|
||||||
for d in [North, South, East, West, Above, Below].iter() {
|
let _ = d.split_fixed([x, y, w, h], a);
|
||||||
let _ = d.split_fixed([x, y, w, h], a);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,3 +116,28 @@ impl<E: Output, A: Content<E>, B: Content<E>> BspAreas<E, A, B> for Bsp<A, B> {
|
||||||
#[macro_export] macro_rules! row {
|
#[macro_export] macro_rules! row {
|
||||||
($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::e(bsp, $expr);)*; bsp }};
|
($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::e(bsp, $expr);)*; bsp }};
|
||||||
}
|
}
|
||||||
|
#[cfg(test)] mod test {
|
||||||
|
use super::*;
|
||||||
|
use proptest::prelude::*;
|
||||||
|
proptest! {
|
||||||
|
#[test] fn proptest_op_bsp (
|
||||||
|
d in prop_oneof![
|
||||||
|
Just(North), Just(South),
|
||||||
|
Just(East), Just(West),
|
||||||
|
Just(Above), Just(Below)
|
||||||
|
],
|
||||||
|
a in "\\PC*",
|
||||||
|
b in "\\PC*",
|
||||||
|
x in u16::MIN..u16::MAX,
|
||||||
|
y in u16::MIN..u16::MAX,
|
||||||
|
w in u16::MIN..u16::MAX,
|
||||||
|
h in u16::MIN..u16::MAX,
|
||||||
|
) {
|
||||||
|
let bsp = Bsp(d, a, b);
|
||||||
|
assert_eq!(
|
||||||
|
Content::layout(&bsp, [x, y, w, h]),
|
||||||
|
Render::layout(&bsp, [x, y, w, h]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue