diff --git a/src/it.rs b/src/it.rs index ae6ba474..b3853b66 100644 --- a/src/it.rs +++ b/src/it.rs @@ -28,6 +28,8 @@ use { mod test_error; #[macro_use] mod test_object; +#[macro_use] +mod test_macros; pub mod test_backend; mod test_client; pub mod test_config; diff --git a/src/it/test_ifs.rs b/src/it/test_ifs.rs index b48cd469..1677b59a 100644 --- a/src/it/test_ifs.rs +++ b/src/it/test_ifs.rs @@ -2,6 +2,7 @@ pub mod test_callback; pub mod test_compositor; pub mod test_display; pub mod test_jay_compositor; +pub mod test_region; pub mod test_registry; pub mod test_screenshot; pub mod test_shm; diff --git a/src/it/test_ifs/test_compositor.rs b/src/it/test_ifs/test_compositor.rs index 253c97a1..cf03ac43 100644 --- a/src/it/test_ifs/test_compositor.rs +++ b/src/it/test_ifs/test_compositor.rs @@ -2,11 +2,14 @@ use { crate::{ it::{ test_error::TestError, - test_ifs::test_surface::TestSurface, + test_ifs::{test_region::TestRegion, test_surface::TestSurface}, test_object::{Deleted, TestObject}, test_transport::TestTransport, }, - wire::{wl_compositor::CreateSurface, WlCompositorId}, + wire::{ + wl_compositor::{CreateRegion, CreateSurface}, + WlCompositorId, + }, }, std::{cell::Cell, rc::Rc}, }; @@ -38,6 +41,28 @@ impl TestCompositor { self.tran.add_obj(surface.clone())?; Ok(surface) } + + pub async fn create_region(&self) -> Result, TestError> { + let id = self.tran.id(); + self.deleted.check()?; + self.tran.send(CreateRegion { + self_id: self.id, + id, + }); + self.tran.sync().await; + let client = self.tran.get_client()?; + let server = client.lookup(id)?; + let region = Rc::new(TestRegion { + id, + tran: self.tran.clone(), + server, + destroyed: Cell::new(false), + deleted: Default::default(), + expected: Default::default(), + }); + self.tran.add_obj(region.clone())?; + Ok(region) + } } test_object! { diff --git a/src/it/test_ifs/test_region.rs b/src/it/test_ifs/test_region.rs new file mode 100644 index 00000000..b2835447 --- /dev/null +++ b/src/it/test_ifs/test_region.rs @@ -0,0 +1,81 @@ +use { + crate::{ + ifs::wl_region::WlRegion, + it::{ + test_error::TestError, + test_object::{Deleted, TestObject}, + test_transport::TestTransport, + }, + rect::{Rect, RegionBuilder}, + wire::{wl_region::*, WlRegionId}, + }, + std::{ + cell::{Cell, RefCell}, + rc::Rc, + }, +}; + +pub struct TestRegion { + pub id: WlRegionId, + pub tran: Rc, + pub destroyed: Cell, + pub deleted: Deleted, + pub server: Rc, + pub expected: RefCell, +} + +impl TestRegion { + pub fn destroy(&self) -> Result<(), TestError> { + self.deleted.check()?; + if !self.destroyed.replace(true) { + self.tran.send(Destroy { self_id: self.id }); + } + Ok(()) + } + + pub fn add(&self, rect: Rect) -> Result<(), TestError> { + self.deleted.check()?; + self.expected.borrow_mut().add(rect); + self.tran.send(Add { + self_id: self.id, + x: rect.x1(), + y: rect.y1(), + width: rect.width(), + height: rect.height(), + }); + Ok(()) + } + + pub fn subtract(&self, rect: Rect) -> Result<(), TestError> { + self.deleted.check()?; + self.expected.borrow_mut().sub(rect); + self.tran.send(Subtract { + self_id: self.id, + x: rect.x1(), + y: rect.y1(), + width: rect.width(), + height: rect.height(), + }); + Ok(()) + } + + pub async fn check(&self) -> Result<(), TestError> { + self.tran.sync().await; + let expected = self.expected.borrow_mut().get(); + let actual = self.server.region(); + tassert_eq!(expected, actual); + Ok(()) + } +} + +impl Drop for TestRegion { + fn drop(&mut self) { + let _ = self.destroy(); + } +} + +test_object! { + TestRegion, WlRegion; +} + +impl TestObject for TestRegion {} diff --git a/src/it/test_macros.rs b/src/it/test_macros.rs new file mode 100644 index 00000000..69549a0b --- /dev/null +++ b/src/it/test_macros.rs @@ -0,0 +1,30 @@ +macro_rules! tassert { + ($cond:expr) => { + if !$cond { + bail!( + "Assert `{}` failed ({}:{})", + stringify!($cond), + file!(), + line!() + ); + } + }; +} + +macro_rules! tassert_eq { + ($left:expr, $right:expr) => {{ + let left = $left; + let right = $right; + if left != right { + bail!( + "Assert `{} = {:?} = {:?} = {}` failed ({}:{})", + stringify!($left), + left, + right, + stringify!($right), + file!(), + line!() + ); + } + }}; +} diff --git a/src/it/tests.rs b/src/it/tests.rs index d8b39b29..6b6aa99d 100644 --- a/src/it/tests.rs +++ b/src/it/tests.rs @@ -22,42 +22,12 @@ macro_rules! testcase { }; } -macro_rules! tassert { - ($cond:expr) => { - if !$cond { - bail!( - "Assert `{}` failed ({}:{})", - stringify!($cond), - file!(), - line!() - ); - } - }; -} - -macro_rules! tassert_eq { - ($left:expr, $right:expr) => {{ - let left = $left; - let right = $right; - if left != right { - bail!( - "Assert `{} = {:?} = {:?} = {}` failed ({}:{})", - stringify!($left), - left, - right, - stringify!($right), - file!(), - line!() - ); - } - }}; -} - mod t0001_shm_formats; mod t0002_window; mod t0003_multi_window; mod t0004_quit; mod t0005_create_seat; +mod t0006_region; pub trait TestCase: Sync { fn name(&self) -> &'static str; @@ -80,5 +50,6 @@ pub fn tests() -> Vec<&'static dyn TestCase> { t0003_multi_window, t0004_quit, t0005_create_seat, + t0006_region, } } diff --git a/src/it/tests/t0006_region.rs b/src/it/tests/t0006_region.rs new file mode 100644 index 00000000..9aaa57ea --- /dev/null +++ b/src/it/tests/t0006_region.rs @@ -0,0 +1,32 @@ +use { + crate::{ + it::{test_error::TestError, testrun::TestRun}, + rect::Rect, + }, + std::rc::Rc, +}; + +testcase!(); + +/// Test region creation +async fn test(run: Rc) -> Result<(), TestError> { + let client = run.create_client().await?; + + let region = client.comp.create_region().await?; + region.check().await?; + region.add(Rect::new(10, 20, 30, 40).unwrap())?; + region.check().await?; + region.subtract(Rect::new(15, 25, 25, 35).unwrap())?; + region.check().await?; + + let expected = region.expected.borrow_mut().get(); + + tassert_eq!(expected.extents(), Rect::new(10, 20, 30, 40).unwrap()); + tassert_eq!(expected.len(), 4); + tassert_eq!(expected[0], Rect::new(10, 20, 30, 25).unwrap()); + tassert_eq!(expected[1], Rect::new(10, 25, 15, 35).unwrap()); + tassert_eq!(expected[2], Rect::new(25, 25, 30, 35).unwrap()); + tassert_eq!(expected[3], Rect::new(10, 35, 30, 40).unwrap()); + + Ok(()) +} diff --git a/src/rect.rs b/src/rect.rs index 8ead6d98..26b14fc5 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -19,7 +19,7 @@ pub struct Rect { type Container = SmallVec<[Rect; 1]>; -#[derive(Clone)] +#[derive(Clone, Eq, PartialEq, Debug)] pub struct Region { rects: Container, extents: Rect, diff --git a/src/rect/region.rs b/src/rect/region.rs index 7d46f6ae..0d85d4e2 100644 --- a/src/rect/region.rs +++ b/src/rect/region.rs @@ -533,7 +533,7 @@ fn rects_to_bands(rects_tmp: &[Rect]) -> Container { merged } -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] enum BuilderOp { Add, Sub, @@ -545,6 +545,7 @@ impl Default for BuilderOp { } } +#[derive(Debug)] pub struct RegionBuilder { base: Rc, op: BuilderOp, @@ -599,5 +600,6 @@ impl RegionBuilder { BuilderOp::Add => self.base.union(®ion), BuilderOp::Sub => self.base.subtract(®ion), }; + self.pending.clear(); } }