added "manual" integration tests for basic system/window verification
since i cannot think of any way to verify these tests in a automated way, these are all set up currently as "ignored" tests which need to be manually run (either directly via the IDE, e.g. CLion as I use, or via the an ALTERNATIVE test runner via the CLI (such as nextest). these cannot be run all together via `cargo test` (even if running with only a single thread). `cargo test` can only be used to run them successfully one test per invocation.
This commit is contained in:
parent
9a421f32a6
commit
fbf6d1e716
94
ggdt/tests/manual/keyboard.rs
Normal file
94
ggdt/tests/manual/keyboard.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
use crate::BACKGROUND_COLOR;
|
||||
use ggdt::prelude::*;
|
||||
|
||||
fn display_raw_keyboard_state(system: &mut System<Standard>, x: i32, y: i32) {
|
||||
let font_opts = FontRenderOpts::Color(0xffffffff);
|
||||
let font = &system.res.font;
|
||||
|
||||
system.res.video.print_string("Raw Keyboard State", x, x, font_opts, font);
|
||||
|
||||
let mut idx = 0;
|
||||
for yc in 0..16 {
|
||||
for xc in 0..32 {
|
||||
let state = if let Some(scancode) = num::FromPrimitive::from_u32(idx) {
|
||||
system.res.keyboard.is_key_down(scancode)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
system.res.video.print_char(
|
||||
if state { '1' } else { '0' },
|
||||
x + (xc * 8),
|
||||
y + 10 + (yc * 8),
|
||||
font_opts,
|
||||
font,
|
||||
);
|
||||
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn display_key_state(key: Scancode, system: &mut System<Standard>, x: i32, y: i32) {
|
||||
system.res.video.print_string(
|
||||
&format!(
|
||||
"{:?} - {} {} {} {}",
|
||||
key,
|
||||
system.res.keyboard.is_key_down(key) as i32,
|
||||
system.res.keyboard.is_key_up(key) as i32,
|
||||
system.res.keyboard.is_key_pressed(key) as i32,
|
||||
system.res.keyboard.is_key_released(key) as i32,
|
||||
),
|
||||
x,
|
||||
y,
|
||||
FontRenderOpts::Color(0xffffffff),
|
||||
&system.res.font,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn keyboard_state() {
|
||||
let config = StandardConfig::variable_screen_size(640, 480).scale_factor(2);
|
||||
let mut system = SystemBuilder::new()
|
||||
.window_title("Keyboard State") //
|
||||
.vsync(true)
|
||||
.build(config)
|
||||
.unwrap();
|
||||
|
||||
while !system.do_events().unwrap() {
|
||||
if system.res.keyboard.is_key_pressed(Scancode::Escape) {
|
||||
break;
|
||||
}
|
||||
|
||||
system.res.video.clear(BACKGROUND_COLOR);
|
||||
|
||||
system.update().unwrap();
|
||||
|
||||
display_raw_keyboard_state(&mut system, 2, 2);
|
||||
|
||||
for (idx, key) in [
|
||||
Scancode::A,
|
||||
Scancode::LCtrl,
|
||||
Scancode::RCtrl,
|
||||
Scancode::LAlt,
|
||||
Scancode::RAlt,
|
||||
Scancode::LShift,
|
||||
Scancode::RShift,
|
||||
Scancode::Return,
|
||||
Scancode::KpEnter,
|
||||
Scancode::Up,
|
||||
Scancode::Down,
|
||||
Scancode::Left,
|
||||
Scancode::Right,
|
||||
]
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
display_key_state(*key, &mut system, 2, 160 + (idx as i32 * 10));
|
||||
}
|
||||
|
||||
system.res.video.set_pixel(system.res.mouse.x(), system.res.mouse.y(), to_rgb32(255, 0, 255));
|
||||
|
||||
system.display().unwrap();
|
||||
}
|
||||
}
|
53
ggdt/tests/manual/main.rs
Normal file
53
ggdt/tests/manual/main.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
//! These are tests that need to be manually run and interacted with by the user in order to verify functionality.
|
||||
//! This is specifically for integration-style testing which is testing things like windowing, system events, input
|
||||
//! devices, etc that are more difficult to test in a purely automated way.
|
||||
//!
|
||||
//! TODO: Is there a better way to do this, rather than marking all of these tests as ignored? We don't want them to
|
||||
//! run during any automatic CI step, etc, as those should always run without manual user intervention midway.
|
||||
//!
|
||||
//! HACK: It is not currenly possible to run all of these together via cargo CLI, using something like
|
||||
//! `cargo test -- --test-threads=1 --ignored`. Even restricting to 1 thread like this will fail. This appears
|
||||
//! to be due to a bug in rust-sdl2 where `sdl2::sdl::IS_MAIN_THREAD_DECLARED` is never reset to false after
|
||||
//! `SDL_Quit` is finally called (which only can happen when all subsystems are dropped). Attempting to restart
|
||||
//! SDL even after a supposedly clean shutdown will always result in the error
|
||||
//! "Cannot initialize `Sdl` from more than once thread."
|
||||
//! However, you can run them via an alternative test runner like nextest (https://nexte.st/).
|
||||
//! e.g.`cargo nextest run -j 1 --run-ignored ignored-only`
|
||||
|
||||
mod keyboard;
|
||||
mod mouse;
|
||||
mod system_events;
|
||||
mod system_resources_doslike;
|
||||
mod system_resources_standard;
|
||||
|
||||
use ggdt::prelude::*;
|
||||
|
||||
const BACKGROUND_COLOR: u32 = 0xff2c3041;
|
||||
|
||||
fn draw_base_screen<BitmapType>(
|
||||
dest: &mut BitmapType,
|
||||
bg_color_1: BitmapType::PixelType,
|
||||
bg_color_2: BitmapType::PixelType,
|
||||
color: BitmapType::PixelType,
|
||||
highlight_color: BitmapType::PixelType,
|
||||
) where
|
||||
BitmapType: GeneralBitmap,
|
||||
{
|
||||
for y in 0..dest.height() as i32 {
|
||||
dest.horiz_line(0, dest.right() as i32, y, if y % 2 == 0 { bg_color_1 } else { bg_color_2 });
|
||||
}
|
||||
|
||||
dest.horiz_line(0, 16, 0, color);
|
||||
dest.horiz_line(0, 16, dest.bottom() as i32, color);
|
||||
dest.horiz_line(dest.right() as i32 - 16, dest.right() as i32, 0, color);
|
||||
dest.horiz_line(dest.right() as i32 - 16, dest.right() as i32, dest.bottom() as i32, color);
|
||||
dest.vert_line(0, 0, 16, color);
|
||||
dest.vert_line(dest.right() as i32, 0, 16, color);
|
||||
dest.vert_line(0, dest.bottom() as i32 - 16, dest.bottom() as i32, color);
|
||||
dest.vert_line(dest.right() as i32, dest.bottom() as i32 - 16, dest.bottom() as i32, color);
|
||||
|
||||
dest.set_pixel(0, 0, highlight_color);
|
||||
dest.set_pixel(0, dest.bottom() as i32, highlight_color);
|
||||
dest.set_pixel(dest.right() as i32, 0, highlight_color);
|
||||
dest.set_pixel(dest.right() as i32, dest.bottom() as i32, highlight_color);
|
||||
}
|
98
ggdt/tests/manual/mouse.rs
Normal file
98
ggdt/tests/manual/mouse.rs
Normal file
|
@ -0,0 +1,98 @@
|
|||
use crate::BACKGROUND_COLOR;
|
||||
use ggdt::prelude::*;
|
||||
|
||||
fn display_mouse_state(system: &mut System<Standard>) {
|
||||
let font = &system.res.font;
|
||||
let font_opts = FontRenderOpts::Color(0xffffffff);
|
||||
|
||||
system.res.video.print_string(
|
||||
&format!(
|
||||
"X: {:4} (delta: {:4})\nY: {:4} (delta: {:4})",
|
||||
system.res.mouse.x(),
|
||||
system.res.mouse.x_delta(),
|
||||
system.res.mouse.y(),
|
||||
system.res.mouse.y_delta(),
|
||||
),
|
||||
10,
|
||||
10,
|
||||
font_opts,
|
||||
font,
|
||||
);
|
||||
|
||||
system.res.video.print_string("Buttons - down/up/pressed/released", 10, 40, font_opts, font);
|
||||
use MouseButton::*;
|
||||
for (idx, button) in [Left, Middle, Right, X1, X2].iter().enumerate() {
|
||||
system.res.video.print_string(
|
||||
&format!(
|
||||
"{:?} - {} {} {} {}",
|
||||
button,
|
||||
system.res.mouse.is_button_down(*button) as i32,
|
||||
system.res.mouse.is_button_up(*button) as i32,
|
||||
system.res.mouse.is_button_pressed(*button) as i32,
|
||||
system.res.mouse.is_button_released(*button) as i32,
|
||||
),
|
||||
10,
|
||||
50 + (idx as i32 * 8),
|
||||
font_opts,
|
||||
font,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // should be manually run
|
||||
fn mouse_with_custom_cursor() {
|
||||
let config = StandardConfig::variable_screen_size(320, 240).scale_factor(4);
|
||||
let mut system = SystemBuilder::new()
|
||||
.window_title("Mouse Input, using a Custom Bitmap Cursor")
|
||||
.vsync(true)
|
||||
.show_mouse(false)
|
||||
.build(config)
|
||||
.unwrap();
|
||||
|
||||
system.res.cursor.enable_cursor(true);
|
||||
|
||||
while !system.do_events().unwrap() {
|
||||
if system.res.keyboard.is_key_pressed(Scancode::Escape) {
|
||||
break;
|
||||
}
|
||||
|
||||
system.res.video.clear(BACKGROUND_COLOR);
|
||||
|
||||
system.update().unwrap();
|
||||
|
||||
display_mouse_state(&mut system);
|
||||
system.res.video.set_pixel(system.res.mouse.x(), system.res.mouse.y(), to_rgb32(255, 0, 255));
|
||||
|
||||
system.display().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // should be manually run
|
||||
fn mouse_with_os_cursor() {
|
||||
let config = StandardConfig::variable_screen_size(320, 240).scale_factor(4);
|
||||
let mut system = SystemBuilder::new()
|
||||
.window_title("Mouse Input, using the OS's Native Cursor")
|
||||
.vsync(true)
|
||||
.show_mouse(true)
|
||||
.build(config)
|
||||
.unwrap();
|
||||
|
||||
system.res.cursor.enable_cursor(false);
|
||||
|
||||
while !system.do_events().unwrap() {
|
||||
if system.res.keyboard.is_key_pressed(Scancode::Escape) {
|
||||
break;
|
||||
}
|
||||
|
||||
system.res.video.clear(BACKGROUND_COLOR);
|
||||
|
||||
system.update().unwrap();
|
||||
|
||||
display_mouse_state(&mut system);
|
||||
system.res.video.set_pixel(system.res.mouse.x(), system.res.mouse.y(), to_rgb32(255, 0, 255));
|
||||
|
||||
system.display().unwrap();
|
||||
}
|
||||
}
|
50
ggdt/tests/manual/system_events.rs
Normal file
50
ggdt/tests/manual/system_events.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
use crate::BACKGROUND_COLOR;
|
||||
use ggdt::prelude::*;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[test]
|
||||
#[ignore] // should be manually run
|
||||
fn system_events_display() {
|
||||
let config = StandardConfig::variable_screen_size(640, 480).scale_factor(2);
|
||||
let mut system = SystemBuilder::new()
|
||||
.window_title("Displaying all SystemEvents")
|
||||
.vsync(true)
|
||||
.show_mouse(true)
|
||||
.build(config)
|
||||
.unwrap();
|
||||
|
||||
let mut recent_events = VecDeque::new();
|
||||
|
||||
'mainloop: loop {
|
||||
while recent_events.len() > (system.res.video.height() as usize / system.res.font.line_height() as usize) {
|
||||
recent_events.pop_back();
|
||||
}
|
||||
system.res.update_event_state().unwrap();
|
||||
for event in system.event_pump.poll_iter() {
|
||||
system.res.handle_event(&event).unwrap();
|
||||
recent_events.push_front(event.clone());
|
||||
if event == SystemEvent::Quit {
|
||||
break 'mainloop;
|
||||
}
|
||||
}
|
||||
system.update().unwrap();
|
||||
|
||||
if system.res.keyboard.is_key_pressed(Scancode::Escape) {
|
||||
break 'mainloop;
|
||||
}
|
||||
|
||||
system.res.video.clear(BACKGROUND_COLOR);
|
||||
|
||||
for (idx, event) in recent_events.iter().enumerate() {
|
||||
system.res.video.print_string(
|
||||
&format!("{:?}", event),
|
||||
2,
|
||||
system.res.video.height() as i32 - 10 - (idx as i32 * 10),
|
||||
FontRenderOpts::Color(to_rgb32(255, 255, 255)),
|
||||
&system.res.font,
|
||||
);
|
||||
}
|
||||
|
||||
system.display().unwrap();
|
||||
}
|
||||
}
|
75
ggdt/tests/manual/system_resources_doslike.rs
Normal file
75
ggdt/tests/manual/system_resources_doslike.rs
Normal file
|
@ -0,0 +1,75 @@
|
|||
use crate::draw_base_screen;
|
||||
use ggdt::prelude::*;
|
||||
|
||||
fn draw_state(system: &mut System<DosLike>) {
|
||||
system.res.video.print_string(
|
||||
&format!(
|
||||
"{}x{} (DosLike)\n\n{:3}, {:3}",
|
||||
system.res.video.width(),
|
||||
system.res.video.height(),
|
||||
system.res.mouse.x(),
|
||||
system.res.mouse.y()
|
||||
),
|
||||
10,
|
||||
10,
|
||||
FontRenderOpts::Color(15),
|
||||
&system.res.font,
|
||||
);
|
||||
}
|
||||
|
||||
fn simple_main_loop(mut system: System<DosLike>) {
|
||||
while !system.do_events().unwrap() {
|
||||
if system.res.keyboard.is_key_pressed(Scancode::Escape) {
|
||||
break;
|
||||
}
|
||||
|
||||
system.update().unwrap();
|
||||
|
||||
draw_base_screen(&mut system.res.video, 18, 19, 15, 12);
|
||||
draw_state(&mut system);
|
||||
|
||||
system.display().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn fixed_screen_size_integer_scaling() {
|
||||
let config = DosLikeConfig::fixed_screen_size(320, 240, true).scale_factor(3);
|
||||
let mut system = SystemBuilder::new()
|
||||
.window_title("Fixed Screen Size with Integer Scaling (DosLike)")
|
||||
.vsync(true)
|
||||
.show_mouse(false)
|
||||
.build(config)
|
||||
.unwrap();
|
||||
system.res.cursor.enable_cursor(true);
|
||||
simple_main_loop(system);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn fixed_screen_size_variable_scaling() {
|
||||
let config = DosLikeConfig::fixed_screen_size(320, 240, false).scale_factor(3);
|
||||
let mut system = SystemBuilder::new()
|
||||
.window_title("Fixed Screen Size with Variable Scaling (DosLike)")
|
||||
.vsync(true)
|
||||
.show_mouse(false)
|
||||
.build(config)
|
||||
.unwrap();
|
||||
system.res.cursor.enable_cursor(true);
|
||||
simple_main_loop(system);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn variable_screen_size_fixed_scale_factor() {
|
||||
let config = DosLikeConfig::variable_screen_size(320, 240).scale_factor(3);
|
||||
let mut system = SystemBuilder::new()
|
||||
.window_title("Variable Screen Size with Fixed Scale Factor (DosLike)")
|
||||
.vsync(true)
|
||||
.show_mouse(false)
|
||||
.build(config)
|
||||
.unwrap();
|
||||
system.res.cursor.enable_cursor(true);
|
||||
simple_main_loop(system);
|
||||
}
|
81
ggdt/tests/manual/system_resources_standard.rs
Normal file
81
ggdt/tests/manual/system_resources_standard.rs
Normal file
|
@ -0,0 +1,81 @@
|
|||
use crate::draw_base_screen;
|
||||
use ggdt::prelude::*;
|
||||
|
||||
fn draw_state(system: &mut System<Standard>) {
|
||||
system.res.video.print_string(
|
||||
&format!(
|
||||
"{}x{} (Standard)\n\n{:3}, {:3}",
|
||||
system.res.video.width(),
|
||||
system.res.video.height(),
|
||||
system.res.mouse.x(),
|
||||
system.res.mouse.y()
|
||||
),
|
||||
10,
|
||||
10,
|
||||
FontRenderOpts::Color(COLOR_BRIGHT_WHITE),
|
||||
&system.res.font,
|
||||
);
|
||||
}
|
||||
|
||||
fn simple_main_loop(mut system: System<Standard>) {
|
||||
while !system.do_events().unwrap() {
|
||||
if system.res.keyboard.is_key_pressed(Scancode::Escape) {
|
||||
break;
|
||||
}
|
||||
|
||||
system.update().unwrap();
|
||||
|
||||
draw_base_screen(
|
||||
&mut system.res.video,
|
||||
to_rgb32(32, 32, 32),
|
||||
to_rgb32(44, 44, 44),
|
||||
COLOR_BRIGHT_WHITE,
|
||||
COLOR_BRIGHT_RED,
|
||||
);
|
||||
draw_state(&mut system);
|
||||
|
||||
system.display().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn fixed_screen_size_integer_scaling() {
|
||||
let config = StandardConfig::fixed_screen_size(320, 240, true).scale_factor(3);
|
||||
let mut system = SystemBuilder::new()
|
||||
.window_title("Fixed Screen Size with Integer Scaling (Standard)")
|
||||
.vsync(true)
|
||||
.show_mouse(false)
|
||||
.build(config)
|
||||
.unwrap();
|
||||
system.res.cursor.enable_cursor(true);
|
||||
simple_main_loop(system);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn fixed_screen_size_variable_scaling() {
|
||||
let config = StandardConfig::fixed_screen_size(320, 240, false).scale_factor(3);
|
||||
let mut system = SystemBuilder::new()
|
||||
.window_title("Fixed Screen Size with Variable Scaling (Standard)")
|
||||
.vsync(true)
|
||||
.show_mouse(false)
|
||||
.build(config)
|
||||
.unwrap();
|
||||
system.res.cursor.enable_cursor(true);
|
||||
simple_main_loop(system);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn variable_screen_size_fixed_scale_factor() {
|
||||
let config = StandardConfig::variable_screen_size(320, 240).scale_factor(3);
|
||||
let mut system = SystemBuilder::new()
|
||||
.window_title("Variable Screen Size with Fixed Scale Factor (Standard)")
|
||||
.vsync(true)
|
||||
.show_mouse(false)
|
||||
.build(config)
|
||||
.unwrap();
|
||||
system.res.cursor.enable_cursor(true);
|
||||
simple_main_loop(system);
|
||||
}
|
Loading…
Reference in a new issue