Skip to main content

rite_runtime/
test_support.rs

1//! Test-only helpers for action implementors.
2//!
3//! Provides a [`ReporterHarness`] that owns the channels and an
4//! [`InMemorySink`](crate::InMemorySink) needed to construct a
5//! [`Reporter`] in unit and integration tests, so downstream crates can
6//! exercise their actions without dealing with channel plumbing.
7
8use crossbeam_channel::{Receiver, Sender, unbounded};
9use rite_model::StepId;
10
11use crate::protocol::{ExecEvent, UiCommand};
12use crate::reporter::Reporter;
13use crate::transcript_sink::InMemorySink;
14use rite_model::StepFact;
15
16/// Owns the channels and sink needed to build a [`Reporter`] for tests.
17///
18/// The matching event receiver and command sender are kept alive for the
19/// harness's lifetime, so a reporter built from [`Self::reporter`] never
20/// sees a spurious disconnect while emitting facts.
21pub struct ReporterHarness {
22    sink: InMemorySink,
23    event_tx: Sender<ExecEvent>,
24    _event_rx: Receiver<ExecEvent>,
25    _cmd_tx: Sender<UiCommand>,
26    cmd_rx: Receiver<UiCommand>,
27}
28
29impl ReporterHarness {
30    /// Build a harness with empty channels and an empty sink.
31    #[must_use]
32    pub fn new() -> Self {
33        let (event_tx, event_rx) = unbounded();
34        let (cmd_tx, cmd_rx) = unbounded();
35        Self {
36            sink: InMemorySink::new(),
37            event_tx,
38            _event_rx: event_rx,
39            _cmd_tx: cmd_tx,
40            cmd_rx,
41        }
42    }
43
44    /// Build a reporter scoped to the given step. The reporter borrows
45    /// the harness for its lifetime.
46    pub fn reporter(&mut self, step: StepId) -> Reporter<'_> {
47        let mut reporter = Reporter::new(&self.event_tx, &self.cmd_rx, &mut self.sink);
48        reporter.set_current_step(Some(step));
49        reporter
50    }
51
52    /// Facts recorded by the harness's transcript sink, in order.
53    #[must_use]
54    pub fn facts(&self) -> &[StepFact] {
55        self.sink.facts()
56    }
57}
58
59impl Default for ReporterHarness {
60    fn default() -> Self {
61        Self::new()
62    }
63}