1use std::panic::AssertUnwindSafe;
2
3use futures_lite::FutureExt;
4use wgpu::{Adapter, Device, Instance, Queue};
5
6use crate::{
7 expectations::{expectations_match_failures, ExpectationMatchResult, FailureResult},
8 init::{init_logger, initialize_adapter, initialize_device},
9 isolation,
10 params::TestInfo,
11 report::AdapterReport,
12 GpuTestConfiguration,
13};
14
15#[derive(Hash)]
17pub struct TestingContext {
18 pub instance: Instance,
19 pub adapter: Adapter,
20 pub adapter_info: wgpu::AdapterInfo,
21 pub adapter_downlevel_capabilities: wgpu::DownlevelCapabilities,
22 pub device: Device,
23 pub device_features: wgpu::Features,
24 pub device_limits: wgpu::Limits,
25 pub queue: Queue,
26}
27
28pub async fn execute_test(
33 adapter_report: Option<&AdapterReport>,
34 config: GpuTestConfiguration,
35 test_info: Option<TestInfo>,
36) {
37 if let Some(TestInfo { skip: true, .. }) = test_info {
39 return;
40 }
41
42 init_logger();
43
44 let _test_guard = isolation::OneTestPerProcessGuard::new();
45
46 let Some((instance, adapter, _surface_guard)) =
47 initialize_adapter(adapter_report, &config.params).await
48 else {
49 return;
50 };
51
52 let adapter_info = adapter.get_info();
53 let adapter_downlevel_capabilities = adapter.get_downlevel_capabilities();
54
55 let test_info = test_info.unwrap_or_else(|| {
56 let adapter_report = AdapterReport::from_adapter(&adapter);
57 TestInfo::from_configuration(&config, &adapter_report)
58 });
59
60 if test_info.skip {
62 log::info!("TEST RESULT: SKIPPED");
63 return;
64 }
65
66 log::info!("TEST: {}", config.name);
68
69 let (device, queue) = pollster::block_on(initialize_device(
70 &adapter,
71 config.params.required_features,
72 config.params.required_limits.clone(),
73 ));
74
75 let context = TestingContext {
76 instance,
77 adapter,
78 adapter_info,
79 adapter_downlevel_capabilities,
80 device,
81 device_features: config.params.required_features,
82 device_limits: config.params.required_limits.clone(),
83 queue,
84 };
85
86 let mut failures = Vec::new();
87
88 let panic_res = AssertUnwindSafe((config.test.as_ref().unwrap())(context))
90 .catch_unwind()
91 .await;
92
93 if let Err(panic) = panic_res {
94 let message = panic
95 .downcast_ref::<&str>()
96 .copied()
97 .or_else(|| panic.downcast_ref::<String>().map(String::as_str));
98
99 let result = FailureResult::panic();
100
101 let result = if let Some(panic_str) = message {
102 result.with_message(panic_str)
103 } else {
104 result
105 };
106
107 failures.push(result)
108 }
109
110 cfg_if::cfg_if!(
112 if #[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))] {
113 failures.extend(wgpu::hal::VALIDATION_CANARY.get_and_reset().into_iter().map(|msg| FailureResult::validation_error().with_message(msg)));
114 } else if #[cfg(all(target_arch = "wasm32", feature = "webgl"))] {
115 if _surface_guard.unwrap().check_for_unreported_errors() {
116 failures.push(FailureResult::validation_error());
117 }
118 } else {
119 }
120 );
121
122 if expectations_match_failures(&test_info.failures, failures) == ExpectationMatchResult::Panic {
124 panic!(
125 "{}: test {:?} did not behave as expected",
126 config.location, config.name
127 );
128 }
129 log::info!("TEST FINISHED: {}", config.name);
131}