embedded_hal_mock/
common.rs1use std::{
4 collections::VecDeque,
5 fmt::Debug,
6 sync::{Arc, Mutex},
7 thread,
8};
9
10#[derive(Debug, Clone)]
24pub struct Generic<T: Clone + Debug + PartialEq> {
25 expected: Arc<Mutex<VecDeque<T>>>,
26 done_called: Arc<Mutex<DoneCallDetector>>,
27}
28
29impl<'a, T: 'a> Generic<T>
30where
31 T: Clone + Debug + PartialEq,
32{
33 pub fn new<E>(expected: E) -> Generic<T>
37 where
38 E: IntoIterator<Item = &'a T>,
39 {
40 let mut g = Generic {
41 expected: Arc::new(Mutex::new(VecDeque::new())),
42 done_called: Arc::new(Mutex::new(DoneCallDetector::new())),
43 };
44
45 g.update_expectations(expected);
46
47 g
48 }
49
50 pub fn update_expectations<E>(&mut self, expected: E)
57 where
58 E: IntoIterator<Item = &'a T>,
59 {
60 self.done_impl(false);
62
63 let new_expectations: VecDeque<T> = expected.into_iter().cloned().collect();
65
66 let mut expected = self.expected.lock().unwrap();
68 let mut done_called = self.done_called.lock().unwrap();
69
70 *expected = new_expectations;
72
73 done_called.reset();
75 }
76
77 #[deprecated(
79 since = "0.10.0",
80 note = "The method 'expect' was renamed to 'update_expectations'"
81 )]
82 pub fn expect<E>(&mut self, expected: E)
83 where
84 E: IntoIterator<Item = &'a T>,
85 {
86 self.update_expectations(expected)
87 }
88
89 pub fn done(&mut self) {
91 self.done_impl(true);
92 }
93
94 fn done_impl(&mut self, panic_if_already_done: bool) {
95 self.done_called
96 .lock()
97 .unwrap()
98 .mark_as_called(panic_if_already_done);
99 let e = self.expected.lock().unwrap();
100 assert!(e.is_empty(), "Not all expectations consumed");
101 }
102}
103
104impl<T> Iterator for Generic<T>
106where
107 T: Clone + Debug + PartialEq,
108{
109 type Item = T;
110 fn next(&mut self) -> Option<Self::Item> {
111 self.expected.lock().unwrap().pop_front()
112 }
113}
114
115#[derive(Debug)]
117pub(crate) struct DoneCallDetector {
118 called: bool,
119}
120
121impl DoneCallDetector {
122 pub(crate) fn new() -> Self {
123 Self { called: false }
124 }
125
126 pub(crate) fn mark_as_called(&mut self, panic_if_already_done: bool) {
131 if panic_if_already_done {
132 assert!(!self.called, "The `.done()` method was called twice!");
133 }
134 self.called = true;
135 }
136
137 pub(crate) fn reset(&mut self) {
139 self.called = false;
140 }
141}
142
143impl Drop for DoneCallDetector {
144 fn drop(&mut self) {
145 if !self.called && !thread::panicking() {
148 let msg = "WARNING: A mock (from embedded-hal-mock) was dropped \
149 without calling the `.done()` method. \
150 See https://github.com/dbrgn/embedded-hal-mock/issues/34 \
151 for more details.";
152
153 use std::io::Write;
157 let mut stderr = std::io::stderr();
158 stderr.write_all(b"\x1b[31m").ok();
159 stderr.write_all(msg.as_bytes()).ok();
160 stderr.write_all(b"\x1b[m\n").ok();
161 stderr.flush().ok();
162
163 panic!("{}", msg);
170 }
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 mod generic_mock {
179 use super::*;
180
181 #[test]
182 fn success() {
183 let expectations = [0u8, 1u8];
184 let mut mock: Generic<u8> = Generic::new(&expectations);
185
186 assert_eq!(mock.next(), Some(0u8));
187 assert_eq!(mock.next(), Some(1u8));
188 assert_eq!(mock.next(), None);
189 assert_eq!(mock.next(), None);
190
191 mock.done();
192 }
193
194 #[test]
195 #[should_panic(
196 expected = "WARNING: A mock (from embedded-hal-mock) was dropped without calling the `.done()` method. See https://github.com/dbrgn/embedded-hal-mock/issues/34 for more details."
197 )]
198 fn panic_if_drop_not_called() {
199 let expectations = [0u8, 1u8];
200 let mut mock: Generic<u8> = Generic::new(&expectations);
201 assert_eq!(mock.next(), Some(0u8));
202 assert_eq!(mock.next(), Some(1u8));
203 }
204
205 #[test]
206 #[should_panic(expected = "The `.done()` method was called twice!")]
207 fn panic_if_drop_called_twice() {
208 let expectations = [0u8, 1u8];
209 let mut mock: Generic<u8> = Generic::new(&expectations);
210 assert_eq!(mock.next(), Some(0u8));
211 assert_eq!(mock.next(), Some(1u8));
212 mock.done();
213 mock.done();
214 }
215 }
216}