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