output: collect tests; formatting
Some checks failed
/ build (push) Has been cancelled

This commit is contained in:
🪞👃🪞 2025-04-30 23:48:43 +03:00
parent 9fb5d2d9f7
commit 2b208e3c49
11 changed files with 219 additions and 198 deletions

View file

@ -19,6 +19,8 @@ pub type Usually<T> = Result<T, Box<dyn Error>>;
/// Standard optional result type. /// Standard optional result type.
pub type Perhaps<T> = Result<Option<T>, Box<dyn Error>>; pub type Perhaps<T> = Result<Option<T>, Box<dyn Error>>;
#[cfg(test)] use proptest_derive::Arbitrary;
#[cfg(test)] #[test] fn test_stub_output () -> Usually<()> { #[cfg(test)] #[test] fn test_stub_output () -> Usually<()> {
use crate::*; use crate::*;
struct TestOutput([u16;4]); struct TestOutput([u16;4]);
@ -43,3 +45,152 @@ pub type Perhaps<T> = Result<Option<T>, Box<dyn Error>>;
} }
Ok(()) Ok(())
} }
#[cfg(test)] #[test] fn test_space () {
use crate::*;
assert_eq!(Area::center(&[10u16, 10, 20, 20]), [20, 20]);
}
#[cfg(test)] #[test] fn test_iter_map () {
struct Foo;
impl<T: Output> Content<T> for Foo {}
fn make_map <T: Output, U: Content<T> + Send + Sync> (data: &Vec<U>) -> impl Content<T> {
Map::new(||data.iter(), |foo, index|{})
}
let data = vec![Foo, Foo, Foo];
//let map = make_map(&data);
}
#[cfg(test)] mod test {
use crate::*;
use proptest::{prelude::*, option::of};
use proptest::option::of;
proptest! {
#[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,
) {
let _ = d.split_fixed([x, y, w, h], a);
}
}
proptest! {
#[test] fn proptest_size (
x in u16::MIN..u16::MAX,
y in u16::MIN..u16::MAX,
a in u16::MIN..u16::MAX,
b in u16::MIN..u16::MAX,
) {
let size = [x, y];
let _ = size.w();
let _ = size.h();
let _ = size.wh();
let _ = size.clip_w(a);
let _ = size.clip_h(b);
let _ = size.expect_min(a, b);
let _ = size.to_area_pos();
let _ = size.to_area_size();
}
}
proptest! {
#[test] fn proptest_area (
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,
b in u16::MIN..u16::MAX,
) {
let _: [u16;4] = <[u16;4] as Area<u16>>::zero();
let _: [u16;4] = <[u16;4] as Area<u16>>::from_position([a, b]);
let _: [u16;4] = <[u16;4] as Area<u16>>::from_size([a, b]);
let area: [u16;4] = [x, y, w, h];
let _ = area.expect_min(a, b);
let _ = area.xy();
let _ = area.wh();
let _ = area.xywh();
let _ = area.clip_h(a);
let _ = area.clip_w(b);
let _ = area.clip([a, b]);
let _ = area.set_w(a);
let _ = area.set_h(b);
let _ = area.x2();
let _ = area.y2();
let _ = area.lrtb();
let _ = area.center();
let _ = area.center_x(a);
let _ = area.center_y(b);
let _ = area.center_xy([a, b]);
let _ = area.centered();
}
}
macro_rules! test_op_transform {
($fn:ident, $Op:ident) => {
proptest! {
#[test] fn $fn (
op_x in of(u16::MIN..u16::MAX),
op_y in of(u16::MIN..u16::MAX),
content 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,
) {
if let Some(op) = match (op_x, op_y) {
(Some(x), Some(y)) => Some($Op::xy(x, y, content)),
(Some(x), None) => Some($Op::x(x, content)),
(Some(y), None) => Some($Op::y(y, content)),
_ => None
} {
assert_eq!(Content::layout(&op, [x, y, w, h]),
Render::layout(&op, [x, y, w, h]));
}
}
}
}
}
test_op_transform!(proptest_op_fixed, Fixed);
test_op_transform!(proptest_op_min, Min);
test_op_transform!(proptest_op_max, Max);
test_op_transform!(proptest_op_push, Push);
test_op_transform!(proptest_op_pull, Pull);
test_op_transform!(proptest_op_shrink, Shrink);
test_op_transform!(proptest_op_expand, Expand);
test_op_transform!(proptest_op_margin, Margin);
test_op_transform!(proptest_op_padding, Padding);
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]),
);
}
}
}

