1+ //! `run-make-support` is a support library for run-make tests. It provides command wrappers and
2+ //! convenience utility functions to help test writers reduce duplication. The support library
3+ //! notably is built via cargo: this means that if your test wants some non-trivial utility, such
4+ //! as `object` or `wasmparser`, they can be re-exported and be made available through this library.
5+
16pub mod cc;
27pub mod run;
38pub mod rustc;
@@ -82,7 +87,7 @@ pub fn cygpath_windows<P: AsRef<Path>>(path: P) -> String {
8287 cygpath. arg ( path. as_ref ( ) ) ;
8388 let output = cygpath. output ( ) . unwrap ( ) ;
8489 if !output. status . success ( ) {
85- handle_failed_output ( & format ! ( "{:#?}" , cygpath) , output, caller_line_number) ;
90+ handle_failed_output ( & cygpath, output, caller_line_number) ;
8691 }
8792 let s = String :: from_utf8 ( output. stdout ) . unwrap ( ) ;
8893 // cygpath -w can attach a newline
@@ -98,18 +103,18 @@ pub fn uname() -> String {
98103 let mut uname = Command :: new ( "uname" ) ;
99104 let output = uname. output ( ) . unwrap ( ) ;
100105 if !output. status . success ( ) {
101- handle_failed_output ( & format ! ( "{:#?}" , uname) , output, caller_line_number) ;
106+ handle_failed_output ( & uname, output, caller_line_number) ;
102107 }
103108 String :: from_utf8 ( output. stdout ) . unwrap ( )
104109}
105110
106- fn handle_failed_output ( cmd : & str , output : Output , caller_line_number : u32 ) -> ! {
111+ fn handle_failed_output ( cmd : & Command , output : Output , caller_line_number : u32 ) -> ! {
107112 if output. status . success ( ) {
108- eprintln ! ( "command incorrectly succeeded at line {caller_line_number}" ) ;
113+ eprintln ! ( "command unexpectedly succeeded at line {caller_line_number}" ) ;
109114 } else {
110115 eprintln ! ( "command failed at line {caller_line_number}" ) ;
111116 }
112- eprintln ! ( "{cmd}" ) ;
117+ eprintln ! ( "{cmd:? }" ) ;
113118 eprintln ! ( "output status: `{}`" , output. status) ;
114119 eprintln ! ( "=== STDOUT ===\n {}\n \n " , String :: from_utf8( output. stdout) . unwrap( ) ) ;
115120 eprintln ! ( "=== STDERR ===\n {}\n \n " , String :: from_utf8( output. stderr) . unwrap( ) ) ;
@@ -129,3 +134,127 @@ pub fn set_host_rpath(cmd: &mut Command) {
129134 env:: join_paths ( paths. iter ( ) ) . unwrap ( )
130135 } ) ;
131136}
137+
138+ /// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct
139+ /// containing a `cmd: Command` field. The provided helpers are:
140+ ///
141+ /// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended
142+ /// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add
143+ /// new specific helper methods over relying on these generic argument providers.
144+ /// 2. Environment manipulation methods: `env`, `env_remove` and `env_clear`: these delegate to
145+ /// methods of the same name on [`Command`].
146+ /// 3. Output and execution: `output`, `run` and `run_fail` are provided. `output` waits for the
147+ /// command to finish running and returns the process's [`Output`]. `run` and `run_fail` are
148+ /// higher-level convenience methods which waits for the command to finish running and assert
149+ /// that the command successfully ran or failed as expected. Prefer `run` and `run_fail` when
150+ /// possible.
151+ ///
152+ /// Example usage:
153+ ///
154+ /// ```ignore (illustrative)
155+ /// struct CommandWrapper { cmd: Command }
156+ ///
157+ /// crate::impl_common_helpers!(CommandWrapper);
158+ ///
159+ /// impl CommandWrapper {
160+ /// // ... additional specific helper methods
161+ /// }
162+ /// ```
163+ ///
164+ /// [`Command`]: ::std::process::Command
165+ /// [`Output`]: ::std::process::Output
166+ macro_rules! impl_common_helpers {
167+ ( $wrapper: ident) => {
168+ impl $wrapper {
169+ /// Specify an environment variable.
170+ pub fn env<K , V >( & mut self , key: K , value: V ) -> & mut Self
171+ where
172+ K : AsRef <:: std:: ffi:: OsStr >,
173+ V : AsRef <:: std:: ffi:: OsStr >,
174+ {
175+ self . cmd. env( key, value) ;
176+ self
177+ }
178+
179+ /// Remove an environmental variable.
180+ pub fn env_remove<K >( & mut self , key: K ) -> & mut Self
181+ where
182+ K : AsRef <:: std:: ffi:: OsStr >,
183+ {
184+ self . cmd. env_remove( key) ;
185+ self
186+ }
187+
188+ /// Clear all environmental variables.
189+ pub fn env_var( & mut self ) -> & mut Self {
190+ self . cmd. env_clear( ) ;
191+ self
192+ }
193+
194+ /// Generic command argument provider. Prefer specific helper methods if possible.
195+ /// Note that for some executables, arguments might be platform specific. For C/C++
196+ /// compilers, arguments might be platform *and* compiler specific.
197+ pub fn arg<S >( & mut self , arg: S ) -> & mut Self
198+ where
199+ S : AsRef <:: std:: ffi:: OsStr >,
200+ {
201+ self . cmd. arg( arg) ;
202+ self
203+ }
204+
205+ /// Generic command arguments provider. Prefer specific helper methods if possible.
206+ /// Note that for some executables, arguments might be platform specific. For C/C++
207+ /// compilers, arguments might be platform *and* compiler specific.
208+ pub fn args<S >( & mut self , args: & [ S ] ) -> & mut Self
209+ where
210+ S : AsRef <:: std:: ffi:: OsStr >,
211+ {
212+ self . cmd. args( args) ;
213+ self
214+ }
215+
216+ /// Inspect what the underlying [`Command`][::std::process::Command] is up to the
217+ /// current construction.
218+ pub fn inspect<I >( & mut self , inspector: I ) -> & mut Self
219+ where
220+ I : FnOnce ( & :: std:: process:: Command ) ,
221+ {
222+ inspector( & self . cmd) ;
223+ self
224+ }
225+
226+ /// Get the [`Output`][::std::process::Output] of the finished process.
227+ pub fn output( & mut self ) -> :: std:: process:: Output {
228+ self . cmd. output( ) . expect( "failed to get output of finished process" )
229+ }
230+
231+ /// Run the constructed command and assert that it is successfully run.
232+ #[ track_caller]
233+ pub fn run( & mut self ) -> :: std:: process:: Output {
234+ let caller_location = :: std:: panic:: Location :: caller( ) ;
235+ let caller_line_number = caller_location. line( ) ;
236+
237+ let output = self . cmd. output( ) . unwrap( ) ;
238+ if !output. status. success( ) {
239+ handle_failed_output( & self . cmd, output, caller_line_number) ;
240+ }
241+ output
242+ }
243+
244+ /// Run the constructed command and assert that it does not successfully run.
245+ #[ track_caller]
246+ pub fn run_fail( & mut self ) -> :: std:: process:: Output {
247+ let caller_location = :: std:: panic:: Location :: caller( ) ;
248+ let caller_line_number = caller_location. line( ) ;
249+
250+ let output = self . cmd. output( ) . unwrap( ) ;
251+ if output. status. success( ) {
252+ handle_failed_output( & self . cmd, output, caller_line_number) ;
253+ }
254+ output
255+ }
256+ }
257+ } ;
258+ }
259+
260+ pub ( crate ) use impl_common_helpers;
0 commit comments