1//! Additional combinators for testing sinks.
2
3use futures_sink::Sink;
4
5pub use crate::assert_unmoved::AssertUnmoved;
6pub use crate::interleave_pending::InterleavePending;
7pub use crate::track_closed::TrackClosed;
8
9/// Additional combinators for testing sinks.
10pub trait SinkTestExt<Item>: Sink<Item> {
11 /// Asserts that the given is not moved after being polled.
12 ///
13 /// A check for movement is performed each time the sink is polled
14 /// and when `Drop` is called.
15 ///
16 /// Aside from keeping track of the location at which the sink was first
17 /// polled and providing assertions, this sink adds no runtime behavior
18 /// and simply delegates to the child sink.
19 fn assert_unmoved_sink(self) -> AssertUnmoved<Self>
20 where
21 Self: Sized,
22 {
23 AssertUnmoved::new(self)
24 }
25
26 /// Introduces an extra [`Poll::Pending`](futures_core::task::Poll::Pending)
27 /// in between each operation on the sink.
28 fn interleave_pending_sink(self) -> InterleavePending<Self>
29 where
30 Self: Sized,
31 {
32 InterleavePending::new(self)
33 }
34
35 /// Track whether this sink has been closed and panics if it is used after closing.
36 ///
37 /// # Examples
38 ///
39 /// ```
40 /// # futures::executor::block_on(async {
41 /// use futures::sink::{SinkExt, drain};
42 /// use futures_test::sink::SinkTestExt;
43 ///
44 /// let mut sink = drain::<i32>().track_closed();
45 ///
46 /// sink.send(1).await?;
47 /// assert!(!sink.is_closed());
48 /// sink.close().await?;
49 /// assert!(sink.is_closed());
50 ///
51 /// # Ok::<(), std::convert::Infallible>(()) })?;
52 /// # Ok::<(), std::convert::Infallible>(())
53 /// ```
54 ///
55 /// Note: Unlike [`AsyncWriteTestExt::track_closed`] when
56 /// used as a sink the adaptor will panic if closed too early as there's no easy way to
57 /// integrate as an error.
58 ///
59 /// [`AsyncWriteTestExt::track_closed`]: crate::io::AsyncWriteTestExt::track_closed
60 ///
61 /// ```
62 /// # futures::executor::block_on(async {
63 /// use std::panic::AssertUnwindSafe;
64 /// use futures::{sink::{SinkExt, drain}, future::FutureExt};
65 /// use futures_test::sink::SinkTestExt;
66 ///
67 /// let mut sink = drain::<i32>().track_closed();
68 ///
69 /// sink.close().await?;
70 /// assert!(AssertUnwindSafe(sink.send(1)).catch_unwind().await.is_err());
71 /// # Ok::<(), std::convert::Infallible>(()) })?;
72 /// # Ok::<(), std::convert::Infallible>(())
73 /// ```
74 fn track_closed(self) -> TrackClosed<Self>
75 where
76 Self: Sized,
77 {
78 TrackClosed::new(self)
79 }
80}
81
82impl<Item, W> SinkTestExt<Item> for W where W: Sink<Item> {}
83