1 //! Additional combinators for testing sinks.
2 
3 use futures_sink::Sink;
4 
5 pub use crate::assert_unmoved::AssertUnmoved;
6 pub use crate::interleave_pending::InterleavePending;
7 pub use crate::track_closed::TrackClosed;
8 
9 /// Additional combinators for testing sinks.
10 pub 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.
assert_unmoved_sink(self) -> AssertUnmoved<Self> where Self: Sized,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.
interleave_pending_sink(self) -> InterleavePending<Self> where Self: Sized,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     /// ```
track_closed(self) -> TrackClosed<Self> where Self: Sized,74     fn track_closed(self) -> TrackClosed<Self>
75     where
76         Self: Sized,
77     {
78         TrackClosed::new(self)
79     }
80 }
81 
82 impl<Item, W> SinkTestExt<Item> for W where W: Sink<Item> {}
83