1
0
Fork 0
forked from wry/wry

autocommit 2022-05-01 17:23:55 CEST

This commit is contained in:
Julian Orth 2022-05-01 17:23:55 +02:00
parent 4373ed05bf
commit e1d5bf0e5d
39 changed files with 1772 additions and 57 deletions

View 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();
}
}

View 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 {}

View 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 {}

View 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 {}

View 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 {}

View 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 {}

View 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 {}

View 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 {}