View file

@ -5,8 +5,3 @@ mod map; pub use self::map::*;
//mod reduce; pub use self::reduce::*; //mod reduce; pub use self::reduce::*;
mod thunk; pub use self::thunk::*; mod thunk; pub use self::thunk::*;
mod transform; pub use self::transform::*; mod transform; pub use self::transform::*;
#[cfg(test)] use crate::*;
#[cfg(test)] #[test] fn test_ops () -> Usually<()> {
Ok(())
}

View file

@ -27,9 +27,12 @@
//! test(area, &Align::sw(two_by_four()), [10, 28, 4, 2]); //! test(area, &Align::sw(two_by_four()), [10, 28, 4, 2]);
//! test(area, &Align::w(two_by_four()), [10, 19, 4, 2]); //! test(area, &Align::w(two_by_four()), [10, 19, 4, 2]);
//! ``` //! ```
use crate::*; use crate::*;
#[derive(Debug, Copy, Clone, Default)] pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W } #[derive(Debug, Copy, Clone, Default)]
pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W }
pub struct Align<A>(Alignment, A); pub struct Align<A>(Alignment, A);
#[cfg(feature = "dsl")] #[cfg(feature = "dsl")]
@ -79,6 +82,7 @@ impl<A> Align<A> {
#[inline] pub const fn ne (a: A) -> Self { Self(Alignment::NE, a) } #[inline] pub const fn ne (a: A) -> Self { Self(Alignment::NE, a) }
#[inline] pub const fn se (a: A) -> Self { Self(Alignment::SE, a) } #[inline] pub const fn se (a: A) -> Self { Self(Alignment::SE, a) }
} }
impl<E: Output, A: Content<E>> Content<E> for Align<A> { impl<E: Output, A: Content<E>> Content<E> for Align<A> {
fn content (&self) -> impl Render<E> { fn content (&self) -> impl Render<E> {
&self.1 &self.1

View file

@ -117,28 +117,3 @@ 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]),
);
}
}
}

View file

@ -1,27 +1,4 @@
use crate::*; use crate::*;
#[inline] pub fn map_south<O: Output>(
item_offset: O::Unit,
item_height: O::Unit,
item: impl Content<O>
) -> impl Content<O> {
Push::y(item_offset, Fixed::y(item_height, Fill::x(item)))
}
#[inline] pub fn map_south_west<O: Output>(
item_offset: O::Unit,
item_height: O::Unit,
item: impl Content<O>
) -> impl Content<O> {
Push::y(item_offset, Align::nw(Fixed::y(item_height, Fill::x(item))))
}
#[inline] pub fn map_east<O: Output>(
item_offset: O::Unit,
item_width: O::Unit,
item: impl Content<O>
) -> impl Content<O> {
Push::x(item_offset, Align::w(Fixed::x(item_width, Fill::y(item))))
}
/// Renders items from an iterator. /// Renders items from an iterator.
pub struct Map<E, A, B, I, F, G> pub struct Map<E, A, B, I, F, G>
@ -148,12 +125,26 @@ impl<'a, E, A, B, I, F, G> Content<E> for Map<E, A, B, I, F, G> where
} }
} }
#[cfg(test)] #[test] fn test_iter_map () { #[inline] pub fn map_south<O: Output>(
struct Foo; item_offset: O::Unit,
impl<T: Output> Content<T> for Foo {} item_height: O::Unit,
fn make_map <T: Output, U: Content<T> + Send + Sync> (data: &Vec<U>) -> impl Content<T> { item: impl Content<O>
Map::new(||data.iter(), |foo, index|{}) ) -> impl Content<O> {
} Push::y(item_offset, Fixed::y(item_height, Fill::x(item)))
let data = vec![Foo, Foo, Foo]; }
//let map = make_map(&data);
#[inline] pub fn map_south_west<O: Output>(
item_offset: O::Unit,
item_height: O::Unit,
item: impl Content<O>
) -> impl Content<O> {
Push::y(item_offset, Align::nw(Fixed::y(item_height, Fill::x(item))))
}
#[inline] pub fn map_east<O: Output>(
item_offset: O::Unit,
item_width: O::Unit,
item: impl Content<O>
) -> impl Content<O> {
Push::x(item_offset, Align::w(Fixed::x(item_width, Fill::y(item))))
} }

