1+ use environment:: Environment ;
12use errors:: * ;
23use output:: { OutputAssertion , OutputKind } ;
34use std:: default;
@@ -10,6 +11,7 @@ use std::vec::Vec;
1011#[ derive( Debug ) ]
1112pub struct Assert {
1213 cmd : Vec < String > ,
14+ env : Environment ,
1315 current_dir : Option < PathBuf > ,
1416 expect_success : Option < bool > ,
1517 expect_exit_code : Option < i32 > ,
@@ -27,6 +29,7 @@ impl default::Default for Assert {
2729 . into_iter ( )
2830 . map ( String :: from)
2931 . collect ( ) ,
32+ env : Environment :: inherit ( ) ,
3033 current_dir : None ,
3134 expect_success : Some ( true ) ,
3235 expect_exit_code : None ,
@@ -87,6 +90,7 @@ impl Assert {
8790 /// .with_args(&["42"])
8891 /// .stdout().contains("42")
8992 /// .unwrap();
93+ ///
9094 /// ```
9195 pub fn with_args ( mut self , args : & [ & str ] ) -> Self {
9296 self . cmd . extend ( args. into_iter ( ) . cloned ( ) . map ( String :: from) ) ;
@@ -128,6 +132,41 @@ impl Assert {
128132 self
129133 }
130134
135+ /// Sets environments variables for the command.
136+ ///
137+ /// # Examples
138+ ///
139+ /// ```rust
140+ /// extern crate assert_cli;
141+ ///
142+ /// assert_cli::Assert::command(&["printenv"])
143+ /// .with_env(&[("TEST_ENV", "OK")])
144+ /// .stdout().contains("TEST_ENV=OK")
145+ /// .execute()
146+ /// .unwrap();
147+ ///
148+ /// let env = assert_cli::Environment::empty()
149+ /// .insert("FOO", "BAR");
150+ ///
151+ /// assert_cli::Assert::command(&["printenv"])
152+ /// .with_env(&env)
153+ /// .stdout().is("FOO=BAR")
154+ /// .execute()
155+ /// .unwrap();
156+ ///
157+ /// ::std::env::set_var("BAZ", "BAR");
158+ ///
159+ /// assert_cli::Assert::command(&["printenv"])
160+ /// .stdout().contains("BAZ=BAR")
161+ /// .execute()
162+ /// .unwrap();
163+ /// ```
164+ pub fn with_env < E : Into < Environment > > ( mut self , env : E ) -> Self {
165+ self . env = env. into ( ) ;
166+
167+ self
168+ }
169+
131170 /// Small helper to make chains more readable.
132171 ///
133172 /// # Examples
@@ -253,13 +292,17 @@ impl Assert {
253292 /// ```
254293 pub fn execute ( self ) -> Result < ( ) > {
255294 let cmd = & self . cmd [ 0 ] ;
295+
256296 let args: Vec < _ > = self . cmd . iter ( ) . skip ( 1 ) . collect ( ) ;
257297 let mut command = Command :: new ( cmd) ;
258298 let command = command
259299 . stdin ( Stdio :: piped ( ) )
260300 . stdout ( Stdio :: piped ( ) )
261- . stderr ( Stdio :: piped ( ) ) ;
262- let command = command. args ( & args) ;
301+ . stderr ( Stdio :: piped ( ) )
302+ . env_clear ( )
303+ . envs ( self . env . clone ( ) . compile ( ) )
304+ . args ( & args) ;
305+
263306 let command = match self . current_dir {
264307 Some ( ref dir) => command. current_dir ( dir) ,
265308 None => command,
@@ -426,3 +469,168 @@ impl OutputAssertionBuilder {
426469 self . not ( ) . is ( output)
427470 }
428471}
472+
473+ #[ cfg( test) ]
474+ mod test {
475+ use super :: * ;
476+ use std:: ffi:: OsString ;
477+
478+ fn command ( ) -> Assert {
479+ Assert :: command ( & [ "printenv" ] )
480+ }
481+
482+ #[ test]
483+ fn take_ownership ( ) {
484+ let x = Environment :: inherit ( ) ;
485+
486+ command ( ) . with_env ( x. clone ( ) ) . with_env ( & x) . with_env ( x) ;
487+ }
488+
489+ #[ test]
490+ fn in_place_mod ( ) {
491+ let y = Environment :: empty ( ) ;
492+
493+ let y = y. insert ( "key" , "value" ) ;
494+
495+ assert_eq ! (
496+ y. compile( ) ,
497+ vec![ ( OsString :: from( "key" ) , OsString :: from( "value" ) ) ]
498+ ) ;
499+ }
500+
501+ #[ test]
502+ fn in_place_mod2 ( ) {
503+ let x = Environment :: inherit ( ) ;
504+
505+ command ( )
506+ . with_env ( & x. insert ( "key" , "value" ) . insert ( "key" , "vv" ) )
507+ . stdout ( )
508+ . contains ( "key=vv" )
509+ . execute ( )
510+ . unwrap ( ) ;
511+ // Granted, `insert` moved `x`, so we can no longer reference it, even
512+ // though only a reference was passed to `with_env`
513+ }
514+
515+ #[ test]
516+ fn in_place_mod3 ( ) {
517+ // In-place modification while allowing later accesses to the `Environment`
518+ let y = Environment :: empty ( ) ;
519+
520+ assert_eq ! (
521+ y. clone( ) . insert( "key" , "value" ) . compile( ) ,
522+ vec![ ( OsString :: from( "key" ) , OsString :: from( "value" ) ) ]
523+ ) ;
524+
525+ command ( )
526+ . with_env ( y)
527+ . stdout ( )
528+ . not ( )
529+ . contains ( "key=value" )
530+ . execute ( )
531+ . unwrap ( ) ;
532+ }
533+
534+ #[ test]
535+ fn empty_env ( ) {
536+ // In-place modification while allowing later accesses to the `Environment`
537+ let y = Environment :: empty ( ) ;
538+
539+ assert ! ( command( ) . with_env( y) . stdout( ) . is( "" ) . execute( ) . is_ok( ) ) ;
540+ }
541+ #[ test]
542+ fn take_vec ( ) {
543+ let v = vec ! [ ( "bar" . to_string( ) , "baz" . to_string( ) ) ] ;
544+
545+ command ( )
546+ . with_env ( & vec ! [ ( "bar" , "baz" ) ] )
547+ . stdout ( )
548+ . contains ( "bar=baz" )
549+ . execute ( )
550+ . unwrap ( ) ;
551+
552+ command ( )
553+ . with_env ( & v)
554+ . stdout ( )
555+ . contains ( "bar=baz" )
556+ . execute ( )
557+ . unwrap ( ) ;
558+
559+ command ( )
560+ . with_env ( & vec ! [ ( "bar" , "baz" ) ] )
561+ . stdout ( )
562+ . isnt ( "" )
563+ . execute ( )
564+ . unwrap ( ) ;
565+ }
566+
567+ #[ test]
568+ fn take_slice_of_strs ( ) {
569+ command ( )
570+ . with_env ( & [ ( "bar" , "BAZ" ) ] )
571+ . stdout ( )
572+ . contains ( "bar=BAZ" )
573+ . execute ( )
574+ . unwrap ( ) ;
575+
576+ command ( )
577+ . with_env ( & [ ( "bar" , "BAZ" ) ] [ ..] )
578+ . stdout ( )
579+ . contains ( "bar=BAZ" )
580+ . execute ( )
581+ . unwrap ( ) ;
582+
583+ command ( )
584+ . with_env ( [ ( "bar" , "BAZ" ) ] . as_ref ( ) )
585+ . stdout ( )
586+ . contains ( "bar=BAZ" )
587+ . execute ( )
588+ . unwrap ( ) ;
589+ }
590+
591+ #[ test]
592+ fn take_slice_of_strings ( ) {
593+ // same deal as above
594+
595+ command ( )
596+ . with_env ( & [ ( "bar" . to_string ( ) , "BAZ" . to_string ( ) ) ] )
597+ . stdout ( )
598+ . contains ( "bar=BAZ" )
599+ . execute ( )
600+ . unwrap ( ) ;
601+
602+ command ( )
603+ . with_env ( & [ ( "bar" . to_string ( ) , "BAZ" . to_string ( ) ) ] [ ..] )
604+ . stdout ( )
605+ . contains ( "bar=BAZ" )
606+ . execute ( )
607+ . unwrap ( ) ;
608+ }
609+
610+ #[ test]
611+ fn take_slice ( ) {
612+ command ( )
613+ . with_env ( & [ ( "hey" , "ho" ) ] )
614+ . stdout ( )
615+ . contains ( "hey=ho" )
616+ . execute ( )
617+ . unwrap ( ) ;
618+
619+ command ( )
620+ . with_env ( & [ ( "hey" , "ho" . to_string ( ) ) ] )
621+ . stdout ( )
622+ . contains ( "hey=ho" )
623+ . execute ( )
624+ . unwrap ( ) ;
625+ }
626+
627+ #[ test]
628+ fn take_string_i32 ( ) {
629+ command ( )
630+ . with_env ( & [ ( "bar" , 3 as i32 ) ] )
631+ . stdout ( )
632+ . contains ( "bar=3" )
633+ . execute ( )
634+ . unwrap ( ) ;
635+ }
636+ }
0 commit comments