mod common;
use common::*;
use framewatch::{Config, Engine, EventKind, SystemClock, Target};
#[test]
fn sustained_change_produces_periodic_keyframes() {
let cfg = Config::builder()
.target(Target::ByExe("game.exe".into()))
.settle_ms(100_000) .max_active_ms(150) .fps_cap(0) .build()
.unwrap();
let mut engine = Engine::new(cfg, SystemClock);
let base = base_instant();
let mut settled = 0usize;
let mut frames = 0usize;
for i in 0..20u64 {
let mut buf = solid(10, 10, 10);
let v = (i.wrapping_mul(53) % 240) as u8 + 5;
paint_rect(&mut buf, 20, 20, 280, 140, v, v / 2, 255 - v);
let (f, t) = frame_at(buf, base, i * 50);
frames += 1;
for ev in engine.process(&f, t) {
if ev.kind() == EventKind::Settled {
settled += 1;
}
}
}
assert!(
settled >= 2,
"sustained activity must yield periodic keyframes, got {settled}"
);
assert!(
settled < frames,
"must not capture every frame: {settled} settles vs {frames} frames"
);
}
#[test]
fn sustained_change_without_keyframe_never_settles() {
let cfg = Config::builder()
.target(Target::ByExe("game.exe".into()))
.settle_ms(100_000)
.max_active_ms(0) .fps_cap(0)
.build()
.unwrap();
let mut engine = Engine::new(cfg, SystemClock);
let base = base_instant();
let mut settled = 0usize;
for i in 0..20u64 {
let mut buf = solid(10, 10, 10);
let v = (i.wrapping_mul(53) % 240) as u8 + 5;
paint_rect(&mut buf, 20, 20, 280, 140, v, v / 2, 255 - v);
let (f, t) = frame_at(buf, base, i * 50);
for ev in engine.process(&f, t) {
if ev.kind() == EventKind::Settled {
settled += 1;
}
}
}
assert_eq!(
settled, 0,
"without keyframe, constant change never settles"
);
}
#[test]
fn fps_cap_rate_limits_processing() {
let cfg = Config::builder()
.target(Target::ByExe("game.exe".into()))
.fps_cap(30) .build()
.unwrap();
let mut engine = Engine::new(cfg, SystemClock);
let base = base_instant();
for i in 0..30u64 {
let (f, t) = frame_at(solid(50, 50, 50), base, i * 10);
let _ = engine.process(&f, t);
}
assert!(
engine.frames_dropped() >= 10,
"fps_cap should drop fast frames, dropped {}",
engine.frames_dropped()
);
}