View file

@ -19,7 +19,9 @@
//! //FIXME:test(area, &Fixed::y(4, ()), [20, 18, 0, 4]); //! //FIXME:test(area, &Fixed::y(4, ()), [20, 18, 0, 4]);
//! //FIXME:test(area, &Fixed::xy(4, 4, unit), [18, 18, 4, 4]); //! //FIXME:test(area, &Fixed::xy(4, 4, unit), [18, 18, 4, 4]);
//! ``` //! ```
use crate::*; use crate::*;
/// Defines an enum that transforms its content /// Defines an enum that transforms its content
/// along either the X axis, the Y axis, or both. /// along either the X axis, the Y axis, or both.
macro_rules! transform_xy { macro_rules! transform_xy {
@ -131,6 +133,7 @@ macro_rules! transform_xy_unit {
} }
} }
} }
transform_xy!("fill/x" "fill/y" "fill/xy" |self: Fill, to|{ transform_xy!("fill/x" "fill/y" "fill/xy" |self: Fill, to|{
let [x0, y0, wmax, hmax] = to.xywh(); let [x0, y0, wmax, hmax] = to.xywh();
let [x, y, w, h] = self.content().layout(to).xywh(); let [x, y, w, h] = self.content().layout(to).xywh();
@ -138,7 +141,9 @@ transform_xy!("fill/x" "fill/y" "fill/xy" |self: Fill, to|{
X(_) => [x0, y, wmax, h], X(_) => [x0, y, wmax, h],
Y(_) => [x, y0, w, hmax], Y(_) => [x, y0, w, hmax],
XY(_) => [x0, y0, wmax, hmax], XY(_) => [x0, y0, wmax, hmax],
}.into() }); }.into()
});
transform_xy_unit!("fixed/x" "fixed/y" "fixed/xy"|self: Fixed, area|{ transform_xy_unit!("fixed/x" "fixed/y" "fixed/xy"|self: Fixed, area|{
let [x, y, w, h] = area.xywh(); let [x, y, w, h] = area.xywh();
let fixed_area = match self { let fixed_area = match self {
@ -152,80 +157,55 @@ transform_xy_unit!("fixed/x" "fixed/y" "fixed/xy"|self: Fixed, area|{
Self::Y(fh, _) => [x, y, w, *fh], Self::Y(fh, _) => [x, y, w, *fh],
Self::XY(fw, fh, _) => [x, y, *fw, *fh], Self::XY(fw, fh, _) => [x, y, *fw, *fh],
}; };
fixed_area }); fixed_area
});
transform_xy_unit!("min/x" "min/y" "min/xy"|self: Min, area|{ transform_xy_unit!("min/x" "min/y" "min/xy"|self: Min, area|{
let area = Render::layout(&self.content(), area); let area = Render::layout(&self.content(), area);
match self { match self {
Self::X(mw, _) => [area.x(), area.y(), area.w().max(*mw), area.h()], Self::X(mw, _) => [area.x(), area.y(), area.w().max(*mw), area.h()],
Self::Y(mh, _) => [area.x(), area.y(), area.w(), area.h().max(*mh)], Self::Y(mh, _) => [area.x(), area.y(), area.w(), area.h().max(*mh)],
Self::XY(mw, mh, _) => [area.x(), area.y(), area.w().max(*mw), area.h().max(*mh)], Self::XY(mw, mh, _) => [area.x(), area.y(), area.w().max(*mw), area.h().max(*mh)],
}}); }
});
transform_xy_unit!("max/x" "max/y" "max/xy"|self: Max, area|{ transform_xy_unit!("max/x" "max/y" "max/xy"|self: Max, area|{
let [x, y, w, h] = area.xywh(); let [x, y, w, h] = area.xywh();
Render::layout(&self.content(), match self { Render::layout(&self.content(), match self {
Self::X(fw, _) => [x, y, *fw, h], Self::X(fw, _) => [x, y, *fw, h],
Self::Y(fh, _) => [x, y, w, *fh], Self::Y(fh, _) => [x, y, w, *fh],
Self::XY(fw, fh, _) => [x, y, *fw, *fh], Self::XY(fw, fh, _) => [x, y, *fw, *fh],
}.into())}); }.into())
});
transform_xy_unit!("shrink/x" "shrink/y" "shrink/xy"|self: Shrink, area|Render::layout( transform_xy_unit!("shrink/x" "shrink/y" "shrink/xy"|self: Shrink, area|Render::layout(
&self.content(), &self.content(),
[area.x(), area.y(), area.w().minus(self.dx()), area.h().minus(self.dy())].into())); [area.x(), area.y(), area.w().minus(self.dx()), area.h().minus(self.dy())].into()));
transform_xy_unit!("expand/x" "expand/y" "expand/xy"|self: Expand, area|Render::layout( transform_xy_unit!("expand/x" "expand/y" "expand/xy"|self: Expand, area|Render::layout(
&self.content(), &self.content(),
[area.x(), area.y(), area.w().plus(self.dx()), area.h().plus(self.dy())].into())); [area.x(), area.y(), area.w().plus(self.dx()), area.h().plus(self.dy())].into()));
transform_xy_unit!("push/x" "push/y" "push/xy"|self: Push, area|{ transform_xy_unit!("push/x" "push/y" "push/xy"|self: Push, area|{
let area = Render::layout(&self.content(), area); let area = Render::layout(&self.content(), area);
[area.x().plus(self.dx()), area.y().plus(self.dy()), area.w(), area.h()] }); [area.x().plus(self.dx()), area.y().plus(self.dy()), area.w(), area.h()]
});
transform_xy_unit!("pull/x" "pull/y" "pull/xy"|self: Pull, area|{ transform_xy_unit!("pull/x" "pull/y" "pull/xy"|self: Pull, area|{
let area = Render::layout(&self.content(), area); let area = Render::layout(&self.content(), area);
[area.x().minus(self.dx()), area.y().minus(self.dy()), area.w(), area.h()] }); [area.x().minus(self.dx()), area.y().minus(self.dy()), area.w(), area.h()]
});
transform_xy_unit!("margin/x" "margin/y" "margin/xy"|self: Margin, area|{ transform_xy_unit!("margin/x" "margin/y" "margin/xy"|self: Margin, area|{
let area = Render::layout(&self.content(), area); let area = Render::layout(&self.content(), area);
let dx = self.dx(); let dx = self.dx();
let dy = self.dy(); let dy = self.dy();
[area.x().minus(dx), area.y().minus(dy), area.w().plus(dy.plus(dy)), area.h().plus(dy.plus(dy))] }); [area.x().minus(dx), area.y().minus(dy), area.w().plus(dy.plus(dy)), area.h().plus(dy.plus(dy))]
});
transform_xy_unit!("padding/x" "padding/y" "padding/xy"|self: Padding, area|{ transform_xy_unit!("padding/x" "padding/y" "padding/xy"|self: Padding, area|{
let area = Render::layout(&self.content(), area); let area = Render::layout(&self.content(), area);
let dx = self.dx(); let dx = self.dx();
let dy = self.dy(); let dy = self.dy();
[area.x().plus(dx), area.y().plus(dy), area.w().minus(dy.plus(dy)), area.h().minus(dy.plus(dy)), ] }); [area.x().plus(dx), area.y().plus(dy), area.w().minus(dy.plus(dy)), area.h().minus(dy.plus(dy))]
});
#[cfg(test)] mod test_op_transform {
use super::*;
use proptest::prelude::*;
use proptest::option::of;
macro_rules! test_op_transform {
($fn:ident, $Op:ident) => {
proptest! {
#[test] fn $fn (
op_x in of(u16::MIN..u16::MAX),
op_y in of(u16::MIN..u16::MAX),
content 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,
) {
if let Some(op) = match (op_x, op_y) {
(Some(x), Some(y)) => Some($Op::xy(x, y, content)),
(Some(x), None) => Some($Op::x(x, content)),
(Some(y), None) => Some($Op::y(y, content)),
_ => None
} {
assert_eq!(Content::layout(&op, [x, y, w, h]),
Render::layout(&op, [x, y, w, h]));
}
}
}
}
}
test_op_transform!(test_op_fixed, Fixed);
test_op_transform!(test_op_min, Min);
test_op_transform!(test_op_max, Max);
test_op_transform!(test_op_push, Push);
test_op_transform!(test_op_pull, Pull);
test_op_transform!(test_op_shrink, Shrink);
test_op_transform!(test_op_expand, Expand);
test_op_transform!(test_op_margin, Margin);
test_op_transform!(test_op_padding, Padding);
}

