TestComponent: assert closer to callsite

Attempts to assert closer to callsite to make it easier to debug. This
requires that we also pay attention to remaining items in the
expect_buffer. This check is done on Drop.

Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
Maxime “pep” Buquet 2022-09-23 17:22:32 +02:00
parent e338bff920
commit ad5ece8ad5
Signed by: pep
GPG key ID: DEDA74AEECA9D0F2
4 changed files with 26 additions and 41 deletions

View file

@ -12,6 +12,7 @@ use std::marker::Send;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::task::Context;
use std::thread;
use async_trait::async_trait;
use futures::{task::Poll, Stream};
@ -162,7 +163,6 @@ impl From<Message> for TestElement {
#[derive(Debug)]
pub struct TestComponent {
in_buffer: VecDeque<TestElement>,
out_buffer: VecDeque<TestElement>,
expect_buffer: VecDeque<Expect>,
}
@ -175,7 +175,6 @@ impl TestComponent {
.map(|el| TestElement(el))
.collect::<Vec<_>>(),
),
out_buffer: VecDeque::new(),
expect_buffer: VecDeque::new(),
}
}
@ -212,33 +211,21 @@ impl TestComponent {
.push_back(Expect::Presence(Box::new(callback), desc.into()))
}
/// Asserts expected output and actual output are the same
pub fn assert(&mut self) {
loop {
let out = self.out_buffer.pop_front();
let expected = self.expect_buffer.pop_front();
match (out, expected) {
(None, None) => break,
(Some(out), Some(expected)) => match expected {
Expect::Element(el) => assert_eq!(String::from(&el), String::from(&out)),
Expect::Iq(cb, _) => cb(Iq::try_from(out.0).unwrap()),
Expect::Message(cb, _) => cb(Message::try_from(out.0).unwrap()),
Expect::Presence(cb, _) => cb(Presence::try_from(out.0).unwrap()),
},
(Some(out), None) => panic!("Missing matching expected element: {:?}", out),
(None, Some(expected)) => match expected {
Expect::Element(el) => panic!("Missing matching sent element: {:?}", el),
Expect::Iq(_, desc) => panic!("Missing iq: {}", desc),
Expect::Message(_, desc) => panic!("Missing message: {}", desc),
Expect::Presence(_, desc) => panic!("Missing presence: {}", desc),
},
}
}
}
fn _send_stanza<E: Into<TestElement> + Send>(&mut self, el: E) -> Result<(), Error> {
Ok(self.out_buffer.push_back(el.into()))
let out: TestElement = el.into();
let expected = self.expect_buffer.pop_front();
match expected {
Some(expected) => match expected {
Expect::Element(el) => assert_eq!(String::from(&el), String::from(&out)),
Expect::Iq(cb, _) => cb(Iq::try_from(out.0).unwrap()),
Expect::Message(cb, _) => cb(Message::try_from(out.0).unwrap()),
Expect::Presence(cb, _) => cb(Presence::try_from(out.0).unwrap()),
},
None => panic!("Missing matching expected element: {:?}", out),
}
Ok(())
}
}
@ -254,6 +241,17 @@ impl Stream for TestComponent {
}
}
impl Drop for TestComponent {
fn drop(&mut self) {
// Don't assert if we're already panicking. Rustc displays a huge backtrace when "panicked
// while panicking" even when nobody asks for it (RUST_BACKTRACE unset). Let the error
// appear if there isn't any other error.
if ! thread::panicking() {
assert_eq!(self.expect_buffer.len(), 0, "Remaining expected elements in the buffer");
}
}
}
#[async_trait]
impl ComponentTrait for TestComponent {
async fn send_stanza<E: Into<Element> + Send>(&mut self, el: E) -> Result<(), Error> {

View file

@ -468,7 +468,6 @@ mod tests {
);
room.broadcast_presence(&mut component, &occupant3, &realjid3, BroadcastPresence::Resync).await.unwrap();
component.assert();
}
#[tokio::test]
@ -521,7 +520,6 @@ mod tests {
);
room.broadcast_presence(&mut component, &occupant3, &realjid3, BroadcastPresence::Update).await.unwrap();
component.assert();
}
#[tokio::test]
@ -616,7 +614,6 @@ mod tests {
);
room.broadcast_presence(&mut component, &occupant3, &realjid3, BroadcastPresence::Join).await.unwrap();
component.assert();
}
#[tokio::test]
@ -681,6 +678,5 @@ mod tests {
);
room.broadcast_presence(&mut component, &occupant3, &realjid3, BroadcastPresence::Leave).await.unwrap();
component.assert();
}
}

View file

@ -61,5 +61,4 @@ async fn test_iq_unimplemented() {
component.expect(reply);
handle_stanza(&mut component, &mut rooms).await.unwrap();
component.assert();
}

View file

@ -106,7 +106,6 @@ async fn test_join_presence_empty_room() {
}, "Room subject to participant1");
handle_stanza(&mut component, &mut rooms).await.unwrap();
component.assert();
assert_eq!(rooms.len(), 1);
match rooms.get(&roomjid) {
@ -160,7 +159,6 @@ async fn test_join_presence_nick_already_assigned() {
);
handle_stanza(&mut component, &mut rooms).await.unwrap();
component.assert();
match rooms.get(&roomjid) {
Some(room) => assert_eq!(room.occupants.len(), 1),
@ -263,7 +261,6 @@ async fn test_join_presence_existing_room() {
}, "Subject for participant2");
handle_stanza(&mut component, &mut rooms).await.unwrap();
component.assert();
match rooms.get(&roomjid) {
Some(room) => assert_eq!(room.occupants.len(), 2),
@ -330,7 +327,6 @@ async fn test_presence_resync() {
);
handle_stanza(&mut component, &mut rooms).await.unwrap();
component.assert();
match rooms.get(&roomjid) {
Some(room) => assert_eq!(room.occupants.len(), 2),
@ -355,7 +351,6 @@ async fn test_leave_non_existing_room() {
let mut rooms: HashMap<BareJid, Room> = HashMap::new();
handle_stanza(&mut component, &mut rooms).await.unwrap();
// The leave should be ignored, there should be no output at all.
component.assert();
}
#[tokio::test]
@ -395,7 +390,6 @@ async fn test_leave_last_participant() {
handle_stanza(&mut component, &mut rooms).await.unwrap();
component.assert();
assert_eq!(rooms.len(), 0);
}
@ -458,7 +452,6 @@ async fn test_leave_room_not_last() {
);
handle_stanza(&mut component, &mut rooms).await.unwrap();
component.assert();
assert_eq!(rooms.len(), 1);
match rooms.get(&roomjid) {
Some(room) => assert_eq!(room.occupants.len(), 1),
@ -545,7 +538,6 @@ async fn test_join_msn() {
component.expect_message(|_| (), "Subject message for participant2");
handle_stanza(&mut component, &mut rooms).await.unwrap();
component.assert();
assert_eq!(rooms.len(), 1);
match rooms.get(&roomjid) {