Skip to content

Commit

Permalink
auto-skip tests when event loop or display creation fails
Browse files Browse the repository at this point in the history
  • Loading branch information
SludgePhD committed Aug 14, 2023
1 parent 1b3671c commit d68a454
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 70 deletions.
39 changes: 18 additions & 21 deletions src/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -650,26 +650,23 @@ mod tests {

#[test]
fn image_copy() {
// 1x1 surfaces/images tend to fail with an allocation error, so use a larger size.
const TEST_WIDTH: u32 = 16;
const TEST_HEIGHT: u32 = 16;

let display = test_display();
let mut surface = test_surface(&display);
let mut output_image = Image::new(
&display,
ImageFormat::new(TEST_PIXELFORMAT),
TEST_WIDTH,
TEST_HEIGHT,
)
.expect("failed to create output image");

surface
.copy_to_image(&mut output_image)
.expect("Surface::copy_to_image failed");

surface.sync().unwrap();
let map = output_image.map().expect("failed to map output image");
assert_eq!(&map[..TEST_DATA.len()], TEST_DATA);
run_test(|display| {
let mut surface = test_surface(&display);
let mut output_image = Image::new(
&display,
ImageFormat::new(TEST_PIXELFORMAT),
TEST_WIDTH,
TEST_HEIGHT,
)
.expect("failed to create output image");

surface
.copy_to_image(&mut output_image)
.expect("Surface::copy_to_image failed");

surface.sync().unwrap();
let map = output_image.map().expect("failed to map output image");
assert_eq!(&map[..TEST_DATA.len()], TEST_DATA);
});
}
}
66 changes: 58 additions & 8 deletions src/test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Unit test utilities.
use winit::platform::x11::EventLoopBuilderExtX11;
use std::{any::type_name, panic::catch_unwind, sync::OnceLock};

use winit::{event_loop::EventLoop, platform::x11::EventLoopBuilderExtX11};

