make it sounder

This commit is contained in:
Corwin 2023-04-25 20:34:47 +01:00
parent d45486b189
commit 1eadd5bdf7
No known key found for this signature in database
2 changed files with 67 additions and 55 deletions

View file

@ -9,16 +9,19 @@ use image::GenericImage;
use io::Write;
use regex::Regex;
use runner::VideoBuffer;
use std::cell::Cell;
use std::io;
use std::path::Path;
use std::rc::Rc;
#[derive(PartialEq, Eq, Debug, Clone)]
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
enum Status {
Running,
Failed,
Success,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum Timing {
None,
WaitFor(i32),
@ -28,77 +31,81 @@ enum Timing {
const TEST_RUNNER_TAG: u16 = 785;
fn test_file(file_to_run: &str) -> Status {
let mut finished = Status::Running;
let finished = Rc::new(Cell::new(Status::Running));
let debug_reader_mutex = Regex::new(r"(?s)^\[(.*)\] GBA Debug: (.*)$").unwrap();
let tagged_cycles_reader = Regex::new(r"Cycles: (\d*) Tag: (\d*)").unwrap();
let mut mgba = runner::MGBA::new(file_to_run).unwrap();
let video_buffer = mgba.get_video_buffer();
let mut number_of_cycles = Timing::None;
mgba.set_logger(|message| {
if let Some(captures) = debug_reader_mutex.captures(message) {
let log_level = &captures[1];
let out = &captures[2];
{
let finished = finished.clone();
let video_buffer = mgba.get_video_buffer();
let number_of_cycles = Cell::new(Timing::None);
if out.starts_with("image:") {
let image_path = out.strip_prefix("image:").unwrap();
match check_image_match(image_path, &video_buffer) {
Err(e) => {
println!("[failed]");
println!("{}", e);
finished = Status::Failed;
mgba.set_logger(move |message| {
if let Some(captures) = debug_reader_mutex.captures(message) {
let log_level = &captures[1];
let out = &captures[2];
if out.starts_with("image:") {
let image_path = out.strip_prefix("image:").unwrap();
match check_image_match(image_path, &video_buffer) {
Err(e) => {
println!("[failed]");
println!("{}", e);
finished.set(Status::Failed);
}
Ok(_) => {}
}
Ok(_) => {}
}
} else if out.ends_with("...") {
print!("{}", out);
io::stdout().flush().expect("can't flush stdout");
} else if out.starts_with("Cycles: ") {
if let Some(captures) = tagged_cycles_reader.captures(out) {
let num_cycles: i32 = captures[1].parse().unwrap();
let tag: u16 = captures[2].parse().unwrap();
} else if out.ends_with("...") {
print!("{}", out);
io::stdout().flush().expect("can't flush stdout");
} else if out.starts_with("Cycles: ") {
if let Some(captures) = tagged_cycles_reader.captures(out) {
let num_cycles: i32 = captures[1].parse().unwrap();
let tag: u16 = captures[2].parse().unwrap();
if tag == TEST_RUNNER_TAG {
number_of_cycles = match number_of_cycles {
Timing::WaitFor(n) => Timing::Difference(num_cycles - n),
Timing::None => Timing::WaitFor(num_cycles),
Timing::Difference(_) => Timing::WaitFor(num_cycles),
};
if tag == TEST_RUNNER_TAG {
number_of_cycles.set(match number_of_cycles.get() {
Timing::WaitFor(n) => Timing::Difference(num_cycles - n),
Timing::None => Timing::WaitFor(num_cycles),
Timing::Difference(_) => Timing::WaitFor(num_cycles),
});
}
}
} else if out == "[ok]" {
if let Timing::Difference(cycles) = number_of_cycles.get() {
println!(
"[ok: {} c ≈ {} s]",
cycles,
((cycles as f64 / (16.78 * 1_000_000.0)) * 100.0).round() / 100.0
);
} else {
println!("{}", out);
}
}
} else if out == "[ok]" {
if let Timing::Difference(cycles) = number_of_cycles {
println!(
"[ok: {} c ≈ {} s]",
cycles,
((cycles as f64 / (16.78 * 1_000_000.0)) * 100.0).round() / 100.0
);
} else {
println!("{}", out);
}
} else {
println!("{}", out);
}
if log_level == "FATAL" {
finished = Status::Failed;
}
if log_level == "FATAL" {
finished.set(Status::Failed);
}
if out == "Tests finished successfully" {
finished = Status::Success;
if out == "Tests finished successfully" {
finished.set(Status::Success);
}
}
}
});
});
}
loop {
mgba.advance_frame();
if finished != Status::Running {
if finished.get() != Status::Running {
break;
}
}
return finished;
return finished.get();
}
fn main() -> Result<(), Error> {

View file

@ -3,6 +3,7 @@ use crate::bindings;
use std::ffi::c_void;
use std::ffi::CStr;
use std::ffi::CString;
use std::marker::PhantomData;
use std::os::raw::c_char;
#[allow(
@ -12,8 +13,9 @@ use std::os::raw::c_char;
non_snake_case
)]
pub struct MGBA {
pub struct MGBA<'a> {
mgba: *mut bindings::MGBA,
_phantom: PhantomData<&'a ()>,
}
pub struct VideoBuffer {
@ -34,14 +36,17 @@ impl VideoBuffer {
}
}
impl MGBA {
impl<'a> MGBA<'a> {
pub fn new(filename: &str) -> Result<Self, anyhow::Error> {
let c_str = CString::new(filename).expect("should be able to make cstring from filename");
let mgba = unsafe { bindings::new_runner(c_str.as_ptr() as *mut c_char) };
if mgba.is_null() {
Err(anyhow::anyhow!("could not create core"))
} else {
Ok(MGBA { mgba })
Ok(MGBA {
mgba,
_phantom: PhantomData,
})
}
}
@ -57,7 +62,7 @@ impl MGBA {
pub fn advance_frame(&mut self) {
unsafe { bindings::advance_frame(self.mgba) }
}
pub fn set_logger(&mut self, mut logger: impl FnMut(&str)) {
pub fn set_logger(&mut self, logger: impl Fn(&str) + 'a) {
unsafe {
let callback = generate_c_callback(move |message: *mut c_char| {
logger(
@ -99,7 +104,7 @@ extern "C" fn drop_box<T>(data: *mut c_void) {
}
}
impl Drop for MGBA {
impl Drop for MGBA<'_> {
fn drop(&mut self) {
unsafe { bindings::free_runner(self.mgba) }
}