View file

@ -3,8 +3,3 @@ mod coordinate; pub use self::coordinate::*;
mod direction; pub use self::direction::*; mod direction; pub use self::direction::*;
mod measure; pub use self::measure::*; mod measure; pub use self::measure::*;
mod size; pub use self::size::*; mod size; pub use self::size::*;
#[cfg(test)] #[test] fn test_space () {
use crate::*;
assert_eq!(Area::center(&[10u16, 10, 20, 20]), [20, 20]);
}

View file

@ -96,40 +96,3 @@ impl<N: Coordinate> Area<N> for [N;4] {
fn w (&self) -> N { self[2] } fn w (&self) -> N { self[2] }
fn h (&self) -> N { self[3] } fn h (&self) -> N { self[3] }
} }
#[cfg(test)] mod test_area {
use super::*;
use proptest::prelude::*;
proptest! {
#[test] fn test_area_prop (
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,
b in u16::MIN..u16::MAX,
) {
let _: [u16;4] = <[u16;4] as Area<u16>>::zero();
let _: [u16;4] = <[u16;4] as Area<u16>>::from_position([a, b]);
let _: [u16;4] = <[u16;4] as Area<u16>>::from_size([a, b]);
let area: [u16;4] = [x, y, w, h];
let _ = area.expect_min(a, b);
let _ = area.xy();
let _ = area.wh();
let _ = area.xywh();
let _ = area.clip_h(a);
let _ = area.clip_w(b);
let _ = area.clip([a, b]);
let _ = area.set_w(a);
let _ = area.set_h(b);
let _ = area.x2();
let _ = area.y2();
let _ = area.lrtb();
let _ = area.center();
let _ = area.center_x(a);
let _ = area.center_y(b);
let _ = area.center_xy([a, b]);
let _ = area.centered();
}
}
}

