Skip to content

Commit

Permalink
Merge pull request #913 from psychon/atom_manager_tests
Browse files Browse the repository at this point in the history
Add some tests for atom_manager! macro
  • Loading branch information
mergify[bot] authored Jan 30, 2024
2 parents 4b60265 + 0aeb36a commit 0fbfd89
Showing 1 changed file with 205 additions and 0 deletions.
205 changes: 205 additions & 0 deletions x11rb/tests/x11_utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
use std::{collections::HashMap, io::IoSlice};
use x11rb::{
atom_manager,
connection::{
BufWithFds, DiscardMode, ReplyOrError, RequestConnection, RequestKind, SequenceNumber,
},
cookie::{Cookie, CookieWithFds, VoidCookie},
errors::{ConnectionError, ParseError, ReplyError},
protocol::xproto::{InternAtomReply, INTERN_ATOM_REQUEST},
utils::RawFdContainer,
x11_utils::{ExtensionInformation, Serialize, TryParse, TryParseFd},
};

atom_manager! {
Atoms: AtomsCookies {
FIRST,
SECOND,
THIRD: b"3rd",
LAST,
}
}

struct AtomFakeConnection {
// Mapping from byte string to the corresponding atom value and sequence number.
// If no entry is found, sending the InternAtom request fails.
// If the entry does not fit into u16, fetching the reply fails.
atoms_and_cookies: HashMap<Vec<u8>, u32>,
}

impl RequestConnection for AtomFakeConnection {
type Buf = Vec<u8>;

fn send_request_with_reply<R>(
&self,
bufs: &[IoSlice],
_fds: Vec<RawFdContainer>,
) -> Result<Cookie<Self, R>, ConnectionError>
where
R: TryParse,
{
let bytes: Vec<u8> = bufs.iter().flat_map(|buf| buf.iter().copied()).collect();
// request type and only-if-exists flag
assert_eq!(bytes[..2], [INTERN_ATOM_REQUEST, 0]);
// We ignore the length field
let name_len = usize::from(u16::from_ne_bytes([bytes[4], bytes[5]]));
let name = &bytes[8..(8 + name_len)];

match self.atoms_and_cookies.get(name) {
// We recycle the atom as the sequence number
Some(&atom) => Ok(Cookie::new(self, atom.into())),
None => Err(ConnectionError::UnsupportedExtension),
}
}

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> {
unimplemented!()
}

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> {
let sequence_u16 = match u16::try_from(sequence) {
Ok(value) => value,
Err(_) => return Err(ConnectionError::UnsupportedExtension),
};
let reply = InternAtomReply {
length: 0,
sequence: sequence_u16,
atom: sequence.try_into().unwrap(),
};
let mut data = reply.serialize().to_vec();
data.extend([0; 32]);
Ok(ReplyOrError::Reply(data))
}

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 {
2usize.pow(16)
}

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_atom_manager_success() {
let conn = AtomFakeConnection {
atoms_and_cookies: [
(b"FIRST".to_vec(), 42),
(b"SECOND".to_vec(), 50),
(b"3rd".to_vec(), 100),
(b"LAST".to_vec(), 200),
]
.into(),
};
let atoms = Atoms::new(&conn).unwrap();
let atoms = atoms.reply().unwrap();

assert_eq!(atoms.FIRST, 42);
assert_eq!(atoms.SECOND, 50);
assert_eq!(atoms.THIRD, 100);
assert_eq!(atoms.LAST, 200);
}

#[test]
fn test_atom_manager_sending_fails() {
let conn = AtomFakeConnection {
atoms_and_cookies: [
(b"FIRST".to_vec(), 42),
(b"3rd".to_vec(), 100),
(b"LAST".to_vec(), 200),
]
.into(),
};
match Atoms::new(&conn) {
// This error is produced in send_request_with_reply() above
Err(ConnectionError::UnsupportedExtension) => {}
Err(err) => panic!("Unexpected error: {err:?}"),
Ok(_) => unreachable!(),
};
}

#[test]
fn test_atom_manager_receiving_fails() {
// A value that does not fit into u16 indicates to AtomFakeConnection that receiving fails
let too_large = u32::from(u16::MAX) * 3;
let conn = AtomFakeConnection {
atoms_and_cookies: [
(b"FIRST".to_vec(), 42),
(b"SECOND".to_vec(), too_large),
(b"3rd".to_vec(), 100),
(b"LAST".to_vec(), 200),
]
.into(),
};
let atoms = Atoms::new(&conn).unwrap();
match atoms.reply() {
// This error is produced in wait_for_reply_or_raw_error() above
Err(ReplyError::ConnectionError(ConnectionError::UnsupportedExtension)) => {}
result => panic!("Unexpected result: {result:?}"),
}
}

0 comments on commit 0fbfd89

Please sign in to comment.