use std::collections::VecDeque;
use std::sync::Arc;
use std::time::Duration;
use visual_cortex::{
Brightness, CaptureError, EventKind, Frame, FrameSource, Rate, Region, Session,
};
struct ScriptedSource {
steps: VecDeque<Result<Arc<Frame>, CaptureError>>,
}
impl ScriptedSource {
fn new(steps: impl IntoIterator<Item = Result<Arc<Frame>, CaptureError>>) -> Self {
Self {
steps: steps.into_iter().collect(),
}
}
}
#[async_trait::async_trait]
impl FrameSource for ScriptedSource {
async fn capture_frame(&mut self) -> Result<Arc<Frame>, CaptureError> {
self.steps
.pop_front()
.unwrap_or(Err(CaptureError::Exhausted))
}
}
async fn next_event(stream: &mut visual_cortex::EventStream) -> visual_cortex::Event {
tokio::time::timeout(Duration::from_secs(30), stream.next())
.await
.expect("timed out waiting for event")
.expect("stream closed unexpectedly")
}
#[tokio::test(start_paused = true)]
async fn target_loss_and_reattach_emit_session_events() {
let bg = || Ok(Arc::new(Frame::solid(8, 8, [10, 10, 10, 255])));
let steps = vec![
bg(), Err(CaptureError::TargetLost), Err(CaptureError::TargetLost), bg(), bg(),
];
let session = Session::builder()
.source(ScriptedSource::new(steps))
.build()
.await
.unwrap();
let mut stream = session
.watch("probe")
.region(Region::Full)
.rate(Rate::hz(20.0))
.detector(Brightness)
.on_threshold(|_| false)
.subscribe()
.unwrap();
let first = next_event(&mut stream).await;
assert!(
matches!(first.kind, EventKind::TargetLost),
"expected TargetLost, got {:?}",
first.kind
);
let second = next_event(&mut stream).await;
assert!(
matches!(second.kind, EventKind::TargetReattached),
"expected TargetReattached, got {:?}",
second.kind
);
}