autocommit 2022-05-01 17:23:55 CEST
This commit is contained in:
parent
4373ed05bf
commit
e1d5bf0e5d
39 changed files with 1772 additions and 57 deletions
45
src/it/test_ifs/test_callback.rs
Normal file
45
src/it/test_ifs/test_callback.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
use {
|
||||
crate::{
|
||||
it::{
|
||||
test_error::TestError, test_object::TestObject, test_transport::TestTransport,
|
||||
testrun::ParseFull,
|
||||
},
|
||||
utils::buffd::MsgParser,
|
||||
wire::{wl_callback::*, WlCallbackId},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct TestCallback {
|
||||
pub id: WlCallbackId,
|
||||
pub transport: Rc<TestTransport>,
|
||||
pub handler: Cell<Option<Box<dyn FnOnce()>>>,
|
||||
pub done: Cell<bool>,
|
||||
}
|
||||
|
||||
impl TestCallback {
|
||||
fn handle_done(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let _ev = Done::parse_full(parser)?;
|
||||
self.dispatch();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn dispatch(&self) {
|
||||
self.done.set(true);
|
||||
if let Some(handler) = self.handler.take() {
|
||||
handler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_object! {
|
||||
TestCallback, WlCallback;
|
||||
|
||||
DONE => handle_done,
|
||||
}
|
||||
|
||||
impl TestObject for TestCallback {
|
||||
fn on_remove(&self, _transport: &TestTransport) {
|
||||
self.dispatch();
|
||||
}
|
||||
}
|
||||
18
src/it/test_ifs/test_compositor.rs
Normal file
18
src/it/test_ifs/test_compositor.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
use {
|
||||
crate::{
|
||||
it::{test_object::TestObject, test_transport::TestTransport},
|
||||
wire::WlCompositorId,
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub struct TestCompositor {
|
||||
pub id: WlCompositorId,
|
||||
pub transport: Rc<TestTransport>,
|
||||
}
|
||||
|
||||
test_object! {
|
||||
TestCompositor, WlCompositor;
|
||||
}
|
||||
|
||||
impl TestObject for TestCompositor {}
|
||||
55
src/it/test_ifs/test_display.rs
Normal file
55
src/it/test_ifs/test_display.rs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
use {
|
||||
crate::{
|
||||
it::{
|
||||
test_error::TestError, test_object::TestObject, test_transport::TestTransport,
|
||||
testrun::ParseFull,
|
||||
},
|
||||
object::ObjectId,
|
||||
utils::buffd::MsgParser,
|
||||
wire::{wl_display::*, WlDisplayId},
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub struct TestDisplay {
|
||||
pub transport: Rc<TestTransport>,
|
||||
pub id: WlDisplayId,
|
||||
}
|
||||
|
||||
impl TestDisplay {
|
||||
fn handle_error(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let ev = Error::parse_full(parser)?;
|
||||
let msg = format!("Compositor sent an error: {}", ev.message);
|
||||
self.transport.error(&msg);
|
||||
self.transport.kill();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_delete_id(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let ev = DeleteId::parse_full(parser)?;
|
||||
match self.transport.objects.remove(&ObjectId::from_raw(ev.id)) {
|
||||
None => {
|
||||
let msg = format!(
|
||||
"Compositor sent delete_id for object {} which does not exist",
|
||||
ev.id
|
||||
);
|
||||
self.transport.error(&msg);
|
||||
self.transport.kill();
|
||||
}
|
||||
Some(obj) => {
|
||||
obj.on_remove(&self.transport);
|
||||
self.transport.obj_ids.borrow_mut().release(ev.id);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
test_object! {
|
||||
TestDisplay, WlDisplay;
|
||||
|
||||
ERROR => handle_error,
|
||||
DELETE_ID => handle_delete_id,
|
||||
}
|
||||
|
||||
impl TestObject for TestDisplay {}
|
||||
48
src/it/test_ifs/test_jay_compositor.rs
Normal file
48
src/it/test_ifs/test_jay_compositor.rs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
use {
|
||||
crate::{
|
||||
client::ClientId,
|
||||
it::{
|
||||
test_error::TestError, test_object::TestObject, test_transport::TestTransport,
|
||||
testrun::ParseFull,
|
||||
},
|
||||
utils::buffd::MsgParser,
|
||||
wire::{
|
||||
jay_compositor::{self, *},
|
||||
JayCompositorId,
|
||||
},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct TestJayCompositor {
|
||||
pub id: JayCompositorId,
|
||||
pub transport: Rc<TestTransport>,
|
||||
pub client_id: Cell<Option<ClientId>>,
|
||||
}
|
||||
|
||||
impl TestJayCompositor {
|
||||
pub async fn get_client_id(&self) -> Result<ClientId, TestError> {
|
||||
if self.client_id.get().is_none() {
|
||||
self.transport.send(GetClientId { self_id: self.id });
|
||||
}
|
||||
self.transport.sync().await;
|
||||
match self.client_id.get() {
|
||||
Some(c) => Ok(c),
|
||||
_ => bail!("Compositor did not send a client id"),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_client_id(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let ev = jay_compositor::ClientId::parse_full(parser)?;
|
||||
self.client_id.set(Some(ClientId::from_raw(ev.client_id)));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
test_object! {
|
||||
TestJayCompositor, JayCompositor;
|
||||
|
||||
CLIENT_ID => handle_client_id,
|
||||
}
|
||||
|
||||
impl TestObject for TestJayCompositor {}
|
||||
185
src/it/test_ifs/test_registry.rs
Normal file
185
src/it/test_ifs/test_registry.rs
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
use {
|
||||
crate::{
|
||||
it::{
|
||||
test_error::TestError,
|
||||
test_ifs::{
|
||||
test_compositor::TestCompositor, test_jay_compositor::TestJayCompositor,
|
||||
test_shm::TestShm,
|
||||
},
|
||||
test_object::TestObject,
|
||||
test_transport::TestTransport,
|
||||
testrun::ParseFull,
|
||||
},
|
||||
utils::{buffd::MsgParser, clonecell::CloneCell, copyhashmap::CopyHashMap},
|
||||
wire::{wl_registry::*, WlRegistryId},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct TestGlobal {
|
||||
pub name: u32,
|
||||
pub interface: String,
|
||||
pub version: u32,
|
||||
}
|
||||
|
||||
pub struct TestRegistrySingletons {
|
||||
pub jay_compositor: u32,
|
||||
pub wl_compositor: u32,
|
||||
pub wl_shm: u32,
|
||||
}
|
||||
|
||||
pub struct TestRegistry {
|
||||
pub id: WlRegistryId,
|
||||
pub transport: Rc<TestTransport>,
|
||||
pub globals: CopyHashMap<u32, Rc<TestGlobal>>,
|
||||
pub singletons: CloneCell<Option<Rc<TestRegistrySingletons>>>,
|
||||
pub jay_compositor: CloneCell<Option<Rc<TestJayCompositor>>>,
|
||||
pub compositor: CloneCell<Option<Rc<TestCompositor>>>,
|
||||
pub shm: CloneCell<Option<Rc<TestShm>>>,
|
||||
}
|
||||
|
||||
macro_rules! singleton {
|
||||
($field:expr) => {
|
||||
if let Some(s) = $field.get() {
|
||||
return Ok(s);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl TestRegistry {
|
||||
pub async fn get_singletons(&self) -> Result<Rc<TestRegistrySingletons>, TestError> {
|
||||
singleton!(self.singletons);
|
||||
self.transport.sync().await;
|
||||
singleton!(self.singletons);
|
||||
let mut jay_compositor = 0;
|
||||
let mut wl_compositor = 0;
|
||||
let mut wl_shm = 0;
|
||||
for global in self.globals.lock().values() {
|
||||
match global.interface.as_str() {
|
||||
"jay_compositor" => jay_compositor = global.name,
|
||||
"wl_compositor" => wl_compositor = global.name,
|
||||
"wl_shm" => wl_shm = global.name,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
macro_rules! singleton {
|
||||
($($name:ident,)*) => {
|
||||
TestRegistrySingletons {
|
||||
$(
|
||||
$name: {
|
||||
if $name == 0 {
|
||||
bail!("Compositor did not send {} singleton", stringify!($name));
|
||||
}
|
||||
$name
|
||||
},
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
let singletons = Rc::new(singleton! {
|
||||
jay_compositor,
|
||||
wl_compositor,
|
||||
wl_shm,
|
||||
});
|
||||
self.singletons.set(Some(singletons.clone()));
|
||||
Ok(singletons)
|
||||
}
|
||||
|
||||
pub async fn get_jay_compositor(&self) -> Result<Rc<TestJayCompositor>, TestError> {
|
||||
singleton!(self.jay_compositor);
|
||||
let singletons = self.get_singletons().await?;
|
||||
singleton!(self.jay_compositor);
|
||||
let jc = Rc::new(TestJayCompositor {
|
||||
id: self.transport.id(),
|
||||
transport: self.transport.clone(),
|
||||
client_id: Default::default(),
|
||||
});
|
||||
self.bind(&jc, singletons.jay_compositor, 1)?;
|
||||
self.jay_compositor.set(Some(jc.clone()));
|
||||
Ok(jc)
|
||||
}
|
||||
|
||||
pub async fn get_compositor(&self) -> Result<Rc<TestCompositor>, TestError> {
|
||||
singleton!(self.compositor);
|
||||
let singletons = self.get_singletons().await?;
|
||||
singleton!(self.compositor);
|
||||
let jc = Rc::new(TestCompositor {
|
||||
id: self.transport.id(),
|
||||
transport: self.transport.clone(),
|
||||
});
|
||||
self.bind(&jc, singletons.wl_compositor, 4)?;
|
||||
self.compositor.set(Some(jc.clone()));
|
||||
Ok(jc)
|
||||
}
|
||||
|
||||
pub async fn get_shm(&self) -> Result<Rc<TestShm>, TestError> {
|
||||
singleton!(self.shm);
|
||||
let singletons = self.get_singletons().await?;
|
||||
singleton!(self.shm);
|
||||
let jc = Rc::new(TestShm {
|
||||
id: self.transport.id(),
|
||||
transport: self.transport.clone(),
|
||||
formats: Default::default(),
|
||||
formats_awaited: Cell::new(false),
|
||||
});
|
||||
self.bind(&jc, singletons.wl_shm, 1)?;
|
||||
self.shm.set(Some(jc.clone()));
|
||||
Ok(jc)
|
||||
}
|
||||
|
||||
pub fn bind<O: TestObject>(
|
||||
&self,
|
||||
obj: &Rc<O>,
|
||||
name: u32,
|
||||
version: u32,
|
||||
) -> Result<(), TestError> {
|
||||
self.transport.send(Bind {
|
||||
self_id: self.id,
|
||||
name,
|
||||
interface: obj.interface().name(),
|
||||
version,
|
||||
id: obj.id().into(),
|
||||
});
|
||||
self.transport.add_obj(obj.clone())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_global(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let ev = Global::parse_full(parser)?;
|
||||
let prev = self.globals.set(
|
||||
ev.name,
|
||||
Rc::new(TestGlobal {
|
||||
name: ev.name,
|
||||
interface: ev.interface.to_string(),
|
||||
version: ev.version,
|
||||
}),
|
||||
);
|
||||
if prev.is_some() {
|
||||
self.transport.error(&format!(
|
||||
"Compositor sent global {} multiple times",
|
||||
ev.name
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_global_remove(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let ev = GlobalRemove::parse_full(parser)?;
|
||||
if self.globals.remove(&ev.name).is_none() {
|
||||
self.transport.error(&format!(
|
||||
"Compositor sent global_remove for {} which does not exist",
|
||||
ev.name
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
test_object! {
|
||||
TestRegistry, WlRegistry;
|
||||
|
||||
GLOBAL => handle_global,
|
||||
GLOBAL_REMOVE => handle_global_remove,
|
||||
}
|
||||
|
||||
impl TestObject for TestRegistry {}
|
||||
59
src/it/test_ifs/test_shm.rs
Normal file
59
src/it/test_ifs/test_shm.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
use {
|
||||
crate::{
|
||||
it::{
|
||||
test_error::TestError, test_ifs::test_shm_pool::TestShmPool, test_mem::TestMem,
|
||||
test_object::TestObject, test_transport::TestTransport, testrun::ParseFull,
|
||||
},
|
||||
utils::{buffd::MsgParser, clonecell::CloneCell, copyhashmap::CopyHashMap},
|
||||
wire::{wl_shm::*, WlShmId},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct TestShm {
|
||||
pub id: WlShmId,
|
||||
pub transport: Rc<TestTransport>,
|
||||
pub formats: CopyHashMap<u32, ()>,
|
||||
pub formats_awaited: Cell<bool>,
|
||||
}
|
||||
|
||||
impl TestShm {
|
||||
pub async fn formats(&self) -> &CopyHashMap<u32, ()> {
|
||||
if !self.formats_awaited.replace(true) {
|
||||
self.transport.sync().await;
|
||||
}
|
||||
&self.formats
|
||||
}
|
||||
|
||||
pub fn create_pool(&self, size: usize) -> Result<Rc<TestShmPool>, TestError> {
|
||||
let mem = TestMem::new(size)?;
|
||||
let pool = Rc::new(TestShmPool {
|
||||
id: self.transport.id(),
|
||||
transport: self.transport.clone(),
|
||||
mem: CloneCell::new(mem.clone()),
|
||||
destroyed: Cell::new(false),
|
||||
});
|
||||
self.transport.send(CreatePool {
|
||||
self_id: self.id,
|
||||
id: pool.id,
|
||||
fd: mem.fd.clone(),
|
||||
size: size as _,
|
||||
});
|
||||
self.transport.add_obj(pool.clone())?;
|
||||
Ok(pool)
|
||||
}
|
||||
|
||||
fn handle_format(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let ev = Format::parse_full(parser)?;
|
||||
self.formats.set(ev.format, ());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
test_object! {
|
||||
TestShm, WlShm;
|
||||
|
||||
FORMAT => handle_format,
|
||||
}
|
||||
|
||||
impl TestObject for TestShm {}
|
||||
61
src/it/test_ifs/test_shm_buffer.rs
Normal file
61
src/it/test_ifs/test_shm_buffer.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
use {
|
||||
crate::{
|
||||
it::{
|
||||
test_error::TestError, test_mem::TestMem, test_object::TestObject,
|
||||
test_transport::TestTransport, testrun::ParseFull,
|
||||
},
|
||||
utils::buffd::MsgParser,
|
||||
wire::{wl_buffer::*, WlBufferId},
|
||||
},
|
||||
std::{
|
||||
cell::Cell,
|
||||
ops::{Deref, Range},
|
||||
rc::Rc,
|
||||
},
|
||||
};
|
||||
|
||||
pub struct TestShmBuffer {
|
||||
pub id: WlBufferId,
|
||||
pub transport: Rc<TestTransport>,
|
||||
pub range: Range<usize>,
|
||||
pub mem: Rc<TestMem>,
|
||||
pub released: Cell<bool>,
|
||||
pub destroyed: Cell<bool>,
|
||||
}
|
||||
|
||||
impl TestShmBuffer {
|
||||
pub fn destroy(&self) {
|
||||
if self.destroyed.replace(true) {
|
||||
return;
|
||||
}
|
||||
self.transport.send(Destroy { self_id: self.id });
|
||||
}
|
||||
|
||||
fn handle_release(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let _ev = Release::parse_full(parser)?;
|
||||
self.released.set(true);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for TestShmBuffer {
|
||||
type Target = [Cell<u8>];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.mem[self.range.clone()]
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TestShmBuffer {
|
||||
fn drop(&mut self) {
|
||||
self.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
test_object! {
|
||||
TestShmBuffer, WlBuffer;
|
||||
|
||||
RELEASE => handle_release,
|
||||
}
|
||||
|
||||
impl TestObject for TestShmBuffer {}
|
||||
86
src/it/test_ifs/test_shm_pool.rs
Normal file
86
src/it/test_ifs/test_shm_pool.rs
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
use {
|
||||
crate::{
|
||||
format::Format,
|
||||
it::{
|
||||
test_error::TestError, test_ifs::test_shm_buffer::TestShmBuffer, test_mem::TestMem,
|
||||
test_object::TestObject, test_transport::TestTransport,
|
||||
},
|
||||
utils::clonecell::CloneCell,
|
||||
wire::{wl_shm_pool::*, WlShmPoolId},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct TestShmPool {
|
||||
pub id: WlShmPoolId,
|
||||
pub transport: Rc<TestTransport>,
|
||||
pub mem: CloneCell<Rc<TestMem>>,
|
||||
pub destroyed: Cell<bool>,
|
||||
}
|
||||
|
||||
impl TestShmPool {
|
||||
pub fn create_buffer(
|
||||
&self,
|
||||
offset: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
stride: i32,
|
||||
format: &Format,
|
||||
) -> Result<Rc<TestShmBuffer>, TestError> {
|
||||
let size = (height * stride) as usize;
|
||||
let start = offset as usize;
|
||||
let end = start + size;
|
||||
let mem = self.mem.get();
|
||||
if end > mem.len() {
|
||||
bail!("Out-of-bounds buffer");
|
||||
}
|
||||
let buffer = Rc::new(TestShmBuffer {
|
||||
id: self.transport.id(),
|
||||
transport: self.transport.clone(),
|
||||
range: start..end,
|
||||
mem,
|
||||
released: Cell::new(true),
|
||||
destroyed: Cell::new(false),
|
||||
});
|
||||
self.transport.add_obj(buffer.clone())?;
|
||||
self.transport.send(CreateBuffer {
|
||||
self_id: self.id,
|
||||
id: buffer.id,
|
||||
offset,
|
||||
width,
|
||||
height,
|
||||
stride,
|
||||
format: format.wl_id.unwrap_or(format.drm),
|
||||
});
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
pub fn resize(&self, size: usize) -> Result<(), TestError> {
|
||||
let mem = self.mem.get().grow(size)?;
|
||||
self.mem.set(mem);
|
||||
self.transport.send(Resize {
|
||||
self_id: self.id,
|
||||
size: size as _,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn destroy(&self) {
|
||||
if self.destroyed.replace(true) {
|
||||
return;
|
||||
}
|
||||
self.transport.send(Destroy { self_id: self.id });
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TestShmPool {
|
||||
fn drop(&mut self) {
|
||||
self.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
test_object! {
|
||||
TestShmPool, WlShmPool;
|
||||
}
|
||||
|
||||
impl TestObject for TestShmPool {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue