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+
133use anyhow:: { bail, Context } ;
234use pico_args:: Arguments ;
3- use std:: ffi:: OsString ;
35+ use regex_lite:: { Regex , RegexBuilder } ;
36+ use std:: { ffi:: OsString , sync:: LazyLock } ;
437use xshell:: Shell ;
538
639/// 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";
1548/// Path to default CTS test list.
1649const CTS_DEFAULT_TEST_LIST : & str = "cts_runner/test.lst" ;
1750
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+
1863pub fn run_cts ( shell : Shell , mut args : Arguments ) -> anyhow:: Result < ( ) > {
1964 let skip_checkout = args. contains ( "--skip-checkout" ) ;
2065 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+ }
2173
2274 let mut list_files = Vec :: < OsString > :: new ( ) ;
2375 while let Some ( file) = args. opt_value_from_str ( "-f" ) ? {
2476 list_files. push ( file) ;
2577 }
2678
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 < _ > > ( ) ;
2887
2988 if tests. is_empty ( ) && list_files. is_empty ( ) {
3089 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<()> {
3594 tests. extend ( shell. read_file ( file) ?. lines ( ) . filter_map ( |line| {
3695 let trimmed = line. trim ( ) ;
3796 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+ } )
39104 } ) )
40105 }
41106
@@ -143,15 +208,27 @@ pub fn run_cts(shell: Shell, mut args: Arguments) -> anyhow::Result<()> {
143208
144209 log:: info!( "Running CTS" ) ;
145210 for test in & tests {
146- log:: info!( "Running {}" , test. to_string_lossy( ) ) ;
211+ match ( & test. fails_if , & running_on_backend) {
212+ ( Some ( backend) , Some ( running_on_backend) ) if backend == running_on_backend => {
213+ log:: info!(
214+ "Skipping {} on {} backend" ,
215+ test. selector. to_string_lossy( ) ,
216+ running_on_backend,
217+ ) ;
218+ continue ;
219+ }
220+ _ => { }
221+ }
222+
223+ log:: info!( "Running {}" , test. selector. to_string_lossy( ) ) ;
147224 shell
148225 . cmd ( "cargo" )
149226 . args ( run_flags)
150227 . args ( [ "--manifest-path" . as_ref ( ) , wgpu_cargo_toml. as_os_str ( ) ] )
151228 . args ( [ "-p" , "cts_runner" ] )
152229 . args ( [ "--bin" , "cts_runner" ] )
153230 . args ( [ "--" , "./tools/run_deno" , "--verbose" ] )
154- . args ( [ test] )
231+ . args ( [ & test. selector ] )
155232 . run ( )
156233 . context ( "CTS failed" ) ?;
157234 }
0 commit comments