1use crate::error::{ReadOutcome, Result, UsbSerialError};
7use crate::transport::{BulkIn, BulkOut, ControlRequest, EndpointInfo, InterfaceInfo, Transport};
8use std::collections::VecDeque;
9use std::sync::{Arc, Mutex};
10
11#[derive(Debug, Clone)]
13pub struct RecordedControl {
14 pub request_type: u8,
15 pub request: u8,
16 pub value: u16,
17 pub index: u16,
18 pub data: Vec<u8>,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct RecordedBulkOut {
24 pub endpoint: u8,
25 pub data: Vec<u8>,
26}
27
28#[derive(Debug, Default)]
29struct FakeState {
30 device_descriptor: [u8; 18],
31 raw_descriptors: Vec<u8>,
32 interfaces: Vec<InterfaceInfo>,
33 endpoints: Vec<(u8, EndpointInfo)>,
34 recorded: Vec<RecordedControl>,
35 recorded_bulk_out: Vec<RecordedBulkOut>,
36 control_in_responses: Vec<Vec<u8>>,
37 interrupt_in_queue: VecDeque<u8>,
38 rx_queue: VecDeque<u8>,
39 tx_log: Vec<u8>,
40 bulk_read_error: Option<String>,
41 claimed: Vec<u8>,
42 open_endpoints: Vec<u8>,
44 at_modem: bool,
46 at_line_buf: Vec<u8>,
47}
48
49#[derive(Debug, Clone)]
51pub struct FakeTransport {
52 inner: Arc<Mutex<FakeState>>,
53}
54
55impl Default for FakeTransport {
56 fn default() -> Self {
57 Self::new()
58 }
59}
60
61impl FakeTransport {
62 pub fn new() -> Self {
64 Self::cdc_single_iface()
65 }
66
67 pub fn cdc_single_iface() -> Self {
69 let t = Self {
70 inner: Arc::new(Mutex::new(FakeState::default())),
71 };
72 {
73 let mut s = t.inner.lock().unwrap();
74 s.device_descriptor = [
75 18, 1, 0x00, 0x02, 0x02, 0x00, 0x00, 64, 0x34, 0x12, 0x78, 0x56, 0x00, 0x01, 0x01,
76 0x02, 0x00, 1,
77 ];
78 s.interfaces = vec![InterfaceInfo {
79 id: 0,
80 class: 2,
81 subclass: 2,
82 protocol: 0,
83 }];
84 s.endpoints = vec![
85 (
86 0,
87 EndpointInfo {
88 address: 0x81,
89 attributes: 2,
90 max_packet_size: 64,
91 interval: 0,
92 },
93 ),
94 (
95 0,
96 EndpointInfo {
97 address: 0x02,
98 attributes: 2,
99 max_packet_size: 64,
100 interval: 0,
101 },
102 ),
103 ];
104 }
105 t
106 }
107
108 pub fn ftdi_ft232r() -> Self {
110 let t = Self::cdc_single_iface();
111 t.set_vendor_product(0x0403, 0x6001);
112 t.set_interfaces(vec![InterfaceInfo {
113 id: 0,
114 class: 255,
115 subclass: 0,
116 protocol: 0,
117 }]);
118 t.configure_endpoints(&[(
119 0,
120 vec![
121 EndpointInfo {
122 address: 0x81,
123 attributes: 2,
124 max_packet_size: 64,
125 interval: 0,
126 },
127 EndpointInfo {
128 address: 0x02,
129 attributes: 2,
130 max_packet_size: 64,
131 interval: 0,
132 },
133 ],
134 )]);
135 t
136 }
137
138 pub fn ftdi_ft2232() -> Self {
139 let t = Self::ftdi_ft232r();
140 t.set_vendor_product(0x0403, 0x6010);
141 t.set_interfaces(vec![
142 InterfaceInfo {
143 id: 0,
144 class: 255,
145 subclass: 0,
146 protocol: 0,
147 },
148 InterfaceInfo {
149 id: 1,
150 class: 255,
151 subclass: 0,
152 protocol: 0,
153 },
154 ]);
155 t.configure_endpoints(&[
156 (
157 0,
158 vec![
159 EndpointInfo {
160 address: 0x81,
161 attributes: 2,
162 max_packet_size: 64,
163 interval: 0,
164 },
165 EndpointInfo {
166 address: 0x02,
167 attributes: 2,
168 max_packet_size: 64,
169 interval: 0,
170 },
171 ],
172 ),
173 (
174 1,
175 vec![
176 EndpointInfo {
177 address: 0x83,
178 attributes: 2,
179 max_packet_size: 64,
180 interval: 0,
181 },
182 EndpointInfo {
183 address: 0x04,
184 attributes: 2,
185 max_packet_size: 64,
186 interval: 0,
187 },
188 ],
189 ),
190 ]);
191 t.patch_device_descriptor(|d| d[13] = 7);
192 t
193 }
194
195 pub fn cp2102() -> Self {
196 Self::ftdi_ft232r().also(|t| t.set_vendor_product(0x10C4, 0xEA60))
197 }
198
199 pub fn cp2105() -> Self {
200 let t = Self::cp2102();
201 t.set_vendor_product(0x10C4, 0xEA70);
202 t.set_interfaces(vec![
203 InterfaceInfo {
204 id: 0,
205 class: 255,
206 subclass: 0,
207 protocol: 0,
208 },
209 InterfaceInfo {
210 id: 1,
211 class: 255,
212 subclass: 0,
213 protocol: 0,
214 },
215 ]);
216 t.configure_endpoints(&[
217 (
218 0,
219 vec![
220 EndpointInfo {
221 address: 0x81,
222 attributes: 2,
223 max_packet_size: 64,
224 interval: 0,
225 },
226 EndpointInfo {
227 address: 0x02,
228 attributes: 2,
229 max_packet_size: 64,
230 interval: 0,
231 },
232 ],
233 ),
234 (
235 1,
236 vec![
237 EndpointInfo {
238 address: 0x83,
239 attributes: 2,
240 max_packet_size: 64,
241 interval: 0,
242 },
243 EndpointInfo {
244 address: 0x04,
245 attributes: 2,
246 max_packet_size: 64,
247 interval: 0,
248 },
249 ],
250 ),
251 ]);
252 t
253 }
254
255 pub fn ch340_dual_iface() -> Self {
256 let t = Self::cdc_single_iface();
257 t.set_vendor_product(0x1A86, 0x7523);
258 t.set_interfaces(vec![
259 InterfaceInfo {
260 id: 0,
261 class: 255,
262 subclass: 0,
263 protocol: 0,
264 },
265 InterfaceInfo {
266 id: 1,
267 class: 255,
268 subclass: 0,
269 protocol: 0,
270 },
271 ]);
272 t.configure_endpoints(&[(
273 1,
274 vec![
275 EndpointInfo {
276 address: 0x82,
277 attributes: 2,
278 max_packet_size: 64,
279 interval: 0,
280 },
281 EndpointInfo {
282 address: 0x03,
283 attributes: 2,
284 max_packet_size: 64,
285 interval: 0,
286 },
287 ],
288 )]);
289 t
290 }
291
292 pub fn pl2303_hx() -> Self {
293 let t = Self::cdc_single_iface();
294 t.set_vendor_product(0x067B, 0x2303);
295 t.patch_device_descriptor(|d| d[4] = 0);
296 t.configure_endpoints(&[(
297 0,
298 vec![
299 EndpointInfo {
300 address: 0x81,
301 attributes: 3,
302 max_packet_size: 64,
303 interval: 1,
304 },
305 EndpointInfo {
306 address: 0x02,
307 attributes: 2,
308 max_packet_size: 64,
309 interval: 0,
310 },
311 EndpointInfo {
312 address: 0x83,
313 attributes: 2,
314 max_packet_size: 64,
315 interval: 0,
316 },
317 ],
318 )]);
319 t.set_interfaces(vec![InterfaceInfo {
320 id: 0,
321 class: 255,
322 subclass: 0,
323 protocol: 0,
324 }]);
325 t
326 }
327
328 pub fn pl2303_hxn() -> Self {
329 let t = Self::pl2303_hx();
330 t.patch_device_descriptor(|d| {
331 d[4] = 0x00;
332 d[7] = 64;
333 d[2] = 0x00;
334 d[3] = 0x02;
335 });
336 t
337 }
338
339 pub fn pl2303_type01() -> Self {
340 let t = Self::pl2303_hx();
341 t.patch_device_descriptor(|d| d[4] = 0x02);
342 t
343 }
344
345 pub fn pl2303_ta() -> Self {
346 let t = Self::pl2303_hx();
347 t.patch_device_descriptor(|d| {
348 d[2] = 0x00;
349 d[3] = 0x02;
350 d[12] = 0x00;
351 d[13] = 0x03;
352 });
353 t
354 }
355
356 pub fn cdc_iad() -> Self {
357 let t = Self::cdc_single_iface();
358 t.set_vendor_product(0x2341, 0x0043);
359 t.patch_device_descriptor(|d| {
360 d[4] = 0xEF;
361 d[5] = 0x02;
362 d[6] = 0x01;
363 });
364 let i0 = InterfaceInfo {
365 id: 0,
366 class: 2,
367 subclass: 2,
368 protocol: 0,
369 };
370 let i1 = InterfaceInfo {
371 id: 1,
372 class: 10,
373 subclass: 0,
374 protocol: 0,
375 };
376 t.set_interfaces(vec![i0, i1]);
377 t.configure_endpoints(&[
378 (
379 0,
380 vec![EndpointInfo {
381 address: 0x81,
382 attributes: 3,
383 max_packet_size: 64,
384 interval: 1,
385 }],
386 ),
387 (
388 1,
389 vec![
390 EndpointInfo {
391 address: 0x82,
392 attributes: 2,
393 max_packet_size: 64,
394 interval: 0,
395 },
396 EndpointInfo {
397 address: 0x03,
398 attributes: 2,
399 max_packet_size: 64,
400 interval: 0,
401 },
402 ],
403 ),
404 ]);
405 t.set_raw_descriptors(vec![
407 9, 4, 0, 0, 1, 2, 2, 0, 0, 7, 5, 0x81, 3, 64, 0, 1, 9, 4, 1, 0, 2, 10, 0, 0, 7, 5,
408 0x82, 2, 64, 0, 7, 5, 0x03, 2, 64, 0, 8, 11, 0, 2, 2, 2, 0, 0,
409 ]);
410 t
411 }
412
413 pub fn cdc_multi() -> Self {
414 let t = Self::cdc_iad();
415 t.set_interfaces(vec![
416 InterfaceInfo {
417 id: 0,
418 class: 2,
419 subclass: 2,
420 protocol: 0,
421 },
422 InterfaceInfo {
423 id: 1,
424 class: 10,
425 subclass: 0,
426 protocol: 0,
427 },
428 InterfaceInfo {
429 id: 2,
430 class: 2,
431 subclass: 2,
432 protocol: 0,
433 },
434 InterfaceInfo {
435 id: 3,
436 class: 10,
437 subclass: 0,
438 protocol: 0,
439 },
440 ]);
441 t.configure_endpoints(&[
442 (
443 1,
444 vec![
445 EndpointInfo {
446 address: 0x82,
447 attributes: 2,
448 max_packet_size: 64,
449 interval: 0,
450 },
451 EndpointInfo {
452 address: 0x03,
453 attributes: 2,
454 max_packet_size: 64,
455 interval: 0,
456 },
457 ],
458 ),
459 (
460 3,
461 vec![
462 EndpointInfo {
463 address: 0x84,
464 attributes: 2,
465 max_packet_size: 64,
466 interval: 0,
467 },
468 EndpointInfo {
469 address: 0x05,
470 attributes: 2,
471 max_packet_size: 64,
472 interval: 0,
473 },
474 ],
475 ),
476 ]);
477 t
478 }
479
480 pub fn gsm_modem() -> Self {
481 let t = Self::cdc_single_iface();
482 t.set_vendor_product(0x1782, 0x4D10);
483 t.set_interfaces(vec![InterfaceInfo {
484 id: 0,
485 class: 255,
486 subclass: 0,
487 protocol: 0,
488 }]);
489 t.configure_endpoints(&[(
490 0,
491 vec![
492 EndpointInfo {
493 address: 0x81,
494 attributes: 2,
495 max_packet_size: 64,
496 interval: 0,
497 },
498 EndpointInfo {
499 address: 0x02,
500 attributes: 2,
501 max_packet_size: 64,
502 interval: 0,
503 },
504 ],
505 )]);
506 t
507 }
508
509 pub fn chrome_ccd_3port() -> Self {
510 let t = Self::cdc_single_iface();
511 t.set_vendor_product(0x18D1, 0x5014);
512 let mut ifaces = Vec::new();
513 let mut eps = Vec::new();
514 for n in 0..3u8 {
515 ifaces.push(InterfaceInfo {
516 id: n,
517 class: 255,
518 subclass: 0,
519 protocol: 0,
520 });
521 eps.push((
522 n,
523 vec![
524 EndpointInfo {
525 address: 0x81 + n * 2,
526 attributes: 2,
527 max_packet_size: 64,
528 interval: 0,
529 },
530 EndpointInfo {
531 address: 0x02 + n * 2,
532 attributes: 2,
533 max_packet_size: 64,
534 interval: 0,
535 },
536 ],
537 ));
538 }
539 t.set_interfaces(ifaces);
540 t.configure_endpoints(&eps);
541 t
542 }
543
544 fn also<F: FnOnce(&Self)>(self, f: F) -> Self {
545 f(&self);
546 self
547 }
548
549 pub fn recorded_bulk_out(&self) -> Vec<RecordedBulkOut> {
550 self.inner.lock().unwrap().recorded_bulk_out.clone()
551 }
552
553 pub fn push_rx(&self, data: &[u8]) {
554 let mut s = self.inner.lock().unwrap();
555 s.rx_queue.extend(data);
556 }
557
558 pub fn push_interrupt_in(&self, data: &[u8]) {
559 let mut s = self.inner.lock().unwrap();
560 s.interrupt_in_queue.extend(data);
561 }
562
563 pub fn take_tx(&self) -> Vec<u8> {
565 let mut s = self.inner.lock().unwrap();
566 std::mem::take(&mut s.tx_log)
567 }
568
569 pub fn recorded_controls(&self) -> Vec<RecordedControl> {
571 self.inner.lock().unwrap().recorded.clone()
572 }
573
574 pub fn clear_recorded(&self) {
575 let mut s = self.inner.lock().unwrap();
576 s.recorded.clear();
577 s.recorded_bulk_out.clear();
578 }
579
580 pub fn claimed_interfaces(&self) -> Vec<u8> {
581 self.inner.lock().unwrap().claimed.clone()
582 }
583
584 pub fn script_control_in_response(&self, data: Vec<u8>) {
586 self.inner.lock().unwrap().control_in_responses.push(data);
587 }
588
589 pub fn inject_bulk_read_error(&self, msg: impl Into<String>) {
590 self.inner.lock().unwrap().bulk_read_error = Some(msg.into());
591 }
592
593 pub fn enable_at_modem(&self) {
595 let mut s = self.inner.lock().unwrap();
596 s.at_modem = true;
597 s.at_line_buf.clear();
598 }
599
600 pub fn disable_at_modem(&self) {
601 let mut s = self.inner.lock().unwrap();
602 s.at_modem = false;
603 s.at_line_buf.clear();
604 }
605
606 pub fn set_interfaces(&self, interfaces: Vec<InterfaceInfo>) {
607 self.inner.lock().unwrap().interfaces = interfaces;
608 }
609
610 pub fn configure_endpoints(&self, layout: &[(u8, Vec<EndpointInfo>)]) {
611 let mut s = self.inner.lock().unwrap();
612 s.endpoints = layout
613 .iter()
614 .flat_map(|(iface, eps)| eps.iter().map(move |ep| (*iface, *ep)))
615 .collect();
616 }
617
618 pub fn set_raw_descriptors(&self, raw: Vec<u8>) {
619 self.inner.lock().unwrap().raw_descriptors = raw;
620 }
621
622 pub fn set_vendor_product(&self, vendor_id: u16, product_id: u16) {
623 let mut s = self.inner.lock().unwrap();
624 s.device_descriptor[8] = (vendor_id & 0xff) as u8;
625 s.device_descriptor[9] = (vendor_id >> 8) as u8;
626 s.device_descriptor[10] = (product_id & 0xff) as u8;
627 s.device_descriptor[11] = (product_id >> 8) as u8;
628 }
629
630 pub fn patch_device_descriptor(&self, mut patch: impl FnMut(&mut [u8; 18])) {
631 let mut s = self.inner.lock().unwrap();
632 patch(&mut s.device_descriptor);
633 }
634}
635
636struct FakeBulkIn {
637 inner: Arc<Mutex<FakeState>>,
638 interrupt: bool,
639 endpoint: u8,
640}
641
642impl Drop for FakeBulkIn {
643 fn drop(&mut self) {
644 if let Ok(mut s) = self.inner.lock() {
645 s.open_endpoints.retain(|&e| e != self.endpoint);
646 }
647 }
648}
649
650impl BulkIn for FakeBulkIn {
651 fn read(&mut self, buf: &mut [u8], _timeout_ms: u32) -> Result<ReadOutcome> {
652 let mut s = self.inner.lock().unwrap();
653 if let Some(err) = s.bulk_read_error.take() {
654 return Err(UsbSerialError::Io(err));
655 }
656 let queue = if self.interrupt {
657 &mut s.interrupt_in_queue
658 } else {
659 &mut s.rx_queue
660 };
661 if queue.is_empty() {
662 return Ok(ReadOutcome::TimedOut);
663 }
664 let n = buf.len().min(queue.len());
665 for (i, byte) in queue.drain(..n).enumerate() {
666 buf[i] = byte;
667 }
668 Ok(ReadOutcome::Data(buf[..n].to_vec()))
669 }
670
671 fn cancel_all(&mut self) {}
672
673 fn clear_halt(&mut self) -> Result<()> {
674 Ok(())
675 }
676}
677
678struct FakeBulkOut {
679 inner: Arc<Mutex<FakeState>>,
680 endpoint: u8,
681}
682
683impl Drop for FakeBulkOut {
684 fn drop(&mut self) {
685 if let Ok(mut s) = self.inner.lock() {
686 s.open_endpoints.retain(|&e| e != self.endpoint);
687 }
688 }
689}
690
691impl BulkOut for FakeBulkOut {
692 fn write(&mut self, data: &[u8], _timeout_ms: u32) -> Result<usize> {
693 let mut s = self.inner.lock().unwrap();
694 s.tx_log.extend_from_slice(data);
695 s.recorded_bulk_out.push(RecordedBulkOut {
696 endpoint: self.endpoint,
697 data: data.to_vec(),
698 });
699 if s.at_modem {
700 feed_at_modem(&mut s, data);
701 }
702 Ok(data.len())
703 }
704
705 fn clear_halt(&mut self) -> Result<()> {
706 Ok(())
707 }
708}
709
710fn feed_at_modem(s: &mut FakeState, data: &[u8]) {
712 s.at_line_buf.extend_from_slice(data);
713 while let Some(idx) = s.at_line_buf.iter().position(|&b| b == b'\r') {
714 let raw: Vec<u8> = s.at_line_buf.drain(..=idx).collect();
715 let line = std::str::from_utf8(&raw[..raw.len().saturating_sub(1)])
716 .unwrap_or("")
717 .trim()
718 .to_ascii_uppercase();
719 let reply = at_modem_reply(&line);
720 s.rx_queue.extend(reply.as_bytes());
721 }
722}
723
724fn at_modem_reply(cmd: &str) -> String {
725 match cmd {
726 "" => "\r\nOK\r\n".to_string(),
727 "AT" => "\r\nOK\r\n".to_string(),
728 "ATI" => {
729 "\r\nQuectel_Ltd\r\nQuectel_M26\r\nRevision: M26FBR03A06-TTS\r\n\r\nOK\r\n".to_string()
730 }
731 "AT+GMR" => "\r\nRevision: M26FBR03A06-TTS\r\n\r\nOK\r\n".to_string(),
732 "AT+CSQ" => {
733 "\r\n+CREG: 0,1\r\n\r\n+CSQ: 20,99\r\n\r\nOK\r\n".to_string()
735 }
736 c if c.starts_with("AT") => "\r\nERROR\r\n".to_string(),
737 _ => String::new(),
739 }
740}
741
742impl Transport for FakeTransport {
743 fn raw_device_descriptor(&self) -> [u8; 18] {
744 self.inner.lock().unwrap().device_descriptor
745 }
746
747 fn raw_descriptors(&self) -> Vec<u8> {
748 self.inner.lock().unwrap().raw_descriptors.clone()
749 }
750
751 fn device_class(&self) -> u8 {
752 self.raw_device_descriptor()[4]
753 }
754
755 fn interfaces(&self) -> Vec<InterfaceInfo> {
756 self.inner.lock().unwrap().interfaces.clone()
757 }
758
759 fn endpoints(&self, interface: u8) -> Vec<EndpointInfo> {
760 self.inner
761 .lock()
762 .unwrap()
763 .endpoints
764 .iter()
765 .filter(|(iface, _)| *iface == interface)
766 .map(|(_, ep)| *ep)
767 .collect()
768 }
769
770 fn claim_interface(&self, interface: u8) -> Result<()> {
771 self.inner.lock().unwrap().claimed.push(interface);
772 Ok(())
773 }
774
775 fn release_interface(&self, interface: u8) -> Result<()> {
776 let mut s = self.inner.lock().unwrap();
777 s.claimed.retain(|&i| i != interface);
778 Ok(())
779 }
780
781 fn control_out(&self, req: &ControlRequest) -> Result<usize> {
782 let mut s = self.inner.lock().unwrap();
783 s.recorded.push(RecordedControl {
784 request_type: req.request_type,
785 request: req.request,
786 value: req.value,
787 index: req.index,
788 data: req.data.clone(),
789 });
790 Ok(req.data.len())
791 }
792
793 fn control_in(&self, req: &ControlRequest) -> Result<Vec<u8>> {
794 let mut s = self.inner.lock().unwrap();
795 s.recorded.push(RecordedControl {
796 request_type: req.request_type,
797 request: req.request,
798 value: req.value,
799 index: req.index,
800 data: req.data.clone(),
801 });
802 if let Some(resp) = s.control_in_responses.pop() {
803 return Ok(resp);
804 }
805 Ok(req.data.clone())
806 }
807
808 fn open_bulk_in(&self, endpoint: u8, _max_packet_size: u16) -> Result<Box<dyn BulkIn>> {
809 self.mark_endpoint_open(endpoint)?;
810 Ok(Box::new(FakeBulkIn {
811 inner: self.inner.clone(),
812 interrupt: false,
813 endpoint,
814 }))
815 }
816
817 fn open_bulk_out(&self, endpoint: u8, _max_packet_size: u16) -> Result<Box<dyn BulkOut>> {
818 self.mark_endpoint_open(endpoint)?;
819 Ok(Box::new(FakeBulkOut {
820 inner: self.inner.clone(),
821 endpoint,
822 }))
823 }
824
825 fn open_interrupt_in(&self, endpoint: u8, _max_packet_size: u16) -> Result<Box<dyn BulkIn>> {
826 self.mark_endpoint_open(endpoint)?;
827 Ok(Box::new(FakeBulkIn {
828 inner: self.inner.clone(),
829 interrupt: true,
830 endpoint,
831 }))
832 }
833}
834
835impl FakeTransport {
836 fn mark_endpoint_open(&self, endpoint: u8) -> Result<()> {
837 let mut s = self.inner.lock().unwrap();
838 if s.open_endpoints.contains(&endpoint) {
839 return Err(UsbSerialError::Io("endpoint already in use".into()));
840 }
841 s.open_endpoints.push(endpoint);
842 Ok(())
843 }
844}
845
846#[cfg(test)]
847mod at_modem_tests {
848 use super::*;
849
850 #[test]
851 fn at_modem_replies_ok_and_csq_with_urc() {
852 let fake = FakeTransport::cdc_single_iface();
853 fake.enable_at_modem();
854 let mut out = fake.open_bulk_out(0x02, 64).unwrap();
855 out.write(b"AT\r", 1000).unwrap();
856 out.write(b"AT+CSQ\r", 1000).unwrap();
857 let mut s = fake.inner.lock().unwrap();
858 let rx: Vec<u8> = s.rx_queue.drain(..).collect();
859 let text = String::from_utf8_lossy(&rx);
860 assert!(text.contains("OK"), "{text}");
861 assert!(text.contains("+CREG:"), "{text}");
862 assert!(text.contains("+CSQ: 20,99"), "{text}");
863 }
864
865 #[test]
866 fn at_modem_unknown_at_returns_error() {
867 let fake = FakeTransport::cdc_single_iface();
868 fake.enable_at_modem();
869 let mut out = fake.open_bulk_out(0x02, 64).unwrap();
870 out.write(b"AT+FOO\r", 1000).unwrap();
871 let mut s = fake.inner.lock().unwrap();
872 let rx: Vec<u8> = s.rx_queue.drain(..).collect();
873 assert_eq!(String::from_utf8_lossy(&rx), "\r\nERROR\r\n");
874 }
875}