use crate::{
display::Display,
Expand All @@ -9,6 +11,15 @@ use crate::{
PixelFormat,
};

struct DisplayHandle {
event_loop: EventLoop<()>,
}

unsafe impl Send for DisplayHandle {}
unsafe impl Sync for DisplayHandle {}

static EVENT_LOOP: OnceLock<anyhow::Result<DisplayHandle>> = OnceLock::new();

pub const TEST_WIDTH: u32 = 16;
pub const TEST_HEIGHT: u32 = 16;
pub const TEST_RTFORMAT: RTFormat = RTFormat::RGB32;
Expand All @@ -20,13 +31,6 @@ pub const TEST_DATA: &[u8] = &[
0xff, 0xff, 0x00, 0x00, // blue
];

pub fn test_display() -> Display {
let ev = winit::event_loop::EventLoopBuilder::new()
.with_any_thread(true)
.build();
Display::new(ev).expect("failed to obtain VA-API display")
}

/// Creates a [`Surface`] and fills its pixels with [`TEST_DATA`].
pub fn test_surface(display: &Display) -> Surface {
let mut surface = Surface::new(&display, TEST_WIDTH, TEST_HEIGHT, TEST_RTFORMAT)
Expand All @@ -51,3 +55,49 @@ pub fn test_surface(display: &Display) -> Surface {

surface
}

pub fn run_test<'a, T: FnOnce(&Display)>(test: T) {
let event_loop = match event_loop() {
Ok(h) => &h.event_loop,
Err(e) => {
log::warn!(
"skipping test '{}' due to error in requirements (event loop): {e}",
type_name::<T>()
);
return;
}
};

let display = match Display::new(event_loop) {
Ok(d) => d,
Err(e) => {
log::warn!(
"skipping test '{}' due to error in requirements (VADisplay): {e}",
type_name::<T>()
);
return;
}
};

test(&display);
}

fn event_loop() -> &'static anyhow::Result<DisplayHandle> {
// Frustratingly, winit seems to have no fallible construction methods for its event loop.
EVENT_LOOP.get_or_init(|| {
catch_unwind(|| {
let ev = winit::event_loop::EventLoopBuilder::new()
.with_any_thread(true)
.build();

DisplayHandle { event_loop: ev }
})
.map_err(|any| {
if let Some(s) = any.downcast_ref::<String>() {
anyhow::anyhow!("{s}")
} else {
anyhow::anyhow!("Box<dyn Any>")
}
})
})
}
82 changes: 41 additions & 41 deletions src/vpp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -665,47 +665,47 @@ mod tests {
#[test]
#[ignore] // FIXME: fails on AMD/Mesa
fn vpp_copy() {
let display = test_display();

// Surface with test data.
let input_surface = test_surface(&display);

let mut output_surface =
Surface::new(&display, TEST_WIDTH, TEST_HEIGHT, TEST_RTFORMAT).unwrap();

let config = Config::new(&display, Profile::None, Entrypoint::VideoProc).unwrap();
let mut context = Context::new(&config, TEST_WIDTH, TEST_HEIGHT).unwrap();

let mut pppbuf = ProcPipelineParameterBuffer::new(&input_surface);
let props = ColorProperties::new().with_color_range(SourceRange::FULL);
pppbuf.set_input_color_properties(props);
pppbuf.set_input_color_standard(ColorStandardType::BT601);
pppbuf.set_output_color_properties(props);
pppbuf.set_output_color_standard(ColorStandardType::SRGB);

let mut params =
Buffer::new_param(&context, BufferType::ProcPipelineParameter, pppbuf).unwrap();

let mut picture = context.begin_picture(&mut output_surface).unwrap();
picture.render_picture(&mut params).unwrap();
unsafe {
picture.end_picture().unwrap();
}
run_test(|display| {
// Surface with test data.
let input_surface = test_surface(&display);

let mut output_surface =
Surface::new(&display, TEST_WIDTH, TEST_HEIGHT, TEST_RTFORMAT).unwrap();

let config = Config::new(&display, Profile::None, Entrypoint::VideoProc).unwrap();
let mut context = Context::new(&config, TEST_WIDTH, TEST_HEIGHT).unwrap();

let mut pppbuf = ProcPipelineParameterBuffer::new(&input_surface);
let props = ColorProperties::new().with_color_range(SourceRange::FULL);
pppbuf.set_input_color_properties(props);
pppbuf.set_input_color_standard(ColorStandardType::BT601);
pppbuf.set_output_color_properties(props);
pppbuf.set_output_color_standard(ColorStandardType::SRGB);

let mut params =
Buffer::new_param(&context, BufferType::ProcPipelineParameter, pppbuf).unwrap();

let mut picture = context.begin_picture(&mut output_surface).unwrap();
picture.render_picture(&mut params).unwrap();
unsafe {
picture.end_picture().unwrap();
}

let mut output_image = Image::new(
&display,
ImageFormat::new(TEST_PIXELFORMAT),
TEST_WIDTH,
TEST_HEIGHT,
)
.expect("failed to create output image");

output_surface.sync().expect("sync failed");
// TODO: the following unwrap fails on AMD/Mesa for seemingly no reason
output_surface.copy_to_image(&mut output_image).unwrap();

output_surface.sync().unwrap();
let map = output_image.map().expect("failed to map output image");
assert_eq!(&map[..TEST_DATA.len()], TEST_DATA);
let mut output_image = Image::new(
&display,
ImageFormat::new(TEST_PIXELFORMAT),
TEST_WIDTH,
TEST_HEIGHT,
)
.expect("failed to create output image");

output_surface.sync().expect("sync failed");
// TODO: the following unwrap fails on AMD/Mesa for seemingly no reason
output_surface.copy_to_image(&mut output_image).unwrap();

output_surface.sync().unwrap();
let map = output_image.map().expect("failed to map output image");
assert_eq!(&map[..TEST_DATA.len()], TEST_DATA);
});
}
}

0 comments on commit d68a454

Please sign in to comment.