1+ #![ feature( if_let_guard) ]
12#![ feature( iter_collect_into) ]
23#![ feature( iter_intersperse) ]
34#![ feature( let_chains) ]
@@ -157,6 +158,22 @@ fn log_test(test_name: &str, result: TestResult, reason: Option<&str>) {
157158 ) ;
158159}
159160
161+ fn parse_directives ( path : & Path ) -> Vec < String > {
162+ let source = fs:: File :: open ( path) . expect ( & format ! ( "cannot open `{}`" , path. display( ) ) ) ;
163+ let mut reader = BufReader :: with_capacity ( 1024 , source) ;
164+
165+ let mut directives = vec ! [ ] ;
166+ let mut line = String :: new ( ) ;
167+ while reader. read_line ( & mut line) . expect ( & format ! ( "cannot read contents of `{}`" , path. display( ) ) ) >= 1 {
168+ if let Some ( directive) = line. trim_start ( ) . strip_prefix ( "//@" ) . map ( str:: trim) {
169+ directives. push ( directive. to_owned ( ) ) ;
170+ }
171+ line. clear ( ) ;
172+ }
173+
174+ directives
175+ }
176+
160177fn run_test ( path : & Path , aux_dir_path : & Path , root_dir : & Path , opts : & Opts , results : & mut TestRunResults ) {
161178 if !path. is_file ( ) { return ; }
162179 if !path. extension ( ) . is_some_and ( |v| v == "rs" ) { return ; }
@@ -192,96 +209,95 @@ fn run_test(path: &Path, aux_dir_path: &Path, root_dir: &Path, opts: &Opts, resu
192209 crate_name = & unmangled_crate_name[ ..unmangled_crate_name. floor_char_boundary( 48 ) ] ,
193210 ) ;
194211
195- let source = fs:: File :: open ( & path) . expect ( & format ! ( "cannot open `{}`" , path. display( ) ) ) ;
196- let mut reader = BufReader :: with_capacity ( 1024 , source) ;
197-
198- let mut directives = vec ! [ ] ;
199- let mut line = String :: new ( ) ;
200- while reader. read_line ( & mut line) . expect ( & format ! ( "cannot read contents of `{}`" , path. display( ) ) ) >= 1 {
201- if let Some ( directive) = line. trim_start ( ) . strip_prefix ( "//@" ) . map ( str:: trim) {
202- directives. push ( directive. to_owned ( ) ) ;
203- }
204- line. clear ( ) ;
205- }
212+ let directives = parse_directives ( & path) ;
206213
207214 if directives. iter ( ) . any ( |d| d == "ignore" ) {
208215 results. ignored_tests_count += 1 ;
209216 log_test ( & name, TestResult :: Ignored , None ) ;
210217 return ;
211218 }
212219
220+ let mut edition: Option < & str > = None ;
213221 let mut expect_command_fail = false ;
214222 let mut expectations = BTreeSet :: new ( ) ;
215223 let mut mutest_prints = BTreeSet :: new ( ) ;
216- let mutest_subcommand = {
217- let mut mutest_subcommand: Option < & str > = None ;
218-
219- for directive in & directives {
220- match directive. as_str ( ) {
221- subcommand @ ( "print-tests" | "print-call-graph" | "print-targets" | "print-mutants" | "print-code" | "build" | "run" ) => {
222- if let Some ( previous_subcommand) = mutest_subcommand && previous_subcommand != "print" {
223- results. ignored_tests_count += 1 ;
224- log_test ( & name, TestResult :: Ignored , Some ( "invalid directives" ) ) ;
225- return ;
226- }
227- match subcommand {
228- "run" => mutest_subcommand = Some ( "build" ) ,
229- "print-tests" => {
230- mutest_prints. insert ( "tests" ) ;
231- mutest_subcommand. get_or_insert ( "print" ) ;
232- }
233- "print-call-graph" => {
234- mutest_prints. insert ( "call-graph" ) ;
235- mutest_subcommand. get_or_insert ( "print" ) ;
236- }
237- "print-targets" => {
238- mutest_prints. insert ( "targets" ) ;
239- mutest_subcommand. get_or_insert ( "print" ) ;
240- }
241- "print-mutants" => {
242- mutest_prints. insert ( "mutants" ) ;
243- mutest_subcommand. get_or_insert ( "print" ) ;
244- }
245- "print-code" => {
246- mutest_prints. insert ( "code" ) ;
247- mutest_subcommand. get_or_insert ( "print" ) ;
248- }
249- subcommand => mutest_subcommand = Some ( subcommand) ,
250- } ;
224+ let mut mutest_subcommand: Option < & str > = None ;
225+ for directive in & directives {
226+ match directive. as_str ( ) {
227+ subcommand @ ( "print-tests" | "print-call-graph" | "print-targets" | "print-mutants" | "print-code" | "build" | "run" ) => {
228+ if let Some ( previous_subcommand) = mutest_subcommand && previous_subcommand != "print" {
229+ results. ignored_tests_count += 1 ;
230+ log_test ( & name, TestResult :: Ignored , Some ( "invalid directives" ) ) ;
231+ return ;
251232 }
252-
253- "fail" => {
254- if let Some ( _previous_subcommand) = mutest_subcommand {
255- results. ignored_tests_count += 1 ;
256- log_test ( & name, TestResult :: Ignored , Some ( "invalid directives" ) ) ;
257- return ;
233+ match subcommand {
234+ "run" => mutest_subcommand = Some ( "build" ) ,
235+ "print-tests" => {
236+ mutest_prints. insert ( "tests" ) ;
237+ mutest_subcommand. get_or_insert ( "print" ) ;
258238 }
259- expect_command_fail = true ;
260- mutest_subcommand = Some ( "build" ) ;
261- }
262-
263- "stdout" => { expectations. insert ( Expectation :: StdOut { empty : false } ) ; }
264- "stdout: empty" => { expectations. insert ( Expectation :: StdOut { empty : true } ) ; }
265- "stderr" => { expectations. insert ( Expectation :: StdErr { empty : false } ) ; }
266- "stderr: empty" => { expectations. insert ( Expectation :: StdErr { empty : true } ) ; }
239+ "print-call-graph" => {
240+ mutest_prints. insert ( "call-graph" ) ;
241+ mutest_subcommand. get_or_insert ( "print" ) ;
242+ }
243+ "print-targets" => {
244+ mutest_prints. insert ( "targets" ) ;
245+ mutest_subcommand. get_or_insert ( "print" ) ;
246+ }
247+ "print-mutants" => {
248+ mutest_prints. insert ( "mutants" ) ;
249+ mutest_subcommand. get_or_insert ( "print" ) ;
250+ }
251+ "print-code" => {
252+ mutest_prints. insert ( "code" ) ;
253+ mutest_subcommand. get_or_insert ( "print" ) ;
254+ }
255+ subcommand => mutest_subcommand = Some ( subcommand) ,
256+ } ;
257+ }
267258
268- _ if directive. starts_with ( "aux-build:" ) => { }
269- _ if directive. starts_with ( "rustc-flags:" ) => { }
270- _ if directive. starts_with ( "verify:" ) => { }
271- _ if directive. starts_with ( "mutation-operators:" ) => { }
272- _ if directive. starts_with ( "mutest-flags:" ) => { }
273- _ if directive. starts_with ( "mutest-subcommand-flags:" ) => { }
259+ "fail" => {
260+ if let Some ( _previous_subcommand) = mutest_subcommand {
261+ results. ignored_tests_count += 1 ;
262+ log_test ( & name, TestResult :: Ignored , Some ( "invalid directives" ) ) ;
263+ return ;
264+ }
265+ expect_command_fail = true ;
266+ mutest_subcommand = Some ( "build" ) ;
267+ }
274268
275- _ => {
269+ _ if let Some ( edition_str) = directive. strip_prefix ( "edition:" ) . map ( str:: trim) => {
270+ if let Some ( _previous_edition) = edition {
276271 results. ignored_tests_count += 1 ;
277- log_test ( & name, TestResult :: Ignored , Some ( & format ! ( "unknown directive: `{directive}`" ) ) ) ;
272+ log_test ( & name, TestResult :: Ignored , Some ( "invalid directives: multiple editions" ) ) ;
278273 return ;
279274 }
275+ edition = Some ( edition_str) ;
276+ }
277+
278+ "stdout" => { expectations. insert ( Expectation :: StdOut { empty : false } ) ; }
279+ "stdout: empty" => { expectations. insert ( Expectation :: StdOut { empty : true } ) ; }
280+ "stderr" => { expectations. insert ( Expectation :: StdErr { empty : false } ) ; }
281+ "stderr: empty" => { expectations. insert ( Expectation :: StdErr { empty : true } ) ; }
282+
283+ _ if directive. starts_with ( "aux-build:" ) => { }
284+ _ if directive. starts_with ( "rustc-flags:" ) => { }
285+ _ if directive. starts_with ( "verify:" ) => { }
286+ _ if directive. starts_with ( "mutation-operators:" ) => { }
287+ _ if directive. starts_with ( "mutest-flags:" ) => { }
288+ _ if directive. starts_with ( "mutest-subcommand-flags:" ) => { }
289+
290+ _ => {
291+ results. ignored_tests_count += 1 ;
292+ log_test ( & name, TestResult :: Ignored , Some ( & format ! ( "unknown directive: `{directive}`" ) ) ) ;
293+ return ;
280294 }
281295 }
296+ }
282297
283- mutest_subcommand. unwrap_or ( "build" )
284- } ;
298+ // Set defaults.
299+ let edition = edition. unwrap_or ( "2018" ) ;
300+ let mutest_subcommand = mutest_subcommand. unwrap_or ( "build" ) ;
285301
286302 // HACK: We invoke mutest-driver directly, rather than through Cargo, which means
287303 // we have to add `windows.lib` to the linker search path manually.
@@ -308,13 +324,38 @@ fn run_test(path: &Path, aux_dir_path: &Path, root_dir: &Path, opts: &Opts, resu
308324 let aux_path = aux_dir_path. join ( aux_build) ;
309325 let aux_crate_name = Path :: new ( aux_build) . file_stem ( ) . expect ( "invalid aux path" ) . to_str ( ) . expect ( "invalid aux path" ) ;
310326
327+ let aux_directives = parse_directives ( & aux_path) ;
328+
329+ let mut edition = None ;
330+ for aux_directive in & aux_directives {
331+ match aux_directive. as_str ( ) {
332+ _ if let Some ( edition_str) = directive. strip_prefix ( "edition:" ) . map ( str:: trim) => {
333+ if let Some ( _previous_edition) = edition {
334+ results. ignored_tests_count += 1 ;
335+ log_test ( & name, TestResult :: Ignored , Some ( "invalid directives: multiple editions" ) ) ;
336+ return ;
337+ }
338+ edition = Some ( edition_str) ;
339+ }
340+
341+ _ => {
342+ results. ignored_tests_count += 1 ;
343+ log_test ( & name, TestResult :: Ignored , Some ( & format ! ( "unknown directive: `{directive}`" ) ) ) ;
344+ return ;
345+ }
346+ }
347+ }
348+
349+ // Set defaults.
350+ let edition = edition. unwrap_or ( "2018" ) ;
351+
311352 let mut cmd = Command :: new ( "target/release/mutest-driver" ) ;
312353 // We need to invoke mutest-driver as a rustc wrapper. This must be the first argument.
313354 cmd. arg ( "/dummy/rustc" ) ;
314355
315356 cmd. arg ( & aux_path) ;
316357 cmd. args ( [ "--crate-name" , aux_crate_name] ) ;
317- cmd. arg ( "--edition=2021" ) ;
358+ cmd. arg ( format ! ( "--edition={edition}" ) ) ;
318359
319360 cmd. args ( [ "--out-dir" , AUX_OUT_DIR ] ) ;
320361
@@ -356,7 +397,7 @@ fn run_test(path: &Path, aux_dir_path: &Path, root_dir: &Path, opts: &Opts, resu
356397
357398 cmd. arg ( & path) ;
358399 cmd. args ( [ "--crate-name" . to_owned ( ) , test_crate_name] ) ;
359- cmd. arg ( "--edition=2021" ) ;
400+ cmd. arg ( format ! ( "--edition={edition}" ) ) ;
360401
361402 cmd. args ( [ "--crate-type" , "lib" ] ) ;
362403
0 commit comments