wgpu_test/
config.rs

1use std::{future::Future, panic::Location, pin::Pin, sync::Arc};
2
3use crate::{TestParameters, TestingContext};
4
5cfg_if::cfg_if! {
6    if #[cfg(target_arch = "wasm32")] {
7        pub type RunTestAsync = Arc<dyn Fn(TestingContext) -> Pin<Box<dyn Future<Output = ()>>>>;
8
9        // We can't use WasmNonSend and WasmNonSync here, as we need these to not require Send/Sync
10        // even with the `fragile-send-sync-non-atomic-wasm` enabled.
11        pub trait RunTestSendSync {}
12        impl<T> RunTestSendSync for T {}
13        pub trait RunTestSend {}
14        impl<T> RunTestSend for T {}
15    } else {
16        pub type RunTestAsync = Arc<dyn Fn(TestingContext) -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync>;
17
18        pub trait RunTestSend: Send {}
19        impl<T> RunTestSend for T where T: Send {}
20        pub trait RunTestSendSync: Send + Sync {}
21        impl<T> RunTestSendSync for T where T: Send + Sync {}
22    }
23}
24
25/// Configuration for a GPU test.
26#[derive(Clone)]
27pub struct GpuTestConfiguration {
28    pub(crate) name: String,
29    pub(crate) location: &'static Location<'static>,
30    pub(crate) params: TestParameters,
31    pub(crate) test: Option<RunTestAsync>,
32}
33
34impl GpuTestConfiguration {
35    #[track_caller]
36    pub fn new() -> Self {
37        Self {
38            name: String::new(),
39            location: Location::caller(),
40            params: TestParameters::default(),
41            test: None,
42        }
43    }
44
45    /// Set the name of the test. Must be unique across all tests in the binary.
46    pub fn name(self, name: &str) -> Self {
47        Self {
48            name: String::from(name),
49            ..self
50        }
51    }
52
53    #[doc(hidden)]
54    /// Derives the name from a `struct S` in the function initializing the test.
55    ///
56    /// Does not overwrite a given name if a name has already been set
57    pub fn name_from_init_function_typename<S>(self, name: &'static str) -> Self {
58        if !self.name.is_empty() {
59            return self;
60        }
61        let type_name = std::any::type_name::<S>();
62
63        // We end up with a string like:
64        //
65        // module::path::we::want::test_name_initializer::S
66        //
67        // So we reverse search for the 4th colon from the end, and take everything before that.
68        let mut colons = 0;
69        let mut colon_4_index = type_name.len();
70        for i in (0..type_name.len()).rev() {
71            if type_name.as_bytes()[i] == b':' {
72                colons += 1;
73            }
74            if colons == 4 {
75                colon_4_index = i;
76                break;
77            }
78        }
79
80        let full = format!("{}::{}", &type_name[..colon_4_index], name);
81        Self { name: full, ..self }
82    }
83
84    /// Set the parameters that the test needs to succeed.
85    pub fn parameters(self, parameters: TestParameters) -> Self {
86        Self {
87            params: parameters,
88            ..self
89        }
90    }
91
92    /// Make the test function an synchronous function.
93    pub fn run_sync(
94        self,
95        test: impl Fn(TestingContext) + Copy + RunTestSendSync + 'static,
96    ) -> Self {
97        Self {
98            test: Some(Arc::new(move |ctx| Box::pin(async move { test(ctx) }))),
99            ..self
100        }
101    }
102
103    /// Make the test function an asynchronous function/future.
104    pub fn run_async<F, R>(self, test: F) -> Self
105    where
106        F: Fn(TestingContext) -> R + RunTestSendSync + 'static,
107        R: Future<Output = ()> + RunTestSend + 'static,
108    {
109        Self {
110            test: Some(Arc::new(move |ctx| Box::pin(test(ctx)))),
111            ..self
112        }
113    }
114}
115
116impl Default for GpuTestConfiguration {
117    fn default() -> Self {
118        Self::new()
119    }
120}
121
122pub type GpuTestInitializer = fn() -> GpuTestConfiguration;