Skip to content

Commit 72c87a7

Browse files
authored
test: add io::Builder::name for better panic messages (#7212)
Introduce tokio_test::io::Builder::name to configure name of the mock object, to include in panic messages. Also show number of remaining actions or action index in some cases to help debugging failed tests.
1 parent 8507e28 commit 72c87a7

File tree

1 file changed

+53
-9
lines changed

1 file changed

+53
-9
lines changed

tokio-test/src/io.rs

+53-9
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ pub struct Handle {
5252
pub struct Builder {
5353
// Sequence of actions for the Mock to take
5454
actions: VecDeque<Action>,
55+
name: String,
5556
}
5657

5758
#[derive(Debug, Clone)]
@@ -71,6 +72,7 @@ struct Inner {
7172
sleep: Option<Pin<Box<Sleep>>>,
7273
read_wait: Option<Waker>,
7374
rx: UnboundedReceiverStream<Action>,
75+
name: String,
7476
}
7577

7678
impl Builder {
@@ -127,6 +129,12 @@ impl Builder {
127129
self
128130
}
129131

132+
/// Set name of the mock IO object to include in panic messages and debug output
133+
pub fn name(&mut self, name: impl Into<String>) -> &mut Self {
134+
self.name = name.into();
135+
self
136+
}
137+
130138
/// Build a `Mock` value according to the defined script.
131139
pub fn build(&mut self) -> Mock {
132140
let (mock, _) = self.build_with_handle();
@@ -135,7 +143,7 @@ impl Builder {
135143

136144
/// Build a `Mock` value paired with a handle
137145
pub fn build_with_handle(&mut self) -> (Mock, Handle) {
138-
let (inner, handle) = Inner::new(self.actions.clone());
146+
let (inner, handle) = Inner::new(self.actions.clone(), self.name.clone());
139147

140148
let mock = Mock { inner };
141149

@@ -184,7 +192,7 @@ impl Handle {
184192
}
185193

186194
impl Inner {
187-
fn new(actions: VecDeque<Action>) -> (Inner, Handle) {
195+
fn new(actions: VecDeque<Action>, name: String) -> (Inner, Handle) {
188196
let (tx, rx) = mpsc::unbounded_channel();
189197

190198
let rx = UnboundedReceiverStream::new(rx);
@@ -195,6 +203,7 @@ impl Inner {
195203
read_wait: None,
196204
rx,
197205
waiting: None,
206+
name,
198207
};
199208

200209
let handle = Handle { tx };
@@ -256,7 +265,7 @@ impl Inner {
256265
Action::Write(ref mut expect) => {
257266
let n = cmp::min(src.len(), expect.len());
258267

259-
assert_eq!(&src[..n], &expect[..n]);
268+
assert_eq!(&src[..n], &expect[..n], "name={} i={}", self.name, i);
260269

261270
// Drop data that was matched
262271
expect.drain(..n);
@@ -418,7 +427,7 @@ impl AsyncWrite for Mock {
418427
self.inner.actions.push_back(action);
419428
}
420429
Poll::Ready(None) => {
421-
panic!("unexpected write");
430+
panic!("unexpected write {}", self.pmsg());
422431
}
423432
}
424433
}
@@ -429,7 +438,7 @@ impl AsyncWrite for Mock {
429438
let until = Instant::now() + rem;
430439
self.inner.sleep = Some(Box::pin(time::sleep_until(until)));
431440
} else {
432-
panic!("unexpected WouldBlock");
441+
panic!("unexpected WouldBlock {}", self.pmsg());
433442
}
434443
}
435444
Ok(0) => {
@@ -445,7 +454,7 @@ impl AsyncWrite for Mock {
445454
continue;
446455
}
447456
None => {
448-
panic!("unexpected write");
457+
panic!("unexpected write {}", self.pmsg());
449458
}
450459
}
451460
}
@@ -475,8 +484,16 @@ impl Drop for Mock {
475484
}
476485

477486
self.inner.actions.iter().for_each(|a| match a {
478-
Action::Read(data) => assert!(data.is_empty(), "There is still data left to read."),
479-
Action::Write(data) => assert!(data.is_empty(), "There is still data left to write."),
487+
Action::Read(data) => assert!(
488+
data.is_empty(),
489+
"There is still data left to read. {}",
490+
self.pmsg()
491+
),
492+
Action::Write(data) => assert!(
493+
data.is_empty(),
494+
"There is still data left to write. {}",
495+
self.pmsg()
496+
),
480497
_ => (),
481498
});
482499
}
@@ -505,6 +522,33 @@ fn is_task_ctx() -> bool {
505522

506523
impl fmt::Debug for Inner {
507524
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
508-
write!(f, "Inner {{...}}")
525+
if self.name.is_empty() {
526+
write!(f, "Inner {{...}}")
527+
} else {
528+
write!(f, "Inner {{name={}, ...}}", self.name)
529+
}
530+
}
531+
}
532+
533+
struct PanicMsgSnippet<'a>(&'a Inner);
534+
535+
impl<'a> fmt::Display for PanicMsgSnippet<'a> {
536+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
537+
if self.0.name.is_empty() {
538+
write!(f, "({} actions remain)", self.0.actions.len())
539+
} else {
540+
write!(
541+
f,
542+
"(name {}, {} actions remain)",
543+
self.0.name,
544+
self.0.actions.len()
545+
)
546+
}
547+
}
548+
}
549+
550+
impl Mock {
551+
fn pmsg(&self) -> PanicMsgSnippet<'_> {
552+
PanicMsgSnippet(&self.inner)
509553
}
510554
}

0 commit comments

Comments
 (0)