145 lines
4.6 KiB
Rust
145 lines
4.6 KiB
Rust
use std::process::{Command, Stdio};
|
|
use std::sync::{Mutex, OnceLock};
|
|
|
|
use ai_app::ui::fixture::{PHONE_FRAME_MS, PHONE_SCALE, phone_size};
|
|
use iris::harness::{Harness, TouchScript};
|
|
|
|
struct CaptureLogger {
|
|
lines: Mutex<Vec<(log::Level, String)>>,
|
|
}
|
|
|
|
static LOGGER: OnceLock<CaptureLogger> = OnceLock::new();
|
|
|
|
impl log::Log for CaptureLogger {
|
|
fn enabled(&self, _metadata: &log::Metadata) -> bool {
|
|
true
|
|
}
|
|
fn log(&self, record: &log::Record) {
|
|
self.lines
|
|
.lock()
|
|
.unwrap()
|
|
.push((record.level(), record.args().to_string()));
|
|
}
|
|
fn flush(&self) {}
|
|
}
|
|
|
|
fn logger() -> &'static CaptureLogger {
|
|
let logger = LOGGER.get_or_init(|| CaptureLogger {
|
|
lines: Mutex::new(Vec::new()),
|
|
});
|
|
let _ = log::set_logger(logger);
|
|
log::set_max_level(log::LevelFilter::Debug);
|
|
logger
|
|
}
|
|
|
|
fn drain(logger: &CaptureLogger) -> Vec<(log::Level, String)> {
|
|
std::mem::take(&mut *logger.lines.lock().unwrap())
|
|
}
|
|
|
|
fn opened() -> (Harness, ai_app::ui::TranscriptScreen) {
|
|
let mut h = Harness::new(phone_size(), PHONE_SCALE);
|
|
let opened = ai_app::ui::fixture::open(&mut h.rsc, &mut h.state).expect("the fixture folds");
|
|
h.frame(0);
|
|
h.frame(PHONE_FRAME_MS);
|
|
(h, opened.screen)
|
|
}
|
|
|
|
#[test]
|
|
fn tracing_is_silent_off_and_round_trips_the_flick_on() {
|
|
let logger = logger();
|
|
|
|
iris::diagnostics::set_trace(false);
|
|
drain(logger); // whatever `opened()` itself logged while building
|
|
let (mut h, screen) = opened();
|
|
drain(logger); // and whatever opening logged
|
|
let flick = TouchScript::parse(include_str!("../touch/flick-120hz.touch"))
|
|
.unwrap_or_else(|e| panic!("flick-120hz.touch: {e}"));
|
|
h.replay(&flick);
|
|
let _ = (screen.list)(&mut h.rsc); // touch the screen the same way a real caller would
|
|
let quiet = drain(logger);
|
|
let debug_lines: Vec<_> = quiet
|
|
.iter()
|
|
.filter(|(level, _)| *level == log::Level::Debug)
|
|
.collect();
|
|
assert!(
|
|
debug_lines.is_empty(),
|
|
"tracing is off, but the ring would still have held these `debug!` lines: {debug_lines:#?}"
|
|
);
|
|
|
|
iris::diagnostics::set_trace(true);
|
|
let (mut h, screen) = opened();
|
|
drain(logger);
|
|
h.replay(&flick);
|
|
let _ = (screen.list)(&mut h.rsc);
|
|
let traced = drain(logger);
|
|
iris::diagnostics::set_trace(false); // leave it off for any test after this one
|
|
|
|
let input_lines: Vec<&str> = traced
|
|
.iter()
|
|
.filter(|(_, msg)| msg.contains("iris input: action="))
|
|
.map(|(_, msg)| msg.as_str())
|
|
.collect();
|
|
assert_eq!(
|
|
input_lines.len(),
|
|
flick.samples.len(),
|
|
"expected one `iris::input` line per replayed sample, got:\n{input_lines:#?}"
|
|
);
|
|
let frame_lines: Vec<&str> = traced
|
|
.iter()
|
|
.filter(|(_, msg)| msg.starts_with("iris frame:"))
|
|
.map(|(_, msg)| msg.as_str())
|
|
.collect();
|
|
assert!(
|
|
!frame_lines.is_empty(),
|
|
"expected at least one `iris::frame` line once tracing was on"
|
|
);
|
|
for line in &frame_lines {
|
|
assert!(
|
|
!line.contains("layout=0ns"),
|
|
"a frame that redrew should not report zero layout time: {line}"
|
|
);
|
|
}
|
|
|
|
let report = input_lines.join("\n");
|
|
let script_path = concat!(
|
|
env!("CARGO_MANIFEST_DIR"),
|
|
"/../iris/scripts/report_to_touch.py"
|
|
);
|
|
let mut child = Command::new("python3")
|
|
.arg(script_path)
|
|
.stdin(Stdio::piped())
|
|
.stdout(Stdio::piped())
|
|
.stderr(Stdio::piped())
|
|
.spawn()
|
|
.expect("python3 must be on PATH to run report_to_touch.py");
|
|
{
|
|
use std::io::Write;
|
|
child
|
|
.stdin
|
|
.take()
|
|
.unwrap()
|
|
.write_all(report.as_bytes())
|
|
.unwrap();
|
|
}
|
|
let output = child.wait_with_output().expect("report_to_touch.py exited");
|
|
assert!(
|
|
output.status.success(),
|
|
"report_to_touch.py failed: {}",
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
let touch_text = String::from_utf8(output.stdout).expect("report_to_touch.py wrote UTF-8");
|
|
let round_tripped =
|
|
TouchScript::parse(&touch_text).unwrap_or_else(|e| panic!("round-tripped script: {e}"));
|
|
|
|
assert_eq!(
|
|
round_tripped.samples.len(),
|
|
flick.samples.len(),
|
|
"round trip produced a different number of samples:\n{touch_text}"
|
|
);
|
|
for (original, back) in flick.samples.iter().zip(round_tripped.samples.iter()) {
|
|
assert_eq!(original.t_ms, back.t_ms);
|
|
assert_eq!(original.action, back.action);
|
|
assert_eq!(original.pos, back.pos);
|
|
}
|
|
}
|