use crate::program::{Program, ProgramOptions};
use hojicha_core::{core::Model, error::Result, event::Event};
use std::sync::{mpsc, Arc, Mutex};
use std::time::Duration;
pub struct TestRunner<M: Model> {
program: crate::program::Program<M>,
timeout: Option<Duration>,
_message_log: Arc<Mutex<Vec<Event<M::Message>>>>,
}
impl<M: Model> TestRunner<M>
where
M::Message: Clone + Send + 'static,
{
pub fn new(model: M) -> Result<Self> {
Self::with_options(model, ProgramOptions::default().headless())
}
pub fn with_options(model: M, options: ProgramOptions) -> Result<Self> {
let program = Program::with_options(model, options)?;
Ok(Self {
program,
timeout: Some(Duration::from_secs(5)), _message_log: Arc::new(Mutex::new(Vec::new())),
})
}
pub fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
pub fn without_timeout(mut self) -> Self {
self.timeout = None;
self
}
pub fn init_async_bridge(&mut self) -> mpsc::SyncSender<Event<M::Message>> {
self.program.init_async_bridge()
}
pub fn sender(&self) -> Option<mpsc::SyncSender<Event<M::Message>>> {
self.program.sender()
}
pub fn send_message(&self, msg: M::Message) -> Result<()> {
self.program.send_message(msg)
}
pub fn run(self) -> Result<()> {
match self.timeout {
Some(timeout) => self.program.run_with_timeout(timeout),
None => self.program.run(),
}
}
pub fn run_until<F>(self, condition: F) -> Result<()>
where
F: FnMut(&M) -> bool + 'static,
{
self.program.run_until(condition)
}
pub fn run_for_updates(self, count: usize) -> Result<()> {
let counter = Arc::new(Mutex::new(0));
let target = count;
self.program.run_until(move |_| {
let mut c = counter.lock().unwrap();
*c += 1;
*c >= target
})
}
}
#[macro_export]
macro_rules! test_runner {
($model:expr) => {
$crate::testing::TestRunner::new($model).unwrap()
};
($model:expr, $timeout:expr) => {
$crate::testing::TestRunner::new($model)
.unwrap()
.with_timeout($timeout)
};
}