mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 16:21:33 +11:00
make it sounder
This commit is contained in:
parent
d45486b189
commit
1eadd5bdf7
|
@ -9,16 +9,19 @@ use image::GenericImage;
|
||||||
use io::Write;
|
use io::Write;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use runner::VideoBuffer;
|
use runner::VideoBuffer;
|
||||||
|
use std::cell::Cell;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||||
enum Status {
|
enum Status {
|
||||||
Running,
|
Running,
|
||||||
Failed,
|
Failed,
|
||||||
Success,
|
Success,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
enum Timing {
|
enum Timing {
|
||||||
None,
|
None,
|
||||||
WaitFor(i32),
|
WaitFor(i32),
|
||||||
|
@ -28,77 +31,81 @@ enum Timing {
|
||||||
const TEST_RUNNER_TAG: u16 = 785;
|
const TEST_RUNNER_TAG: u16 = 785;
|
||||||
|
|
||||||
fn test_file(file_to_run: &str) -> Status {
|
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 debug_reader_mutex = Regex::new(r"(?s)^\[(.*)\] GBA Debug: (.*)$").unwrap();
|
||||||
let tagged_cycles_reader = Regex::new(r"Cycles: (\d*) Tag: (\d*)").unwrap();
|
let tagged_cycles_reader = Regex::new(r"Cycles: (\d*) Tag: (\d*)").unwrap();
|
||||||
|
|
||||||
let mut mgba = runner::MGBA::new(file_to_run).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 finished = finished.clone();
|
||||||
let log_level = &captures[1];
|
let video_buffer = mgba.get_video_buffer();
|
||||||
let out = &captures[2];
|
let number_of_cycles = Cell::new(Timing::None);
|
||||||
|
|
||||||
if out.starts_with("image:") {
|
mgba.set_logger(move |message| {
|
||||||
let image_path = out.strip_prefix("image:").unwrap();
|
if let Some(captures) = debug_reader_mutex.captures(message) {
|
||||||
match check_image_match(image_path, &video_buffer) {
|
let log_level = &captures[1];
|
||||||
Err(e) => {
|
let out = &captures[2];
|
||||||
println!("[failed]");
|
|
||||||
println!("{}", e);
|
if out.starts_with("image:") {
|
||||||
finished = Status::Failed;
|
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);
|
||||||
} else if out.ends_with("...") {
|
io::stdout().flush().expect("can't flush stdout");
|
||||||
print!("{}", out);
|
} else if out.starts_with("Cycles: ") {
|
||||||
io::stdout().flush().expect("can't flush stdout");
|
if let Some(captures) = tagged_cycles_reader.captures(out) {
|
||||||
} else if out.starts_with("Cycles: ") {
|
let num_cycles: i32 = captures[1].parse().unwrap();
|
||||||
if let Some(captures) = tagged_cycles_reader.captures(out) {
|
let tag: u16 = captures[2].parse().unwrap();
|
||||||
let num_cycles: i32 = captures[1].parse().unwrap();
|
|
||||||
let tag: u16 = captures[2].parse().unwrap();
|
|
||||||
|
|
||||||
if tag == TEST_RUNNER_TAG {
|
if tag == TEST_RUNNER_TAG {
|
||||||
number_of_cycles = match number_of_cycles {
|
number_of_cycles.set(match number_of_cycles.get() {
|
||||||
Timing::WaitFor(n) => Timing::Difference(num_cycles - n),
|
Timing::WaitFor(n) => Timing::Difference(num_cycles - n),
|
||||||
Timing::None => Timing::WaitFor(num_cycles),
|
Timing::None => Timing::WaitFor(num_cycles),
|
||||||
Timing::Difference(_) => 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 {
|
} else {
|
||||||
println!("{}", out);
|
println!("{}", out);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
println!("{}", out);
|
|
||||||
}
|
|
||||||
|
|
||||||
if log_level == "FATAL" {
|
if log_level == "FATAL" {
|
||||||
finished = Status::Failed;
|
finished.set(Status::Failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if out == "Tests finished successfully" {
|
if out == "Tests finished successfully" {
|
||||||
finished = Status::Success;
|
finished.set(Status::Success);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
mgba.advance_frame();
|
mgba.advance_frame();
|
||||||
if finished != Status::Running {
|
if finished.get() != Status::Running {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return finished;
|
return finished.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
fn main() -> Result<(), Error> {
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::bindings;
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
#[allow(
|
#[allow(
|
||||||
|
@ -12,8 +13,9 @@ use std::os::raw::c_char;
|
||||||
non_snake_case
|
non_snake_case
|
||||||
)]
|
)]
|
||||||
|
|
||||||
pub struct MGBA {
|
pub struct MGBA<'a> {
|
||||||
mgba: *mut bindings::MGBA,
|
mgba: *mut bindings::MGBA,
|
||||||
|
_phantom: PhantomData<&'a ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VideoBuffer {
|
pub struct VideoBuffer {
|
||||||
|
@ -34,14 +36,17 @@ impl VideoBuffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MGBA {
|
impl<'a> MGBA<'a> {
|
||||||
pub fn new(filename: &str) -> Result<Self, anyhow::Error> {
|
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 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) };
|
let mgba = unsafe { bindings::new_runner(c_str.as_ptr() as *mut c_char) };
|
||||||
if mgba.is_null() {
|
if mgba.is_null() {
|
||||||
Err(anyhow::anyhow!("could not create core"))
|
Err(anyhow::anyhow!("could not create core"))
|
||||||
} else {
|
} else {
|
||||||
Ok(MGBA { mgba })
|
Ok(MGBA {
|
||||||
|
mgba,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +62,7 @@ impl MGBA {
|
||||||
pub fn advance_frame(&mut self) {
|
pub fn advance_frame(&mut self) {
|
||||||
unsafe { bindings::advance_frame(self.mgba) }
|
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 {
|
unsafe {
|
||||||
let callback = generate_c_callback(move |message: *mut c_char| {
|
let callback = generate_c_callback(move |message: *mut c_char| {
|
||||||
logger(
|
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) {
|
fn drop(&mut self) {
|
||||||
unsafe { bindings::free_runner(self.mgba) }
|
unsafe { bindings::free_runner(self.mgba) }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue