@@ -70,9 +70,11 @@ pub struct TestsArgs {
7070 pub repeat : usize ,
7171 /// Optional test to act on (all tests used if omitted).
7272 ///
73- /// The `test_suite::test_name` syntax allows running a single specific test.
74- #[ arg( long, short = 't' ) ]
75- pub test : Option < String > ,
73+ /// Multiple tests may be selected via a comma-separated list, e.g. `--test rmt,i2c,uart`.
74+ /// The `test_suite::test_name` syntax allows selecting a specific test (and may be combined
75+ /// with commas).
76+ #[ arg( long, short = 't' , alias = "tests" , value_delimiter = ',' , num_args = 1 ..) ]
77+ pub test : Option < Vec < String > > ,
7678
7779 /// The toolchain used to build the tests
7880 #[ arg( long) ]
@@ -212,15 +214,6 @@ pub fn examples(workspace: &Path, mut args: ExamplesArgs, action: CargoAction) -
212214
213215/// Execute the given action on the specified HIL tests.
214216pub fn tests ( workspace : & Path , args : TestsArgs , action : CargoAction ) -> Result < ( ) > {
215- let ( test_arg, filter) = if let Some ( test_arg) = args. test . as_deref ( ) {
216- match test_arg. split_once ( "::" ) {
217- Some ( ( test, filter) ) => ( Some ( test) , Some ( filter) ) ,
218- None => ( Some ( test_arg) , None ) ,
219- }
220- } else {
221- ( None , None )
222- } ;
223-
224217 // Absolute path of the 'hil-test' package's root:
225218 let package_path = crate :: windows_safe_path ( & workspace. join ( "hil-test" ) ) ;
226219
@@ -236,11 +229,6 @@ pub fn tests(workspace: &Path, args: TestsArgs, action: CargoAction) -> Result<(
236229 // Sort all tests by name:
237230 tests. sort_by_key ( |a| a. binary_name ( ) ) ;
238231
239- let run_test_extra_args = ( action == CargoAction :: Run )
240- . then ( || filter. as_ref ( ) . map ( |f| std:: slice:: from_ref ( f) ) )
241- . flatten ( )
242- . unwrap_or ( & [ ] ) ;
243-
244232 if let CargoAction :: Build ( Some ( out_dir) ) = & action {
245233 // Make sure the tmp directory has no garbage for us.
246234 let tmp_dir = out_dir. join ( "tmp" ) ;
@@ -250,26 +238,59 @@ pub fn tests(workspace: &Path, args: TestsArgs, action: CargoAction) -> Result<(
250238
251239 let mut commands = CargoCommandBatcher :: new ( ) ;
252240 // Execute the specified action:
253- if tests. iter ( ) . any ( |test| test. matches ( test_arg. as_deref ( ) ) ) {
254- for test in tests
255- . iter ( )
256- . filter ( |test| test. matches ( test_arg. as_deref ( ) ) )
257- {
258- let command = crate :: generate_build_command (
259- & package_path,
260- args. chip ,
261- & target,
262- & test,
263- action. clone ( ) ,
264- false ,
265- args. toolchain . as_deref ( ) ,
266- args. timings ,
267- run_test_extra_args,
268- ) ?;
269- commands. push ( command) ;
241+ // If user sets some specific test(s)
242+ if let Some ( test_arg) = args. test . as_deref ( ) {
243+ let trimmed: Vec < & str > = test_arg. iter ( ) . map ( |s| s. trim ( ) ) . collect ( ) ;
244+
245+ // Reject `--test ""` / `--test " "`
246+ if trimmed. iter ( ) . all ( |s| s. is_empty ( ) ) {
247+ bail ! ( "Empty test selector is not allowed." ) ;
248+ }
249+
250+ let mut selected_failed: Vec < String > = Vec :: new ( ) ;
251+
252+ for selected in trimmed. into_iter ( ) . filter ( |s| !s. is_empty ( ) ) {
253+ let ( test_arg, filter) = match selected. split_once ( "::" ) {
254+ Some ( ( test, filter) ) => ( Some ( test) , Some ( filter) ) ,
255+ None => ( Some ( selected) , None ) ,
256+ } ;
257+
258+ let run_test_extra_args = ( action == CargoAction :: Run )
259+ . then ( || filter. as_ref ( ) . map ( |f| std:: slice:: from_ref ( f) ) )
260+ . flatten ( )
261+ . unwrap_or ( & [ ] ) ;
262+
263+ let matched: Vec < _ > = tests
264+ . iter ( )
265+ . filter ( |t| t. matches ( test_arg. as_deref ( ) ) )
266+ . collect ( ) ;
267+
268+ if matched. is_empty ( ) {
269+ selected_failed. push ( selected. to_string ( ) ) ;
270+ } else {
271+ for test in matched {
272+ let command = crate :: generate_build_command (
273+ & package_path,
274+ args. chip ,
275+ & target,
276+ test,
277+ action. clone ( ) ,
278+ false ,
279+ args. toolchain . as_deref ( ) ,
280+ args. timings ,
281+ run_test_extra_args,
282+ ) ?;
283+ commands. push ( command) ;
284+ }
285+ }
286+ }
287+
288+ if !selected_failed. is_empty ( ) {
289+ bail ! (
290+ "Test not found or unsupported for the given chip: {}" ,
291+ selected_failed. join( ", " )
292+ )
270293 }
271- } else if test_arg. is_some ( ) {
272- bail ! ( "Test not found or unsupported for the given chip" )
273294 } else {
274295 for test in tests {
275296 let command = crate :: generate_build_command (
@@ -281,11 +302,12 @@ pub fn tests(workspace: &Path, args: TestsArgs, action: CargoAction) -> Result<(
281302 false ,
282303 args. toolchain . as_deref ( ) ,
283304 args. timings ,
284- run_test_extra_args ,
305+ & [ ] ,
285306 ) ?;
286307 commands. push ( command) ;
287308 }
288309 }
310+
289311 let mut failed = Vec :: new ( ) ;
290312
291313 for c in commands. build ( false ) {
0 commit comments