343 lines
9.6 KiB
Rust
343 lines
9.6 KiB
Rust
use std::cell::RefCell;
|
|
use std::io::IoSlice;
|
|
use std::ops::Deref;
|
|
|
|
use x11rb::connection::{
|
|
compute_length_field, BufWithFds, ReplyOrError, RequestConnection, RequestKind,
|
|
};
|
|
use x11rb::cookie::{Cookie, CookieWithFds, VoidCookie};
|
|
use x11rb::errors::{ConnectionError, ParseError, ReplyError};
|
|
use x11rb::protocol::xproto::{
|
|
ClientMessageData, ConnectionExt, KeymapNotifyEvent, Segment, SetupAuthenticate,
|
|
};
|
|
use x11rb::utils::RawFdContainer;
|
|
use x11rb::x11_utils::{ExtensionInformation, Serialize, TryParse, TryParseFd};
|
|
|
|
use x11rb_protocol::{DiscardMode, SequenceNumber};
|
|
|
|
#[derive(Debug)]
|
|
struct SavedRequest {
|
|
has_reply: bool,
|
|
data: Vec<u8>,
|
|
}
|
|
|
|
impl SavedRequest {
|
|
fn new(has_reply: bool, data: &[IoSlice]) -> SavedRequest {
|
|
let data = data
|
|
.iter()
|
|
.flat_map(|slice| slice.deref())
|
|
.copied()
|
|
.collect::<Vec<_>>();
|
|
SavedRequest { has_reply, data }
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Default)]
|
|
struct FakeConnection(RefCell<Vec<SavedRequest>>);
|
|
|
|
impl FakeConnection {
|
|
fn check_requests(&self, expected: &[(bool, Vec<u8>)]) {
|
|
let vec = self.0.borrow();
|
|
for (expected, actual) in expected.iter().zip(vec.iter()) {
|
|
assert_eq!(expected.0, actual.has_reply);
|
|
assert_eq!(actual.data, expected.1);
|
|
}
|
|
assert_eq!(expected.len(), vec.len());
|
|
}
|
|
|
|
fn internal_send_request(
|
|
&self,
|
|
bufs: &[IoSlice],
|
|
fds: Vec<RawFdContainer>,
|
|
) -> Result<SequenceNumber, ConnectionError> {
|
|
assert_eq!(fds.len(), 0);
|
|
|
|
let mut storage = Default::default();
|
|
let bufs = compute_length_field(self, bufs, &mut storage)?;
|
|
|
|
self.0.borrow_mut().push(SavedRequest::new(false, bufs));
|
|
Ok(0)
|
|
}
|
|
}
|
|
|
|
impl RequestConnection for FakeConnection {
|
|
type Buf = Vec<u8>;
|
|
|
|
fn send_request_with_reply<R>(
|
|
&self,
|
|
bufs: &[IoSlice],
|
|
fds: Vec<RawFdContainer>,
|
|
) -> Result<Cookie<'_, Self, R>, ConnectionError>
|
|
where
|
|
R: TryParse,
|
|
{
|
|
Ok(Cookie::new(self, self.internal_send_request(bufs, fds)?))
|
|
}
|
|
|
|
fn send_request_with_reply_with_fds<R>(
|
|
&self,
|
|
_bufs: &[IoSlice],
|
|
_fds: Vec<RawFdContainer>,
|
|
) -> Result<CookieWithFds<'_, Self, R>, ConnectionError>
|
|
where
|
|
R: TryParseFd,
|
|
{
|
|
unimplemented!()
|
|
}
|
|
|
|
fn send_request_without_reply(
|
|
&self,
|
|
bufs: &[IoSlice],
|
|
fds: Vec<RawFdContainer>,
|
|
) -> Result<VoidCookie<'_, Self>, ConnectionError> {
|
|
Ok(VoidCookie::new(
|
|
self,
|
|
self.internal_send_request(bufs, fds)?,
|
|
))
|
|
}
|
|
|
|
fn discard_reply(&self, _sequence: SequenceNumber, _kind: RequestKind, _mode: DiscardMode) {
|
|
// Just ignore this
|
|
}
|
|
|
|
fn prefetch_extension_information(
|
|
&self,
|
|
_extension_name: &'static str,
|
|
) -> Result<(), ConnectionError> {
|
|
unimplemented!();
|
|
}
|
|
|
|
fn extension_information(
|
|
&self,
|
|
_extension_name: &'static str,
|
|
) -> Result<Option<ExtensionInformation>, ConnectionError> {
|
|
unimplemented!()
|
|
}
|
|
|
|
fn wait_for_reply_or_raw_error(
|
|
&self,
|
|
_sequence: SequenceNumber,
|
|
) -> Result<ReplyOrError<Vec<u8>>, ConnectionError> {
|
|
unimplemented!()
|
|
}
|
|
|
|
fn wait_for_reply(
|
|
&self,
|
|
_sequence: SequenceNumber,
|
|
) -> Result<Option<Vec<u8>>, ConnectionError> {
|
|
unimplemented!()
|
|
}
|
|
|
|
fn wait_for_reply_with_fds_raw(
|
|
&self,
|
|
_sequence: SequenceNumber,
|
|
) -> Result<ReplyOrError<BufWithFds<Vec<u8>>, Vec<u8>>, ConnectionError> {
|
|
unimplemented!()
|
|
}
|
|
|
|
fn check_for_raw_error(
|
|
&self,
|
|
_sequence: SequenceNumber,
|
|
) -> Result<Option<Vec<u8>>, ConnectionError> {
|
|
unimplemented!()
|
|
}
|
|
|
|
fn maximum_request_bytes(&self) -> usize {
|
|
// Must be at least 4 * 2^16 so that we can test BIG-REQUESTS
|
|
2usize.pow(19)
|
|
}
|
|
|
|
fn prefetch_maximum_request_bytes(&self) {
|
|
unimplemented!()
|
|
}
|
|
|
|
fn parse_error(&self, _error: &[u8]) -> Result<x11rb::x11_utils::X11Error, ParseError> {
|
|
unimplemented!()
|
|
}
|
|
|
|
fn parse_event(&self, _event: &[u8]) -> Result<x11rb::protocol::Event, ParseError> {
|
|
unimplemented!()
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_poly_segment() -> Result<(), ReplyError> {
|
|
let conn = FakeConnection::default();
|
|
let drawable = 42;
|
|
let gc = 0x1337;
|
|
let segments = [
|
|
Segment {
|
|
x1: 1,
|
|
y1: 2,
|
|
x2: 3,
|
|
y2: 4,
|
|
},
|
|
Segment {
|
|
x1: 5,
|
|
y1: 6,
|
|
x2: 7,
|
|
y2: 8,
|
|
},
|
|
];
|
|
let length: u16 = (12 + segments.len() * 8) as u16 / 4;
|
|
conn.poly_segment(drawable, gc, &segments)?;
|
|
|
|
let mut expected = vec![
|
|
x11rb::protocol::xproto::POLY_SEGMENT_REQUEST,
|
|
0, // padding
|
|
];
|
|
expected.extend(length.to_ne_bytes()); // length, not in the xml
|
|
expected.extend(drawable.to_ne_bytes());
|
|
expected.extend(gc.to_ne_bytes());
|
|
// Segments
|
|
for x in 1u16..9u16 {
|
|
expected.extend(x.to_ne_bytes());
|
|
}
|
|
conn.check_requests(&[(false, expected)]);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_big_requests() -> Result<(), ConnectionError> {
|
|
let conn = FakeConnection::default();
|
|
let big_buffer = [0; (1 << 18) + 1];
|
|
let drawable: u32 = 42;
|
|
let gc: u32 = 0x1337;
|
|
let x: i16 = 21;
|
|
let y: i16 = 7;
|
|
let padding = 3; // big_buffer's size rounded up to a multiple of 4
|
|
let big_request_length_field = 4;
|
|
let length: u32 = (16 + big_request_length_field + big_buffer.len() as u32 + padding) / 4;
|
|
conn.poly_text16(drawable, gc, x, y, &big_buffer)?;
|
|
|
|
let mut expected = vec![
|
|
x11rb::protocol::xproto::POLY_TEXT16_REQUEST,
|
|
// padding
|
|
0,
|
|
// Length of zero: we use big requests
|
|
0,
|
|
0,
|
|
];
|
|
// Actual length
|
|
expected.extend(length.to_ne_bytes());
|
|
|
|
expected.extend(drawable.to_ne_bytes());
|
|
expected.extend(gc.to_ne_bytes());
|
|
expected.extend(x.to_ne_bytes());
|
|
expected.extend(y.to_ne_bytes());
|
|
expected.extend(big_buffer.iter());
|
|
expected.extend((0..padding).map(|_| 0));
|
|
|
|
conn.check_requests(&[(false, expected)]);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_too_large_request() {
|
|
let conn = FakeConnection::default();
|
|
let big_buffer = [0; (1 << 19) + 1];
|
|
let drawable: u32 = 42;
|
|
let gc: u32 = 0x1337;
|
|
let x: i16 = 21;
|
|
let y: i16 = 7;
|
|
let res = conn.poly_text16(drawable, gc, x, y, &big_buffer);
|
|
match res.unwrap_err() {
|
|
ConnectionError::MaximumRequestLengthExceeded => {}
|
|
err => panic!("Wrong error: {err:?}"),
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn test_send_event() -> Result<(), ConnectionError> {
|
|
// Prepare the event
|
|
let buffer: [u8; 32] = [
|
|
11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
|
24, 25, 26, 27, 28, 29, 30,
|
|
];
|
|
let event = KeymapNotifyEvent::try_parse(&buffer[..])?.0;
|
|
|
|
// "Send" it
|
|
let conn = FakeConnection::default();
|
|
let propagate = true;
|
|
let destination: u32 = 0x1337;
|
|
let event_mask = x11rb_protocol::protocol::xproto::EventMask::BUTTON3_MOTION;
|
|
conn.send_event(propagate, destination, event_mask, event)?;
|
|
|
|
let mut expected = vec![x11rb::protocol::xproto::SEND_EVENT_REQUEST, propagate as _];
|
|
expected.extend(((12u16 + 32u16) / 4).to_ne_bytes());
|
|
expected.extend(destination.to_ne_bytes());
|
|
expected.extend(u32::from(event_mask).to_ne_bytes());
|
|
expected.extend(buffer.iter());
|
|
conn.check_requests(&[(false, expected)]);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_get_keyboard_mapping() -> Result<(), ConnectionError> {
|
|
let conn = FakeConnection::default();
|
|
let cookie = conn.get_keyboard_mapping(1, 2)?;
|
|
|
|
// Prevent call to discard_reply(), we only check request sending
|
|
std::mem::forget(cookie);
|
|
|
|
let mut expected = Vec::new();
|
|
let length: u16 = 2;
|
|
expected.push(101); // request major code
|
|
expected.push(0); // padding
|
|
expected.extend(length.to_ne_bytes()); // length, not in the xml
|
|
expected.push(1); // first keycode
|
|
expected.push(2); // length
|
|
expected.extend([0, 0]); // padding
|
|
|
|
conn.check_requests(&[(false, expected)]);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_client_message_data_parse() {
|
|
let short_array = [0, 0, 0];
|
|
let err = ClientMessageData::try_parse(&short_array);
|
|
assert!(err.is_err());
|
|
assert_eq!(err.unwrap_err(), ParseError::InsufficientData);
|
|
}
|
|
|
|
#[test]
|
|
fn test_set_modifier_mapping() -> Result<(), ConnectionError> {
|
|
let conn = FakeConnection::default();
|
|
let cookie = conn.set_modifier_mapping(&(1..17).collect::<Vec<_>>())?;
|
|
|
|
// Prevent call to discard_reply(), we only check request sending
|
|
std::mem::forget(cookie);
|
|
|
|
let mut expected = Vec::new();
|
|
let length: u16 = 5;
|
|
expected.push(118); // request major code
|
|
expected.push(2); // keycodes per modifier
|
|
expected.extend(length.to_ne_bytes()); // length, not in the xml
|
|
expected.extend(1u8..17u8);
|
|
|
|
conn.check_requests(&[(false, expected)]);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_serialize_setup_authenticate() {
|
|
let setup = SetupAuthenticate {
|
|
status: 2,
|
|
reason: b"12345678".to_vec(),
|
|
};
|
|
// At the time of writing, the code generator does not produce the correct code...
|
|
let length = 2u16.to_ne_bytes();
|
|
let setup_bytes = [
|
|
2, 0, 0, 0, 0, 0, length[0], length[1], b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8',
|
|
];
|
|
assert_eq!(&setup_bytes[..], &setup.serialize()[..]);
|
|
}
|
|
|
|
#[cfg(feature = "xinput")]
|
|
#[allow(dead_code)]
|
|
fn compile_test(conn: &impl RequestConnection) {
|
|
use x11rb::protocol::xinput::{xi_query_device, Device};
|
|
let _ = xi_query_device(conn, Device::ALL);
|
|
}
|