View file

@ -1,9 +1,12 @@
use crate::*; use crate::*;
#[cfg(test)] use proptest_derive::Arbitrary;
/// A cardinal direction. /// A cardinal direction.
#[derive(Copy, Clone, PartialEq, Debug)] #[derive(Copy, Clone, PartialEq, Debug)]
#[cfg_attr(test, derive(Arbitrary))] #[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]) {
let [x, y, w, h] = area.xywh(); let [x, y, w, h] = area.xywh();
@ -16,23 +19,3 @@ impl Direction {
} }
} }
} }
#[cfg(test)] mod test {
use super::*;
use proptest::prelude::*;
proptest! {
#[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,
) {
let _ = d.split_fixed([x, y, w, h], a);
}
}
}

View file

@ -38,26 +38,3 @@ impl<N: Coordinate> Size<N> for [N;2] {
fn x (&self) -> N { self[0] } fn x (&self) -> N { self[0] }
fn y (&self) -> N { self[1] } fn y (&self) -> N { self[1] }
} }
#[cfg(test)] mod test_size {
use super::*;
use proptest::prelude::*;
proptest! {
#[test] fn test_size (
x in u16::MIN..u16::MAX,
y in u16::MIN..u16::MAX,
a in u16::MIN..u16::MAX,
b in u16::MIN..u16::MAX,
) {
let size = [x, y];
let _ = size.w();
let _ = size.h();
let _ = size.wh();
let _ = size.clip_w(a);
let _ = size.clip_h(b);
let _ = size.expect_min(a, b);
let _ = size.to_area_pos();
let _ = size.to_area_size();
}
}
}

View file

@ -3,7 +3,14 @@ use std::time::Duration;
use std::thread::{spawn, JoinHandle}; use std::thread::{spawn, JoinHandle};
use crossterm::event::{poll, read}; use crossterm::event::{poll, read};
#[derive(Debug, Clone)] pub struct TuiIn(pub Arc<AtomicBool>, pub Event); #[derive(Debug, Clone)]
pub struct TuiIn(
/// Exit flag
pub Arc<AtomicBool>,
/// Input event
pub Event,
);
impl Input for TuiIn { impl Input for TuiIn {
type Event = Event; type Event = Event;
type Handled = bool; type Handled = bool;