flipdot_testing/
virtual_sign_bus.rs

1use std::error::Error;
2use std::mem;
3
4use log::{debug, info, warn};
5
6use flipdot_core::{Address, ChunkCount, Message, Offset, Operation, Page, PageFlipStyle, SignBus, SignType, State};
7
8/// Mock implementation of a bus containing one or more signs.
9///
10/// The bus is populated with one or more [`VirtualSign`]s which actually implement the sign protocol.
11/// `VirtualSignBus` forwards messages to each virtual sign in turn until one of them handles it.
12///
13/// While most likely not a 100% accurate implementation of the protocol, it is sufficient
14/// for interacting with a real ODK.
15///
16/// Messages and responses are logged using the [`log`] crate for debugging purposes. Consuming binaries
17/// typically use the [`env_logger`] crate and can be run with the `RUST_LOG=debug` environment variable
18/// to watch the bus messages go by.
19///
20/// # Examples
21///
22/// ```no_run
23/// use flipdot_core::PageFlipStyle;
24/// use flipdot_serial::SerialSignBus;
25/// use flipdot_testing::{Address, Odk, VirtualSign, VirtualSignBus};
26///
27/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
28/// #
29/// let bus = VirtualSignBus::new(vec![VirtualSign::new(Address(3), PageFlipStyle::Manual)]);
30/// let port = serial::open("/dev/ttyUSB0")?;
31/// let mut odk = Odk::try_new(port, bus)?;
32/// loop {
33///     // VirtualSignBus processes the messsages from the real ODK over serial.
34///     odk.process_message()?;
35/// }
36/// #
37/// # Ok(()) }
38/// ```
39///
40/// [`log`]: https://crates.io/crates/log
41/// [`env_logger`]: https://crates.io/crates/env_logger
42#[derive(Debug, Clone, PartialEq, Eq, Hash)]
43pub struct VirtualSignBus<'a> {
44    signs: Vec<VirtualSign<'a>>,
45}
46
47impl<'a> VirtualSignBus<'a> {
48    /// Creates a new `VirtualSignBus` with the specified virtual signs.
49    ///
50    /// # Examples
51    ///
52    /// ```no_run
53    /// # use flipdot_core::PageFlipStyle;
54    /// # use flipdot_serial::SerialSignBus;
55    /// # use flipdot_testing::{Address, Odk, VirtualSign, VirtualSignBus};
56    /// #
57    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
58    /// #
59    /// let bus = VirtualSignBus::new(vec![VirtualSign::new(Address(3), PageFlipStyle::Manual)]);
60    /// let port = serial::open("COM3")?;
61    /// let odk = Odk::try_new(port, bus)?;
62    /// #
63    /// # Ok(()) }
64    /// ```
65    pub fn new<I>(signs: I) -> Self
66    where
67        I: IntoIterator<Item = VirtualSign<'a>>,
68    {
69        VirtualSignBus {
70            signs: signs.into_iter().collect(),
71        }
72    }
73
74    /// Returns a reference to the [`VirtualSign`] at a specific index matching the original order passed to [`new`](Self::new).
75    ///
76    /// Useful when writing tests in order to verify properties of an individual sign.
77    ///
78    /// # Examples
79    ///
80    /// ```
81    /// # use flipdot_core::PageFlipStyle;
82    /// # use flipdot_testing::{Address, VirtualSign, VirtualSignBus};
83    /// let signs = vec![VirtualSign::new(Address(5), PageFlipStyle::Manual), VirtualSign::new(Address(16), PageFlipStyle::Manual)];
84    /// let bus = VirtualSignBus::new(signs);
85    /// let second_sign = bus.sign(1);
86    /// assert_eq!(Address(16), second_sign.address());
87    /// ```
88    pub fn sign(&self, index: usize) -> &VirtualSign<'a> {
89        &self.signs[index]
90    }
91}
92
93impl SignBus for VirtualSignBus<'_> {
94    /// Handles a bus message by trying each sign in turn to see if it can handle it (i.e. returns a [`Some`] response).
95    fn process_message<'a>(&mut self, message: Message<'_>) -> Result<Option<Message<'a>>, Box<dyn Error + Send + Sync>> {
96        debug!("Bus message: {}", message);
97        for sign in &mut self.signs {
98            let response = sign.process_message(&message);
99            if let Some(response_message) = response {
100                debug!(" Vsign {:04X}: {}", sign.address().0, response_message);
101                return Ok(Some(response_message));
102            }
103        }
104        Ok(None)
105    }
106}
107
108/// Mock implementation of a single sign on a [`VirtualSignBus`].
109///
110/// Encapsulates all the state associated with a virtual sign and implements the sign protocol for it.
111/// In general, you do not need to interact with this class directly; you simply pass it off to a
112/// [`VirtualSignBus`], which forwards messages appropriately.
113///
114/// # Examples
115///
116/// See [`VirtualSignBus`].
117#[derive(Debug, Clone, PartialEq, Eq, Hash)]
118pub struct VirtualSign<'a> {
119    address: Address,
120    flip_style: PageFlipStyle,
121    state: State,
122    pages: Vec<Page<'a>>,
123    pending_data: Vec<u8>,
124    data_chunks: u16,
125    width: u32,
126    height: u32,
127    sign_type: Option<SignType>,
128}
129
130impl VirtualSign<'_> {
131    /// Creates a new `VirtualSign` with the specified address and page flip style.
132    ///
133    /// # Examples
134    ///
135    /// ```
136    /// # use std::iter;
137    /// # use flipdot_core::PageFlipStyle;
138    /// # use flipdot_testing::{Address, VirtualSign, VirtualSignBus};
139    /// let sign = VirtualSign::new(Address(22), PageFlipStyle::Manual);
140    /// let bus = VirtualSignBus::new(iter::once(sign));
141    /// ```
142    pub fn new(address: Address, flip_style: PageFlipStyle) -> Self {
143        VirtualSign {
144            address,
145            flip_style,
146            state: State::Unconfigured,
147            pages: vec![],
148            pending_data: vec![],
149            data_chunks: 0,
150            width: 0,
151            height: 0,
152            sign_type: None,
153        }
154    }
155
156    /// Returns the sign's address.
157    ///
158    /// # Examples
159    ///
160    /// ```
161    /// # use flipdot_core::PageFlipStyle;
162    /// # use flipdot_testing::{Address, VirtualSign};
163    /// let sign = VirtualSign::new(Address(22), PageFlipStyle::Manual);
164    /// assert_eq!(Address(22), sign.address());
165    /// ```
166    pub fn address(&self) -> Address {
167        self.address
168    }
169
170    /// Returns the sign's current state.
171    ///
172    /// # Examples
173    ///
174    /// ```
175    /// # use flipdot_core::{PageFlipStyle, State};
176    /// # use flipdot_testing::{Address, VirtualSign};
177    /// #
178    /// let sign = VirtualSign::new(Address(3), PageFlipStyle::Manual);
179    /// assert_eq!(State::Unconfigured, sign.state());
180    /// ```
181    pub fn state(&self) -> State {
182        self.state
183    }
184
185    /// Returns the sign's configured type.
186    ///
187    /// This is initially [`None`] and will only be set if the sign has received a configuration message over the bus.
188    /// Note that even if it has, this may still be [`None`] if the configuration did not match any known types
189    /// (e.g. potentially when driving from a real ODK).
190    ///
191    /// # Examples
192    ///
193    /// ```
194    /// # use flipdot_core::PageFlipStyle;
195    /// # use flipdot_testing::{Address, VirtualSign};
196    /// let sign = VirtualSign::new(Address(17), PageFlipStyle::Manual);
197    /// assert_eq!(None, sign.sign_type());
198    /// ```
199    pub fn sign_type(&self) -> Option<SignType> {
200        self.sign_type
201    }
202
203    /// Returns the sign's current [`Page`]s as a slice.
204    ///
205    /// May be empty if no pages have yet been sent to this sign or it has been reset.
206    ///
207    /// # Examples
208    ///
209    /// ```
210    /// # use flipdot_core::PageFlipStyle;
211    /// # use flipdot_testing::{Address, VirtualSign};
212    /// let sign = VirtualSign::new(Address(1), PageFlipStyle::Manual);
213    /// assert!(sign.pages().is_empty());
214    /// ```
215    pub fn pages(&self) -> &[Page<'_>] {
216        &self.pages
217    }
218
219    /// Handle a bus message, updating our state accordingly.
220    ///
221    /// # Examples
222    ///
223    /// ```
224    /// # use flipdot_core::{Message, PageFlipStyle, State};
225    /// # use flipdot_testing::{Address, VirtualSign};
226    /// #
227    /// let mut sign = VirtualSign::new(Address(3), PageFlipStyle::Manual);
228    /// let response = sign.process_message(&Message::QueryState(Address(3)));
229    /// assert_eq!(Some(Message::ReportState(Address(3), State::Unconfigured)), response);
230    /// ```
231    pub fn process_message<'a>(&mut self, message: &Message<'_>) -> Option<Message<'a>> {
232        match *message {
233            Message::Hello(address) | Message::QueryState(address) if address == self.address => Some(self.query_state()),
234            Message::RequestOperation(address, Operation::ReceiveConfig) if address == self.address => self.receive_config(),
235            Message::SendData(offset, ref data) => self.send_data(offset, data.get()),
236            Message::DataChunksSent(chunks) => self.data_chunks_sent(chunks),
237            Message::RequestOperation(address, Operation::ReceivePixels) if address == self.address => self.receive_pixels(),
238            Message::PixelsComplete(address) if address == self.address => self.pixels_complete(),
239            Message::RequestOperation(address, Operation::ShowLoadedPage) if address == self.address => self.show_loaded_page(),
240            Message::RequestOperation(address, Operation::LoadNextPage) if address == self.address => self.load_next_page(),
241            Message::RequestOperation(address, Operation::StartReset) if address == self.address => Some(self.start_reset()),
242            Message::RequestOperation(address, Operation::FinishReset) if address == self.address => self.finish_reset(),
243            Message::Goodbye(address) if address == self.address => self.goodbye(),
244            _ => None,
245        }
246    }
247
248    /// Handles `QueryState` or `Hello` messages
249    fn query_state<'a>(&mut self) -> Message<'a> {
250        let state = self.state;
251
252        // We don't actually need to do anything to load or show a page,
253        // so just flip over to the final state for the next time we get asked.
254        match state {
255            State::PageLoadInProgress => self.state = State::PageLoaded,
256            State::PageShowInProgress => self.state = State::PageShown,
257            _ => {}
258        };
259
260        Message::ReportState(self.address, state)
261    }
262
263    /// Handles `RequestOperation` messages for `ReceiveConfig`.
264    fn receive_config<'a>(&mut self) -> Option<Message<'a>> {
265        match self.state {
266            State::Unconfigured | State::ConfigFailed => {
267                self.state = State::ConfigInProgress;
268                Some(Message::AckOperation(self.address, Operation::ReceiveConfig))
269            }
270            _ => None,
271        }
272    }
273
274    /// Handles `SendData` messages.
275    fn send_data<'a>(&mut self, offset: Offset, data: &[u8]) -> Option<Message<'a>> {
276        if self.state == State::ConfigInProgress && offset == Offset(0) && data.len() == 16 {
277            let (kind, width, height) = match data[0] {
278                0x04 => ("Max3000", data[5..9].iter().sum(), data[4]),
279                0x08 => ("Horizon", data[7], data[5]),
280                _ => return None,
281            };
282
283            info!(
284                "Vsign {:04X} configuration: {} x {} {} sign",
285                self.address.0, width, height, kind
286            );
287
288            self.sign_type = SignType::from_bytes(data).ok();
289            match self.sign_type {
290                Some(sign_type) => info!("Vsign {:04X} matches known type: {:?}", self.address.0, sign_type),
291                None => warn!("Please report unknown configuration {:?}", data),
292            }
293
294            self.width = u32::from(width);
295            self.height = u32::from(height);
296            self.data_chunks += 1;
297        } else if self.state == State::PixelsInProgress {
298            if offset == Offset(0) {
299                self.flush_pixels();
300            }
301            self.pending_data.extend_from_slice(data);
302            self.data_chunks += 1;
303        }
304        None
305    }
306
307    /// Handles `DataChunksSent` messages.
308    fn data_chunks_sent<'a>(&mut self, chunks: ChunkCount) -> Option<Message<'a>> {
309        if ChunkCount(self.data_chunks) == chunks {
310            match self.state {
311                State::ConfigInProgress => self.state = State::ConfigReceived,
312                State::PixelsInProgress => self.state = State::PixelsReceived,
313                _ => {}
314            }
315        } else {
316            match self.state {
317                State::ConfigInProgress => self.state = State::ConfigFailed,
318                State::PixelsInProgress => self.state = State::PixelsFailed,
319                _ => {}
320            }
321        }
322        self.flush_pixels();
323        self.data_chunks = 0;
324        None
325    }
326
327    /// Handles `RequestOperation` messages for `ReceivePixels`.
328    fn receive_pixels<'a>(&mut self) -> Option<Message<'a>> {
329        match self.state {
330            State::ConfigReceived
331            | State::PixelsFailed
332            | State::PageLoaded
333            | State::PageLoadInProgress
334            | State::PageShown
335            | State::PageShowInProgress
336            | State::ShowingPages => {
337                self.state = State::PixelsInProgress;
338                self.pages.clear();
339                Some(Message::AckOperation(self.address, Operation::ReceivePixels))
340            }
341            _ => None,
342        }
343    }
344
345    /// Handles `PixelsComplete` messages.
346    fn pixels_complete<'a>(&mut self) -> Option<Message<'a>> {
347        if self.state == State::PixelsReceived {
348            self.state = match self.flip_style {
349                PageFlipStyle::Automatic => State::ShowingPages,
350                PageFlipStyle::Manual => State::PageLoaded,
351            };
352            for page in &self.pages {
353                info!(
354                    "Vsign {:04X} Page {} ({} x {})\n{}",
355                    self.address.0,
356                    page.id(),
357                    page.width(),
358                    page.height(),
359                    page
360                );
361            }
362        }
363        None
364    }
365
366    /// Handles `RequestOperation` messages for `ShowLoadedPage`.
367    fn show_loaded_page<'a>(&mut self) -> Option<Message<'a>> {
368        if self.state == State::PageLoaded {
369            self.state = State::PageShowInProgress;
370            Some(Message::AckOperation(self.address, Operation::ShowLoadedPage))
371        } else {
372            None
373        }
374    }
375
376    /// Handles `RequestOperation` messages for `LoadNextPage`.
377    fn load_next_page<'a>(&mut self) -> Option<Message<'a>> {
378        if self.state == State::PageShown {
379            self.state = State::PageLoadInProgress;
380            Some(Message::AckOperation(self.address, Operation::LoadNextPage))
381        } else {
382            None
383        }
384    }
385
386    /// Handles `RequestOperation` messages for `StartReset`.
387    fn start_reset<'a>(&mut self) -> Message<'a> {
388        self.state = State::ReadyToReset;
389        Message::AckOperation(self.address, Operation::StartReset)
390    }
391
392    /// Handles `RequestOperation` messages for `FinishReset`.
393    fn finish_reset<'a>(&mut self) -> Option<Message<'a>> {
394        if self.state == State::ReadyToReset {
395            self.reset();
396            Some(Message::AckOperation(self.address, Operation::FinishReset))
397        } else {
398            None
399        }
400    }
401
402    /// Handles `Goodbye` messages.
403    fn goodbye<'a>(&mut self) -> Option<Message<'a>> {
404        self.reset();
405        None
406    }
407
408    /// Convert the currently-buffered pixel data into a `Page` and add it to our page vector.
409    fn flush_pixels(&mut self) {
410        if !self.pending_data.is_empty() {
411            let data = mem::take(&mut self.pending_data);
412            if self.width > 0 && self.height > 0 {
413                let page = Page::from_bytes(self.width, self.height, data).expect("Error loading page");
414                self.pages.push(page);
415            }
416        }
417    }
418
419    /// Reset the sign back to its initial unconfigured state. Used for the reset and shutdown operations.
420    fn reset(&mut self) {
421        self.state = State::Unconfigured;
422        self.pages.clear();
423        self.pending_data.clear();
424        self.data_chunks = 0;
425        self.width = 0;
426        self.height = 0;
427        self.sign_type = None;
428    }
429}
430
431#[cfg(test)]
432mod tests {
433    use super::*;
434    use flipdot_core::{Data, PageId};
435    use test_case::test_case;
436
437    #[test_case(PageFlipStyle::Automatic ; "automatic page flip")]
438    #[test_case(PageFlipStyle::Manual ; "manual page flip")]
439    fn normal_behavior(flip_style: PageFlipStyle) {
440        let mut page1 = Page::new(PageId(0), 90, 7);
441        for x in 0..page1.width() {
442            for y in 0..page1.height() {
443                page1.set_pixel(x, y, x % 2 == y % 2);
444            }
445        }
446
447        let mut page2 = Page::new(PageId(1), 90, 7);
448        for x in 0..page2.width() {
449            for y in 0..page2.height() {
450                page2.set_pixel(x, y, x % 2 != y % 2);
451            }
452        }
453
454        // Initial values
455        let mut sign = VirtualSign::new(Address(3), flip_style);
456        assert_eq!(Address(3), sign.address());
457        assert_eq!(None, sign.sign_type());
458        assert_eq!(0, sign.pages().len());
459        assert_eq!(0, sign.width);
460        assert_eq!(0, sign.height);
461
462        // Discover and configuration
463        let response = sign.process_message(&Message::Hello(Address(3)));
464        assert_eq!(Some(Message::ReportState(Address(3), State::Unconfigured)), response);
465
466        let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceiveConfig));
467        assert_eq!(Some(Message::AckOperation(Address(3), Operation::ReceiveConfig)), response);
468
469        let response = sign.process_message(&Message::QueryState(Address(3)));
470        assert_eq!(Some(Message::ReportState(Address(3), State::ConfigInProgress)), response);
471
472        let response = sign.process_message(&Message::SendData(
473            Offset(0x00),
474            Data::try_new(SignType::Max3000Side90x7.to_bytes()).unwrap(),
475        ));
476        assert_eq!(None, response);
477
478        let response = sign.process_message(&Message::QueryState(Address(3)));
479        assert_eq!(Some(Message::ReportState(Address(3), State::ConfigInProgress)), response);
480
481        let response = sign.process_message(&Message::DataChunksSent(ChunkCount(1)));
482        assert_eq!(None, response);
483
484        let response = sign.process_message(&Message::QueryState(Address(3)));
485        assert_eq!(Some(Message::ReportState(Address(3), State::ConfigReceived)), response);
486
487        assert_eq!(Some(SignType::Max3000Side90x7), sign.sign_type());
488        assert_eq!(90, sign.width);
489        assert_eq!(7, sign.height);
490
491        let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceivePixels));
492        assert_eq!(Some(Message::AckOperation(Address(3), Operation::ReceivePixels)), response);
493
494        // Send page
495        assert_eq!(0, sign.pages().len());
496
497        let mut chunks_sent = 0;
498        for (i, chunk) in page1.as_bytes().chunks(16).enumerate() {
499            let response = sign.process_message(&Message::QueryState(Address(3)));
500            assert_eq!(Some(Message::ReportState(Address(3), State::PixelsInProgress)), response);
501
502            let response = sign.process_message(&Message::SendData(Offset((i * 16) as u16), Data::try_new(chunk).unwrap()));
503            assert_eq!(None, response);
504
505            chunks_sent += 1;
506        }
507
508        let response = sign.process_message(&Message::QueryState(Address(3)));
509        assert_eq!(Some(Message::ReportState(Address(3), State::PixelsInProgress)), response);
510
511        let response = sign.process_message(&Message::DataChunksSent(ChunkCount(chunks_sent)));
512        assert_eq!(None, response);
513
514        let response = sign.process_message(&Message::QueryState(Address(3)));
515        assert_eq!(Some(Message::ReportState(Address(3), State::PixelsReceived)), response);
516
517        let response = sign.process_message(&Message::PixelsComplete(Address(3)));
518        assert_eq!(None, response);
519
520        assert_eq!(&[page1], sign.pages());
521
522        let response = sign.process_message(&Message::QueryState(Address(3)));
523
524        match flip_style {
525            PageFlipStyle::Automatic => {
526                assert_eq!(Some(Message::ReportState(Address(3), State::ShowingPages)), response);
527            }
528
529            PageFlipStyle::Manual => {
530                assert_eq!(Some(Message::ReportState(Address(3), State::PageLoaded)), response);
531
532                // Show page
533                let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ShowLoadedPage));
534                assert_eq!(Some(Message::AckOperation(Address(3), Operation::ShowLoadedPage)), response);
535
536                let response = sign.process_message(&Message::QueryState(Address(3)));
537                assert_eq!(Some(Message::ReportState(Address(3), State::PageShowInProgress)), response);
538
539                let response = sign.process_message(&Message::QueryState(Address(3)));
540                assert_eq!(Some(Message::ReportState(Address(3), State::PageShown)), response);
541
542                // Load next page
543                let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::LoadNextPage));
544                assert_eq!(Some(Message::AckOperation(Address(3), Operation::LoadNextPage)), response);
545
546                let response = sign.process_message(&Message::QueryState(Address(3)));
547                assert_eq!(Some(Message::ReportState(Address(3), State::PageLoadInProgress)), response);
548
549                let response = sign.process_message(&Message::QueryState(Address(3)));
550                assert_eq!(Some(Message::ReportState(Address(3), State::PageLoaded)), response);
551            }
552        }
553
554        // Send different page
555        let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceivePixels));
556        assert_eq!(Some(Message::AckOperation(Address(3), Operation::ReceivePixels)), response);
557
558        assert_eq!(0, sign.pages().len());
559
560        let mut chunks_sent = 0;
561        for (i, chunk) in page2.as_bytes().chunks(16).enumerate() {
562            let response = sign.process_message(&Message::QueryState(Address(3)));
563            assert_eq!(Some(Message::ReportState(Address(3), State::PixelsInProgress)), response);
564
565            let response = sign.process_message(&Message::SendData(Offset((i * 16) as u16), Data::try_new(chunk).unwrap()));
566            assert_eq!(None, response);
567
568            chunks_sent += 1;
569        }
570
571        let response = sign.process_message(&Message::QueryState(Address(3)));
572        assert_eq!(Some(Message::ReportState(Address(3), State::PixelsInProgress)), response);
573
574        let response = sign.process_message(&Message::DataChunksSent(ChunkCount(chunks_sent)));
575        assert_eq!(None, response);
576
577        let response = sign.process_message(&Message::QueryState(Address(3)));
578        assert_eq!(Some(Message::ReportState(Address(3), State::PixelsReceived)), response);
579
580        let response = sign.process_message(&Message::PixelsComplete(Address(3)));
581        assert_eq!(None, response);
582
583        assert_eq!(&[page2], sign.pages());
584
585        // Reset
586        let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::StartReset));
587        assert_eq!(Some(Message::AckOperation(Address(3), Operation::StartReset)), response);
588
589        let response = sign.process_message(&Message::Hello(Address(3)));
590        assert_eq!(Some(Message::ReportState(Address(3), State::ReadyToReset)), response);
591
592        let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::FinishReset));
593        assert_eq!(Some(Message::AckOperation(Address(3), Operation::FinishReset)), response);
594
595        let response = sign.process_message(&Message::Hello(Address(3)));
596        assert_eq!(Some(Message::ReportState(Address(3), State::Unconfigured)), response);
597
598        assert_eq!(Address(3), sign.address());
599        assert_eq!(None, sign.sign_type());
600        assert_eq!(0, sign.pages().len());
601        assert_eq!(0, sign.width);
602        assert_eq!(0, sign.height);
603
604        // Configure again
605        let response = sign.process_message(&Message::Hello(Address(3)));
606        assert_eq!(Some(Message::ReportState(Address(3), State::Unconfigured)), response);
607
608        let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceiveConfig));
609        assert_eq!(Some(Message::AckOperation(Address(3), Operation::ReceiveConfig)), response);
610
611        let response = sign.process_message(&Message::QueryState(Address(3)));
612        assert_eq!(Some(Message::ReportState(Address(3), State::ConfigInProgress)), response);
613
614        let response = sign.process_message(&Message::SendData(
615            Offset(0x00),
616            Data::try_new(SignType::Max3000Side90x7.to_bytes()).unwrap(),
617        ));
618        assert_eq!(None, response);
619
620        let response = sign.process_message(&Message::QueryState(Address(3)));
621        assert_eq!(Some(Message::ReportState(Address(3), State::ConfigInProgress)), response);
622
623        let response = sign.process_message(&Message::DataChunksSent(ChunkCount(1)));
624        assert_eq!(None, response);
625
626        let response = sign.process_message(&Message::QueryState(Address(3)));
627        assert_eq!(Some(Message::ReportState(Address(3), State::ConfigReceived)), response);
628
629        assert_eq!(Some(SignType::Max3000Side90x7), sign.sign_type());
630        assert_eq!(90, sign.width);
631        assert_eq!(7, sign.height);
632
633        // Shut down
634        let response = sign.process_message(&Message::Goodbye(Address(3)));
635        assert_eq!(None, response);
636
637        assert_eq!(None, sign.sign_type());
638        assert_eq!(0, sign.pages().len());
639        assert_eq!(0, sign.width);
640        assert_eq!(0, sign.height);
641
642        let response = sign.process_message(&Message::Hello(Address(3)));
643        assert_eq!(Some(Message::ReportState(Address(3), State::Unconfigured)), response);
644    }
645
646    #[test]
647    fn invalid_operations() {
648        let mut sign = VirtualSign::new(Address(3), PageFlipStyle::Manual);
649
650        let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceivePixels));
651        assert_eq!(None, response);
652
653        let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ShowLoadedPage));
654        assert_eq!(None, response);
655
656        let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::LoadNextPage));
657        assert_eq!(None, response);
658
659        let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::FinishReset));
660        assert_eq!(None, response);
661
662        let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceiveConfig));
663        assert_eq!(Some(Message::AckOperation(Address(3), Operation::ReceiveConfig)), response);
664
665        let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceiveConfig));
666        assert_eq!(None, response);
667    }
668
669    #[test]
670    fn unknown_config() {
671        let mut sign = VirtualSign::new(Address(3), PageFlipStyle::Manual);
672
673        let response = sign.process_message(&Message::Hello(Address(3)));
674        assert_eq!(Some(Message::ReportState(Address(3), State::Unconfigured)), response);
675
676        let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceiveConfig));
677        assert_eq!(Some(Message::AckOperation(Address(3), Operation::ReceiveConfig)), response);
678
679        let response = sign.process_message(&Message::QueryState(Address(3)));
680        assert_eq!(Some(Message::ReportState(Address(3), State::ConfigInProgress)), response);
681
682        let data = vec![
683            0x04, 0x99, 0x00, 0x0F, 0x09, 0x1C, 0x1C, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
684        ];
685        let response = sign.process_message(&Message::SendData(Offset(0x00), Data::try_new(data).unwrap()));
686        assert_eq!(None, response);
687
688        let response = sign.process_message(&Message::DataChunksSent(ChunkCount(1)));
689        assert_eq!(None, response);
690
691        let response = sign.process_message(&Message::QueryState(Address(3)));
692        assert_eq!(Some(Message::ReportState(Address(3), State::ConfigReceived)), response);
693
694        assert_eq!(None, sign.sign_type());
695        assert_eq!(56, sign.width);
696        assert_eq!(9, sign.height);
697    }
698
699    #[test]
700    fn invalid_config() {
701        let mut sign = VirtualSign::new(Address(3), PageFlipStyle::Manual);
702
703        let response = sign.process_message(&Message::Hello(Address(3)));
704        assert_eq!(Some(Message::ReportState(Address(3), State::Unconfigured)), response);
705
706        let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceiveConfig));
707        assert_eq!(Some(Message::AckOperation(Address(3), Operation::ReceiveConfig)), response);
708
709        let response = sign.process_message(&Message::QueryState(Address(3)));
710        assert_eq!(Some(Message::ReportState(Address(3), State::ConfigInProgress)), response);
711
712        let data = vec![
713            0x0F, 0x99, 0x00, 0x0F, 0x09, 0x1C, 0x1C, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
714        ];
715        let response = sign.process_message(&Message::SendData(Offset(0x00), Data::try_new(data).unwrap()));
716        assert_eq!(None, response);
717
718        let response = sign.process_message(&Message::DataChunksSent(ChunkCount(1)));
719        assert_eq!(None, response);
720
721        let response = sign.process_message(&Message::QueryState(Address(3)));
722        assert_eq!(Some(Message::ReportState(Address(3), State::ConfigFailed)), response);
723
724        assert_eq!(None, sign.sign_type());
725        assert_eq!(0, sign.width);
726        assert_eq!(0, sign.height);
727    }
728}