@@ -527,12 +527,25 @@ impl Cheatcode for ffiCall {
527527 let Self { commandInput : input } = self ;
528528
529529 let output = ffi ( state, input) ?;
530- // TODO: check exit code?
530+
531+ // Check the exit code of the command.
532+ if output. exitCode != 0 {
533+ // If the command failed, return an error with the exit code and stderr.
534+ return Err ( fmt_err ! (
535+ "ffi command {:?} exited with code {}. stderr: {}" ,
536+ input,
537+ output. exitCode,
538+ String :: from_utf8_lossy( & output. stderr)
539+ ) ) ;
540+ }
541+
542+ // If the command succeeded but still wrote to stderr, log it as a warning.
531543 if !output. stderr . is_empty ( ) {
532544 let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
533- error ! ( target: "cheatcodes" , ?input, ?stderr, "non-empty stderr" ) ;
545+ warn ! ( target: "cheatcodes" , ?input, ?stderr, "ffi command wrote to stderr" ) ;
534546 }
535- // we already hex-decoded the stdout in `ffi`
547+
548+ // We already hex-decoded the stdout in the `ffi` helper function.
536549 Ok ( output. stdout . abi_encode ( ) )
537550 }
538551}
@@ -884,6 +897,29 @@ mod tests {
884897 assert_eq ! ( output. stdout, Bytes :: from( msg. as_bytes( ) ) ) ;
885898 }
886899
900+ #[ test]
901+ fn test_ffi_fails_on_error_code ( ) {
902+ let mut cheats = cheats ( ) ;
903+
904+ // Use a command that is guaranteed to fail with a non-zero exit code on any platform.
905+ #[ cfg( unix) ]
906+ let args = vec ! [ "false" . to_string( ) ] ;
907+ #[ cfg( windows) ]
908+ let args = vec ! [ "cmd" . to_string( ) , "/c" . to_string( ) , "exit 1" . to_string( ) ] ;
909+
910+ let result = ffiCall { commandInput : args } . apply ( & mut cheats) ;
911+
912+ // Assert that the cheatcode returned an error.
913+ assert ! ( result. is_err( ) , "Expected ffi cheatcode to fail, but it succeeded" ) ;
914+
915+ // Assert that the error message contains the expected information.
916+ let err_msg = result. unwrap_err ( ) . to_string ( ) ;
917+ assert ! (
918+ err_msg. contains( "exited with code 1" ) ,
919+ "Error message did not contain exit code: {err_msg}"
920+ ) ;
921+ }
922+
887923 #[ test]
888924 fn test_artifact_parsing ( ) {
889925 let s = include_str ! ( "../../evm/test-data/solc-obj.json" ) ;
0 commit comments