1#![allow(clippy::arc_with_non_send_sync)] mod config;
6mod expectations;
7pub mod image;
8mod init;
9mod isolation;
10pub mod native;
11mod params;
12mod poll;
13mod report;
14mod run;
15
16#[cfg(target_arch = "wasm32")]
17pub use init::initialize_html_canvas;
18
19pub use self::image::ComparisonType;
20pub use config::{GpuTestConfiguration, GpuTestInitializer};
21#[doc(hidden)]
22pub use ctor;
23pub use expectations::{FailureApplicationReasons, FailureBehavior, FailureCase, FailureReason};
24pub use init::{initialize_adapter, initialize_device, initialize_instance};
25pub use params::TestParameters;
26pub use run::{execute_test, TestingContext};
27pub use wgpu_macros::gpu_test;
28
29pub fn fail<T>(
38 device: &wgpu::Device,
39 callback: impl FnOnce() -> T,
40 expected_msg_substring: Option<&str>,
41) -> T {
42 device.push_error_scope(wgpu::ErrorFilter::Validation);
43 let result = callback();
44 let validation_error = pollster::block_on(device.pop_error_scope())
45 .expect("expected validation error in callback, but no validation error was emitted");
46 if let Some(expected_msg_substring) = expected_msg_substring {
47 let lowered_expected = expected_msg_substring.to_lowercase();
48 let lowered_actual = validation_error.to_string().to_lowercase();
49 assert!(
50 lowered_actual.contains(&lowered_expected),
51 concat!(
52 "expected validation error case-insensitively containing {}, ",
53 "but it was not present in actual error message:\n{}"
54 ),
55 expected_msg_substring,
56 validation_error
57 );
58 }
59
60 result
61}
62
63#[track_caller]
65pub fn valid<T>(device: &wgpu::Device, callback: impl FnOnce() -> T) -> T {
66 device.push_error_scope(wgpu::ErrorFilter::Validation);
67 let result = callback();
68 if let Some(error) = pollster::block_on(device.pop_error_scope()) {
69 panic!(
70 "`valid` block at {} encountered wgpu error:\n{error}",
71 std::panic::Location::caller()
72 );
73 }
74
75 result
76}
77
78pub fn fail_if<T>(
81 device: &wgpu::Device,
82 should_fail: bool,
83 callback: impl FnOnce() -> T,
84 expected_msg_substring: Option<&'static str>,
85) -> T {
86 if should_fail {
87 fail(device, callback, expected_msg_substring)
88 } else {
89 valid(device, callback)
90 }
91}
92
93fn did_fill_error_scope<T>(
94 device: &wgpu::Device,
95 callback: impl FnOnce() -> T,
96 filter: wgpu::ErrorFilter,
97) -> (bool, T) {
98 device.push_error_scope(filter);
99 let result = callback();
100 let validation_error = pollster::block_on(device.pop_error_scope());
101 let failed = validation_error.is_some();
102
103 (failed, result)
104}
105
106pub fn did_fail<T>(device: &wgpu::Device, callback: impl FnOnce() -> T) -> (bool, T) {
108 did_fill_error_scope(device, callback, wgpu::ErrorFilter::Validation)
109}
110
111pub fn did_oom<T>(device: &wgpu::Device, callback: impl FnOnce() -> T) -> (bool, T) {
113 did_fill_error_scope(device, callback, wgpu::ErrorFilter::OutOfMemory)
114}
115
116#[macro_export]
120macro_rules! gpu_test_main {
121 ($tests: expr) => {
122 #[cfg(target_arch = "wasm32")]
123 wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
124 #[cfg(target_arch = "wasm32")]
125 fn main() {
126 let _ = $tests;
128 }
129
130 #[cfg(not(target_arch = "wasm32"))]
131 fn main() -> $crate::native::MainResult {
132 $crate::native::main($tests)
133 }
134 };
135}