diff --git a/Cargo.lock b/Cargo.lock index e4b84df3..c1fea3af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -952,6 +952,17 @@ dependencies = [ "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]] name = "quanta" version = "0.12.5" @@ -1496,6 +1507,7 @@ dependencies = [ "clojure-reader", "itertools 0.14.0", "konst", + "proptest", "tek_tui", ] @@ -1530,6 +1542,7 @@ name = "tek_output" version = "0.2.0" dependencies = [ "proptest", + "proptest-derive", "tek_edn", "tek_tui", ] diff --git a/edn/Cargo.toml b/edn/Cargo.toml index 11626bea..a212ad6c 100644 --- a/edn/Cargo.toml +++ b/edn/Cargo.toml @@ -13,3 +13,4 @@ default = [] [dev-dependencies] tek_tui = { path = "../tui" } +proptest = "^1.6.0" diff --git a/edn/proptest-regressions/iter.txt b/edn/proptest-regressions/iter.txt new file mode 100644 index 00000000..b4d8405a --- /dev/null +++ b/edn/proptest-regressions/iter.txt @@ -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 = "(𰀀" diff --git a/edn/proptest-regressions/token.txt b/edn/proptest-regressions/token.txt new file mode 100644 index 00000000..cc03cf2f --- /dev/null +++ b/edn/proptest-regressions/token.txt @@ -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 diff --git a/edn/src/iter.rs b/edn/src/iter.rs index ac634a91..b27015f1 100644 --- a/edn/src/iter.rs +++ b/edn/src/iter.rs @@ -108,3 +108,20 @@ pub const fn to_digit (c: char) -> Result { _ => 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(); + } + } +} diff --git a/edn/src/lib.rs b/edn/src/lib.rs index ea7fec7b..10d60bbc 100644 --- a/edn/src/lib.rs +++ b/edn/src/lib.rs @@ -35,45 +35,6 @@ pub(crate) use std::fmt::{Debug, Display, Formatter, Result as FormatResult}; } } } -#[cfg(test)] #[test] fn test_token () -> Result<(), Box> { - 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"); diff --git a/edn/src/token.rs b/edn/src/token.rs index 3549007c..d151d63e 100644 --- a/edn/src/token.rs +++ b/edn/src/token.rs @@ -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> { + 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(()) +} diff --git a/output/Cargo.toml b/output/Cargo.toml index 627c621f..3a708adf 100644 --- a/output/Cargo.toml +++ b/output/Cargo.toml @@ -8,4 +8,5 @@ tek_edn = { path = "../edn" } [dev-dependencies] tek_tui = { path = "../tui" } -proptest = "^1.6.0" +proptest = "^1" +proptest-derive = "^0.5.1" diff --git a/output/src/area.rs b/output/src/area.rs index a571582c..8c669da1 100644 --- a/output/src/area.rs +++ b/output/src/area.rs @@ -96,7 +96,7 @@ impl Area for [N;4] { use super::*; use proptest::prelude::*; proptest! { - #[test] fn test_area ( + #[test] fn test_area_prop ( x in u16::MIN..u16::MAX, y in u16::MIN..u16::MAX, w in u16::MIN..u16::MAX, diff --git a/output/src/direction.rs b/output/src/direction.rs index 1fabc193..afa2139a 100644 --- a/output/src/direction.rs +++ b/output/src/direction.rs @@ -1,6 +1,8 @@ use crate::*; +#[cfg(test)] use proptest_derive::Arbitrary; /// 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 } impl Direction { pub fn split_fixed (self, area: impl Area, 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 proptest::prelude::*; 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, y in u16::MIN..u16::MAX, w in u16::MIN..u16::MAX, h 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); } } } diff --git a/output/src/op_bsp.rs b/output/src/op_bsp.rs index 2cd7e395..5846750e 100644 --- a/output/src/op_bsp.rs +++ b/output/src/op_bsp.rs @@ -116,3 +116,28 @@ impl, B: Content> BspAreas for Bsp { #[macro_export] macro_rules! row { ($($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]), + ); + } + } +}