use std::time::Duration;
use visual_cortex::{Error, EventKind, FakeSource, Frame, Rate, Region, Session};
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")
}
fn checker_png() -> Vec<u8> {
let img = image::ImageBuffer::from_fn(8, 8, |x, y| {
if (x + y) % 2 == 0 {
image::Luma([255u8])
} else {
image::Luma([0u8])
}
});
let mut out = Vec::new();
img.write_to(&mut std::io::Cursor::new(&mut out), image::ImageFormat::Png)
.expect("png encode");
out
}
fn bg_frame() -> Frame {
Frame::from_fn(40, 30, |_, _| [30, 30, 30, 255])
}
fn icon_frame() -> Frame {
Frame::from_fn(40, 30, |x, y| {
if (10..18).contains(&x) && (6..14).contains(&y) {
if ((x - 10) + (y - 6)) % 2 == 0 {
[255, 255, 255, 255]
} else {
[0, 0, 0, 255]
}
} else {
[30, 30, 30, 255]
}
})
}
#[tokio::test(start_paused = true)]
async fn template_appears_and_vanishes() {
let mut frames = vec![bg_frame(), bg_frame(), bg_frame()];
frames.extend([icon_frame(), icon_frame(), icon_frame(), icon_frame()]);
frames.push(bg_frame());
let session = Session::builder()
.source(FakeSource::new(frames))
.build()
.await
.unwrap();
let mut stream = session
.watch("icon")
.region(Region::Full)
.rate(Rate::hz(20.0))
.template(&checker_png(), 0.9)
.subscribe()
.unwrap();
let appeared = next_event(&mut stream).await;
assert!(
matches!(appeared.kind, EventKind::TemplateAppeared { score } if score > 0.9),
"expected TemplateAppeared with high score, got {:?}",
appeared.kind
);
let vanished = next_event(&mut stream).await;
assert!(
matches!(vanished.kind, EventKind::TemplateVanished),
"expected TemplateVanished, got {:?}",
vanished.kind
);
let more = tokio::time::timeout(Duration::from_millis(500), stream.next()).await;
assert!(
more.is_err(),
"no further template events without a transition"
);
}
#[tokio::test]
async fn invalid_template_errors_at_subscribe() {
let session = Session::builder()
.source(FakeSource::new([Frame::solid(2, 2, [0, 0, 0, 255])]))
.build()
.await
.unwrap();
let err = session
.watch("bad")
.template(b"definitely not a png", 0.9)
.subscribe()
.unwrap_err();
assert!(matches!(err, Error::InvalidTemplate(name, _) if name == "bad"));
}
#[test]
fn facade_reexports_all_detectors() {
fn assert_detector<D: visual_cortex::Detector>() {}
assert_detector::<visual_cortex::Brightness>();
assert_detector::<visual_cortex::ColorMatch>();
assert_detector::<visual_cortex::ColorDominance>();
assert_detector::<visual_cortex::TemplateMatcher>();
assert_detector::<visual_cortex::FrameDiff>();
let _channel = visual_cortex::Channel::Red;
}