1#![allow(clippy::arc_with_non_send_sync, reason = "False positive on wasm")]
4
5mod 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};
21pub use expectations::{FailureApplicationReasons, FailureBehavior, FailureCase, FailureReason};
22pub use init::{initialize_adapter, initialize_device, initialize_instance};
23pub use params::TestParameters;
24pub use run::{execute_test, TestingContext};
25pub use wgpu_macros::gpu_test;
26
27pub fn fail<T>(
36 device: &wgpu::Device,
37 callback: impl FnOnce() -> T,
38 expected_msg_substring: Option<&str>,
39) -> T {
40 let scope = device.push_error_scope(wgpu::ErrorFilter::Validation);
41 let result = callback();
42 let validation_error = pollster::block_on(scope.pop())
43 .expect("expected validation error in callback, but no validation error was emitted");
44 if let Some(expected_msg_substring) = expected_msg_substring {
45 let lowered_expected = expected_msg_substring.to_lowercase();
46 let lowered_actual = validation_error.to_string().to_lowercase();
47 assert!(
48 lowered_actual.contains(&lowered_expected),
49 concat!(
50 "expected validation error case-insensitively containing {}, ",
51 "but it was not present in actual error message:\n{}"
52 ),
53 expected_msg_substring,
54 validation_error
55 );
56 }
57
58 result
59}
60
61#[track_caller]
63pub fn valid<T>(device: &wgpu::Device, callback: impl FnOnce() -> T) -> T {
64 let scope = device.push_error_scope(wgpu::ErrorFilter::Validation);
65 let result = callback();
66 if let Some(error) = pollster::block_on(scope.pop()) {
67 panic!(
68 "`valid` block at {} encountered wgpu error:\n{error}",
69 std::panic::Location::caller()
70 );
71 }
72
73 result
74}
75
76pub fn fail_if<T>(
79 device: &wgpu::Device,
80 should_fail: bool,
81 callback: impl FnOnce() -> T,
82 expected_msg_substring: Option<&'static str>,
83) -> T {
84 if should_fail {
85 fail(device, callback, expected_msg_substring)
86 } else {
87 valid(device, callback)
88 }
89}
90
91fn did_fill_error_scope<T>(
92 device: &wgpu::Device,
93 callback: impl FnOnce() -> T,
94 filter: wgpu::ErrorFilter,
95) -> (bool, T) {
96 let scope = device.push_error_scope(filter);
97 let result = callback();
98 let validation_error = pollster::block_on(scope.pop());
99 let failed = validation_error.is_some();
100
101 (failed, result)
102}
103
104pub fn did_fail<T>(device: &wgpu::Device, callback: impl FnOnce() -> T) -> (bool, T) {
106 did_fill_error_scope(device, callback, wgpu::ErrorFilter::Validation)
107}
108
109pub fn did_oom<T>(device: &wgpu::Device, callback: impl FnOnce() -> T) -> (bool, T) {
111 did_fill_error_scope(device, callback, wgpu::ErrorFilter::OutOfMemory)
112}
113
114#[macro_export]
118macro_rules! gpu_test_main {
119 ($tests: expr) => {
120 #[cfg(target_arch = "wasm32")]
121 wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
122 #[cfg(target_arch = "wasm32")]
123 fn main() {
124 let _ = $tests;
126 }
127
128 #[cfg(not(target_arch = "wasm32"))]
129 fn main() -> $crate::native::MainResult {
130 $crate::native::main($tests)
131 }
132 };
133}