1
+ //! Interface for running the WebGPU CTS (Conformance Test Suite) against wgpu.
2
+ //!
3
+ //! To run the default set of tests from `cts_runner/test.lst`:
4
+ //!
5
+ //! ```sh
6
+ //! cargo xtask cts
7
+ //! ```
8
+ //!
9
+ //! To run a specific test selector:
10
+ //!
11
+ //! ```sh
12
+ //! cargo xtask cts 'webgpu:api,operation,command_buffer,basic:*'
13
+ //! ```
14
+ //!
15
+ //! You can also supply your own test list in a file:
16
+ //!
17
+ //! ```sh
18
+ //! cargo xtask cts -f your_tests.lst
19
+ //! ```
20
+ //!
21
+ //! Each line in a test list file is a test selector that will be passed to the
22
+ //! CTS's own command line runner. Note that wildcards may only be used to specify
23
+ //! running all tests in a file, or all subtests in a test.
24
+ //!
25
+ //! A test line may optionally contain a `fails-if(backend)` clause. This
26
+ //! indicates that the test should be skipped on that backend, however, the
27
+ //! runner will only do so if the `--backend` flag is passed to tell it where
28
+ //! it is running.
29
+ //!
30
+ //! Lines starting with `//` or `#` in the test list are treated as comments and
31
+ //! ignored.
32
+
1
33
use anyhow:: { bail, Context } ;
2
34
use pico_args:: Arguments ;
3
- use std:: ffi:: OsString ;
35
+ use regex_lite:: { Regex , RegexBuilder } ;
36
+ use std:: { ffi:: OsString , sync:: LazyLock } ;
4
37
use xshell:: Shell ;
5
38
6
39
/// Path within the repository where the CTS will be checked out.
@@ -15,16 +48,42 @@ const CTS_GIT_URL: &str = "https://github.com/gpuweb/cts.git";
15
48
/// Path to default CTS test list.
16
49
const CTS_DEFAULT_TEST_LIST : & str = "cts_runner/test.lst" ;
17
50
51
+ static TEST_LINE_REGEX : LazyLock < Regex > = LazyLock :: new ( || {
52
+ RegexBuilder :: new ( r#"(?:fails-if\s*\(\s*(?<fails_if>\w+)\s*\)\s+)?(?<selector>.*)"# )
53
+ . build ( )
54
+ . unwrap ( )
55
+ } ) ;
56
+
57
+ #[ derive( Default ) ]
58
+ struct TestLine {
59
+ pub selector : OsString ,
60
+ pub fails_if : Option < String > ,
61
+ }
62
+
18
63
pub fn run_cts ( shell : Shell , mut args : Arguments ) -> anyhow:: Result < ( ) > {
19
64
let skip_checkout = args. contains ( "--skip-checkout" ) ;
20
65
let llvm_cov = args. contains ( "--llvm-cov" ) ;
66
+ let running_on_backend = args. opt_value_from_str :: < _ , String > ( "--backend" ) ?;
67
+
68
+ if running_on_backend. is_none ( ) {
69
+ log:: warn!(
70
+ "fails-if conditions are only evaluated if a backend is specified with --backend"
71
+ ) ;
72
+ }
21
73
22
74
let mut list_files = Vec :: < OsString > :: new ( ) ;
23
75
while let Some ( file) = args. opt_value_from_str ( "-f" ) ? {
24
76
list_files. push ( file) ;
25
77
}
26
78
27
- let mut tests = args. finish ( ) ;
79
+ let mut tests = args
80
+ . finish ( )
81
+ . into_iter ( )
82
+ . map ( |selector| TestLine {
83
+ selector,
84
+ ..Default :: default ( )
85
+ } )
86
+ . collect :: < Vec < _ > > ( ) ;
28
87
29
88
if tests. is_empty ( ) && list_files. is_empty ( ) {
30
89
log:: info!( "Reading default test list from {CTS_DEFAULT_TEST_LIST}" ) ;
@@ -35,7 +94,13 @@ pub fn run_cts(shell: Shell, mut args: Arguments) -> anyhow::Result<()> {
35
94
tests. extend ( shell. read_file ( file) ?. lines ( ) . filter_map ( |line| {
36
95
let trimmed = line. trim ( ) ;
37
96
let is_comment = trimmed. starts_with ( "//" ) || trimmed. starts_with ( "#" ) ;
38
- ( !trimmed. is_empty ( ) && !is_comment) . then ( || OsString :: from ( trimmed) )
97
+ let captures = TEST_LINE_REGEX
98
+ . captures ( trimmed)
99
+ . expect ( "Invalid test line: {trimmed}" ) ;
100
+ ( !trimmed. is_empty ( ) && !is_comment) . then ( || TestLine {
101
+ selector : OsString :: from ( & captures[ "selector" ] ) ,
102
+ fails_if : captures. name ( "fails_if" ) . map ( |m| m. as_str ( ) . to_string ( ) ) ,
103
+ } )
39
104
} ) )
40
105
}
41
106
@@ -142,15 +207,27 @@ pub fn run_cts(shell: Shell, mut args: Arguments) -> anyhow::Result<()> {
142
207
143
208
log:: info!( "Running CTS" ) ;
144
209
for test in & tests {
145
- log:: info!( "Running {}" , test. to_string_lossy( ) ) ;
210
+ match ( & test. fails_if , & running_on_backend) {
211
+ ( Some ( backend) , Some ( running_on_backend) ) if backend == running_on_backend => {
212
+ log:: info!(
213
+ "Skipping {} on {} backend" ,
214
+ test. selector. to_string_lossy( ) ,
215
+ running_on_backend,
216
+ ) ;
217
+ continue ;
218
+ }
219
+ _ => { }
220
+ }
221
+
222
+ log:: info!( "Running {}" , test. selector. to_string_lossy( ) ) ;
146
223
shell
147
224
. cmd ( "cargo" )
148
225
. args ( run_flags)
149
226
. args ( [ "--manifest-path" . as_ref ( ) , wgpu_cargo_toml. as_os_str ( ) ] )
150
227
. args ( [ "-p" , "cts_runner" ] )
151
228
. args ( [ "--bin" , "cts_runner" ] )
152
229
. args ( [ "--" , "./tools/run_deno" , "--verbose" ] )
153
- . args ( [ test] )
230
+ . args ( [ & test. selector ] )
154
231
. run ( )
155
232
. context ( "CTS failed" ) ?;
156
233
}
0 commit comments