@@ -416,13 +416,13 @@ mod env {
416416/// Construct a fake process executor for testing:
417417/// ```rust
418418/// use aws_types::os_shim_internal::{Process, CommandOutput, ExitStatus};
419- /// let process = Process::from_fn(|_cmd| {
420- /// Ok( CommandOutput {
419+ /// let process = Process::from_slice(&[
420+ /// ("echo hello", CommandOutput {
421421/// status: ExitStatus::new(Some(0)),
422422/// stdout: b"hello".to_vec(),
423423/// stderr: Vec::new(),
424- /// })
425- /// } );
424+ /// }),
425+ /// ] );
426426/// ```
427427#[ derive( Clone , Debug ) ]
428428pub struct Process ( process:: Inner ) ;
@@ -451,23 +451,28 @@ impl Process {
451451 Self ( process:: Inner :: Custom ( Arc :: new ( provider) ) )
452452 }
453453
454- /// Create a `Process` from a function that maps command strings to outputs.
454+ /// Create a fake `Process` from a slice of `(command, result)` pairs.
455+ ///
456+ /// When `execute` is called, the command string is looked up in the map.
457+ /// If not found, an `io::ErrorKind::NotFound` error is returned.
455458 ///
456459 /// # Examples
457460 /// ```rust
458461 /// use aws_types::os_shim_internal::{Process, CommandOutput, ExitStatus};
459- /// let process = Process::from_fn(|cmd| {
460- /// Ok( CommandOutput {
462+ /// let process = Process::from_slice(&[
463+ /// ("echo hello", CommandOutput {
461464 /// status: ExitStatus::new(Some(0)),
462- /// stdout: format!("ran: {cmd}").into_bytes (),
465+ /// stdout: b"hello\n".to_vec (),
463466 /// stderr: Vec::new(),
464- /// })
465- /// } );
467+ /// }),
468+ /// ] );
466469 /// ```
467- pub fn from_fn (
468- f : impl Fn ( & str ) -> std:: io:: Result < CommandOutput > + Send + Sync + ' static ,
469- ) -> Self {
470- Self ( process:: Inner :: Fake ( Arc :: new ( f) ) )
470+ pub fn from_slice ( commands : & [ ( & str , CommandOutput ) ] ) -> Self {
471+ let map: HashMap < String , CommandOutput > = commands
472+ . iter ( )
473+ . map ( |( k, v) | ( k. to_string ( ) , v. clone ( ) ) )
474+ . collect ( ) ;
475+ Self ( process:: Inner :: Fake ( Arc :: new ( map) ) )
471476 }
472477
473478 /// Execute a command string and return its output.
@@ -497,35 +502,29 @@ impl Process {
497502 stderr : output. stderr ,
498503 } )
499504 }
500- Inner :: Fake ( f) => f ( command) ,
505+ Inner :: Fake ( map) => map. get ( command) . cloned ( ) . ok_or_else ( || {
506+ std:: io:: Error :: new (
507+ std:: io:: ErrorKind :: NotFound ,
508+ format ! ( "command not found in fake process: {command}" ) ,
509+ )
510+ } ) ,
501511 Inner :: Custom ( provider) => provider. execute ( command) . await ,
502512 }
503513 }
504514}
505515
506516mod process {
517+ use std:: collections:: HashMap ;
507518 use std:: sync:: Arc ;
508519
509520 use super :: ProvideProcess ;
510521
511- type FakeFn = dyn Fn ( & str ) -> std:: io:: Result < super :: CommandOutput > + Send + Sync ;
512-
513- #[ derive( Clone ) ]
522+ #[ derive( Clone , Debug ) ]
514523 pub ( super ) enum Inner {
515524 Real ,
516- Fake ( Arc < FakeFn > ) ,
525+ Fake ( Arc < HashMap < String , super :: CommandOutput > > ) ,
517526 Custom ( Arc < dyn ProvideProcess > ) ,
518527 }
519-
520- impl std:: fmt:: Debug for Inner {
521- fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
522- match self {
523- Inner :: Real => f. write_str ( "Real" ) ,
524- Inner :: Fake ( _) => f. write_str ( "Fake(fn)" ) ,
525- Inner :: Custom ( c) => write ! ( f, "Custom({c:?})" ) ,
526- }
527- }
528- }
529528}
530529
531530#[ cfg( test) ]
@@ -703,34 +702,43 @@ mod test {
703702 }
704703
705704 #[ tokio:: test]
706- async fn process_from_fn_success ( ) {
707- let process = Process :: from_fn ( |cmd| {
708- Ok ( CommandOutput {
705+ async fn process_from_slice_success ( ) {
706+ let process = Process :: from_slice ( & [ (
707+ "my-command" ,
708+ CommandOutput {
709709 status : ExitStatus :: new ( Some ( 0 ) ) ,
710- stdout : format ! ( "output of: {cmd}" ) . into_bytes ( ) ,
710+ stdout : b "output of: my-command" . to_vec ( ) ,
711711 stderr : Vec :: new ( ) ,
712- } )
713- } ) ;
712+ } ,
713+ ) ] ) ;
714714 let output = process. execute ( "my-command" ) . await . expect ( "success" ) ;
715715 assert ! ( output. status. success( ) ) ;
716716 assert_eq ! ( output. stdout, b"output of: my-command" ) ;
717717 assert ! ( output. stderr. is_empty( ) ) ;
718718 }
719719
720720 #[ tokio:: test]
721- async fn process_from_fn_failure ( ) {
722- let process = Process :: from_fn ( |_cmd| {
723- Ok ( CommandOutput {
721+ async fn process_from_slice_failure ( ) {
722+ let process = Process :: from_slice ( & [ (
723+ "bad-command" ,
724+ CommandOutput {
724725 status : ExitStatus :: new ( Some ( 1 ) ) ,
725726 stdout : Vec :: new ( ) ,
726727 stderr : b"something went wrong" . to_vec ( ) ,
727- } )
728- } ) ;
728+ } ,
729+ ) ] ) ;
729730 let output = process. execute ( "bad-command" ) . await . expect ( "io succeeds" ) ;
730731 assert ! ( !output. status. success( ) ) ;
731732 assert_eq ! ( output. stderr, b"something went wrong" ) ;
732733 }
733734
735+ #[ tokio:: test]
736+ async fn process_from_slice_not_found ( ) {
737+ let process = Process :: from_slice ( & [ ] ) ;
738+ let err = process. execute ( "missing" ) . await . expect_err ( "should fail" ) ;
739+ assert_eq ! ( err. kind( ) , std:: io:: ErrorKind :: NotFound ) ;
740+ }
741+
734742 #[ tokio:: test]
735743 async fn custom_process_works ( ) {
736744 #[ derive( Debug ) ]
0 commit comments