@@ -274,40 +274,21 @@ impl ConfigCompileErrorKind {
274274 }
275275}
276276
277- /// An execution error was returned while running a test.
278- ///
279- /// Internal error type.
280- #[ derive( Debug , Error ) ]
281- #[ non_exhaustive]
282- pub ( crate ) enum RunTestError {
283- #[ error( "error spawning test process" ) ]
284- Spawn ( #[ source] std:: io:: Error ) ,
285-
286- #[ error( "errors while managing test process" ) ]
287- Child {
288- /// The errors that occurred; guaranteed to be non-empty.
289- errors : ErrorList < ChildError > ,
290- } ,
291- }
292-
293- /// An error that occurred while setting up or running a setup script.
294- #[ derive( Debug , Error ) ]
295- pub ( crate ) enum SetupScriptError {
296- /// An error occurred while creating a temporary path for the setup script.
277+ /// An execution error occurred while attempting to start a test.
278+ #[ derive( Clone , Debug , Error ) ]
279+ pub enum ChildStartError {
280+ /// An error occurred while creating a temporary path for a setup script.
297281 #[ error( "error creating temporary path for setup script" ) ]
298- TempPath ( #[ source] std:: io:: Error ) ,
299-
300- /// An error occurred while executing the setup script.
301- #[ error( "error executing setup script" ) ]
302- ExecFail ( #[ source] std:: io:: Error ) ,
282+ TempPath ( #[ source] Arc < std:: io:: Error > ) ,
303283
304- /// One or more errors occurred while managing the child process.
305- #[ error( "errors while managing setup script process" ) ]
306- Child {
307- /// The errors that occurred; guaranteed to be non-empty.
308- errors : ErrorList < ChildError > ,
309- } ,
284+ /// An error occurred while spawning the child process.
285+ #[ error( "error spawning child process" ) ]
286+ Spawn ( #[ source] Arc < std:: io:: Error > ) ,
287+ }
310288
289+ /// An error that occurred while reading the output of a setup script.
290+ #[ derive( Clone , Debug , Error ) ]
291+ pub enum SetupScriptOutputError {
311292 /// An error occurred while opening the setup script environment file.
312293 #[ error( "error opening environment file `{path}`" ) ]
313294 EnvFileOpen {
@@ -316,7 +297,7 @@ pub(crate) enum SetupScriptError {
316297
317298 /// The underlying error.
318299 #[ source]
319- error : std:: io:: Error ,
300+ error : Arc < std:: io:: Error > ,
320301 } ,
321302
322303 /// An error occurred while reading the setup script environment file.
@@ -327,42 +308,78 @@ pub(crate) enum SetupScriptError {
327308
328309 /// The underlying error.
329310 #[ source]
330- error : std:: io:: Error ,
311+ error : Arc < std:: io:: Error > ,
331312 } ,
332313
333314 /// An error occurred while parsing the setup script environment file.
334315 #[ error( "line `{line}` in environment file `{path}` not in KEY=VALUE format" ) ]
335- EnvFileParse { path : Utf8PathBuf , line : String } ,
316+ EnvFileParse {
317+ /// The path to the environment file.
318+ path : Utf8PathBuf ,
319+ /// The line at issue.
320+ line : String ,
321+ } ,
336322
337323 /// An environment variable key was reserved.
338324 #[ error( "key `{key}` begins with `NEXTEST`, which is reserved for internal use" ) ]
339- EnvFileReservedKey { key : String } ,
325+ EnvFileReservedKey {
326+ /// The environment variable name.
327+ key : String ,
328+ } ,
340329}
341330
342331/// A list of errors that implements `Error`.
343332///
344333/// In the future, we'll likely want to replace this with a `miette::Diagnostic`-based error, since
345334/// that supports multiple causes via "related".
346335#[ derive( Clone , Debug ) ]
347- pub struct ErrorList < T > ( pub Vec < T > ) ;
336+ pub struct ErrorList < T > {
337+ // A description of what the errors are.
338+ description : & ' static str ,
339+ // Invariant: this list is non-empty.
340+ inner : Vec < T > ,
341+ }
342+
343+ impl < T : std:: error:: Error > ErrorList < T > {
344+ pub ( crate ) fn new < U > ( description : & ' static str , errors : Vec < U > ) -> Option < Self >
345+ where
346+ T : From < U > ,
347+ {
348+ if errors. is_empty ( ) {
349+ None
350+ } else {
351+ Some ( Self {
352+ description,
353+ inner : errors. into_iter ( ) . map ( T :: from) . collect ( ) ,
354+ } )
355+ }
356+ }
348357
349- impl < T > ErrorList < T > {
350- /// Returns true if the error list is empty.
351- pub fn is_empty ( & self ) -> bool {
352- self . 0 . is_empty ( )
358+ /// Returns a 1 line summary of the error list.
359+ pub ( crate ) fn as_one_line_summary ( & self ) -> String {
360+ if self . inner . len ( ) == 1 {
361+ format ! ( "{}" , self . inner[ 0 ] )
362+ } else {
363+ format ! ( "{} errors occurred {}" , self . inner. len( ) , self . description)
364+ }
353365 }
354366}
355367
356368impl < T : std:: error:: Error > fmt:: Display for ErrorList < T > {
357369 fn fmt ( & self , mut f : & mut fmt:: Formatter ) -> fmt:: Result {
358370 // If a single error occurred, pretend that this is just that.
359- if self . 0 . len ( ) == 1 {
360- return write ! ( f, "{}" , self . 0 [ 0 ] ) ;
371+ if self . inner . len ( ) == 1 {
372+ return write ! ( f, "{}" , self . inner [ 0 ] ) ;
361373 }
362374
363375 // Otherwise, list all errors.
364- writeln ! ( f, "{} errors occurred:" , self . 0 . len( ) ) ?;
365- for error in & self . 0 {
376+ writeln ! (
377+ f,
378+ "{} errors occurred {}:" ,
379+ self . inner. len( ) ,
380+ self . description,
381+ ) ?;
382+ for error in & self . inner {
366383 let mut indent = IndentWriter :: new_skip_initial ( " " , f) ;
367384 writeln ! ( indent, "* {}" , DisplayErrorChain ( error) ) ?;
368385 f = indent. into_inner ( ) ;
@@ -373,8 +390,8 @@ impl<T: std::error::Error> fmt::Display for ErrorList<T> {
373390
374391impl < T : std:: error:: Error > std:: error:: Error for ErrorList < T > {
375392 fn source ( & self ) -> Option < & ( dyn std:: error:: Error + ' static ) > {
376- if self . 0 . len ( ) == 1 {
377- self . 0 [ 0 ] . source ( )
393+ if self . inner . len ( ) == 1 {
394+ self . inner [ 0 ] . source ( )
378395 } else {
379396 // More than one error occurred, so we can't return a single error here. Instead, we
380397 // return `None` and display the chain of causes in `fmt::Display`.
@@ -421,10 +438,21 @@ where
421438 }
422439}
423440
424- /// An error was returned during the process of managing a child process.
441+ /// An error was returned while managing a child process or reading its output .
425442#[ derive( Clone , Debug , Error ) ]
426- #[ non_exhaustive]
427443pub enum ChildError {
444+ /// An error occurred while reading from a child file descriptor.
445+ #[ error( transparent) ]
446+ Fd ( #[ from] ChildFdError ) ,
447+
448+ /// An error occurred while reading the output of a setup script.
449+ #[ error( transparent) ]
450+ SetupScriptOutput ( #[ from] SetupScriptOutputError ) ,
451+ }
452+
453+ /// An error was returned while reading from child a file descriptor.
454+ #[ derive( Clone , Debug , Error ) ]
455+ pub enum ChildFdError {
428456 /// An error occurred while reading standard output.
429457 #[ error( "error reading standard output" ) ]
430458 ReadStdout ( #[ source] Arc < std:: io:: Error > ) ,
@@ -1822,14 +1850,18 @@ mod tests {
18221850 fn display_error_list ( ) {
18231851 let err1 = StringError :: new ( "err1" , None ) ;
18241852
1825- let error_list = ErrorList ( vec ! [ err1. clone( ) ] ) ;
1853+ let error_list =
1854+ ErrorList :: < StringError > :: new ( "waiting on the water to boil" , vec ! [ err1. clone( ) ] )
1855+ . expect ( ">= 1 error" ) ;
18261856 insta:: assert_snapshot!( format!( "{}" , error_list) , @"err1" ) ;
18271857 insta:: assert_snapshot!( format!( "{}" , DisplayErrorChain :: new( & error_list) ) , @"err1" ) ;
18281858
18291859 let err2 = StringError :: new ( "err2" , Some ( err1) ) ;
18301860 let err3 = StringError :: new ( "err3" , Some ( err2) ) ;
18311861
1832- let error_list = ErrorList ( vec ! [ err3. clone( ) ] ) ;
1862+ let error_list =
1863+ ErrorList :: < StringError > :: new ( "waiting on flowers to bloom" , vec ! [ err3. clone( ) ] )
1864+ . expect ( ">= 1 error" ) ;
18331865 insta:: assert_snapshot!( format!( "{}" , error_list) , @"err3" ) ;
18341866 insta:: assert_snapshot!( format!( "{}" , DisplayErrorChain :: new( & error_list) ) , @r"
18351867 err3
@@ -1842,10 +1874,14 @@ mod tests {
18421874 let err5 = StringError :: new ( "err5" , Some ( err4) ) ;
18431875 let err6 = StringError :: new ( "err6\n err6 line 2" , Some ( err5) ) ;
18441876
1845- let error_list = ErrorList ( vec ! [ err3, err6] ) ;
1877+ let error_list = ErrorList :: < StringError > :: new (
1878+ "waiting for the heat death of the universe" ,
1879+ vec ! [ err3, err6] ,
1880+ )
1881+ . expect ( ">= 1 error" ) ;
18461882
18471883 insta:: assert_snapshot!( format!( "{}" , error_list) , @r"
1848- 2 errors occurred:
1884+ 2 errors occurred waiting for the heat death of the universe :
18491885 * err3
18501886 caused by:
18511887 - err2
@@ -1857,7 +1893,7 @@ mod tests {
18571893 - err4
18581894 " ) ;
18591895 insta:: assert_snapshot!( format!( "{}" , DisplayErrorChain :: new( & error_list) ) , @r"
1860- 2 errors occurred:
1896+ 2 errors occurred waiting for the heat death of the universe :
18611897 * err3
18621898 caused by:
18631899 - err2
0 commit comments