@@ -471,6 +471,79 @@ mod tests {
471471 Ok ( ( ) )
472472 }
473473
474+ #[ test]
475+ fn determine_branch_surfaces_git_failures ( ) -> color_eyre:: Result < ( ) > {
476+ let dir = TempDir :: new ( ) ?;
477+ let worktree = dir. path ( ) ;
478+
479+ let mut runner = MockCommandRunner :: default ( ) ;
480+ runner. responses . push_back ( Ok ( CommandOutput {
481+ stdout : String :: new ( ) ,
482+ stderr : "fatal: not a git repository" . into ( ) ,
483+ success : false ,
484+ status_code : Some ( 128 ) ,
485+ } ) ) ;
486+
487+ let mut command = MergePrGithubCommand :: with_runner ( "feature/test" . into ( ) , runner) ;
488+ let error = command. determine_branch ( worktree) . unwrap_err ( ) ;
489+ let message = format ! ( "{error}" ) ;
490+ assert ! ( message. contains( "git" ) ) ;
491+ assert ! ( message. contains( "rev-parse" ) ) ;
492+
493+ assert_eq ! (
494+ command. runner. calls,
495+ vec![ RecordedCall {
496+ program: "git" . into( ) ,
497+ dir: worktree. to_path_buf( ) ,
498+ args: vec![ "rev-parse" . into( ) , "--abbrev-ref" . into( ) , "HEAD" . into( ) ] ,
499+ } ]
500+ ) ;
501+
502+ Ok ( ( ) )
503+ }
504+
505+ #[ test]
506+ fn determine_branch_errors_on_empty_output ( ) -> color_eyre:: Result < ( ) > {
507+ let dir = TempDir :: new ( ) ?;
508+ let worktree = dir. path ( ) ;
509+
510+ let mut runner = MockCommandRunner :: default ( ) ;
511+ runner. responses . push_back ( Ok ( CommandOutput {
512+ stdout : "\n " . into ( ) ,
513+ stderr : String :: new ( ) ,
514+ success : true ,
515+ status_code : Some ( 0 ) ,
516+ } ) ) ;
517+
518+ let mut command = MergePrGithubCommand :: with_runner ( "feature/test" . into ( ) , runner) ;
519+ let error = command. determine_branch ( worktree) . unwrap_err ( ) ;
520+ assert ! ( format!( "{error}" ) . contains( "empty branch name" ) ) ;
521+
522+ Ok ( ( ) )
523+ }
524+
525+ #[ test]
526+ fn find_pull_request_errors_on_invalid_json ( ) -> color_eyre:: Result < ( ) > {
527+ let dir = TempDir :: new ( ) ?;
528+ let repo_path = dir. path ( ) ;
529+
530+ let mut runner = MockCommandRunner :: default ( ) ;
531+ runner. responses . push_back ( Ok ( CommandOutput {
532+ stdout : "not-json" . into ( ) ,
533+ stderr : String :: new ( ) ,
534+ success : true ,
535+ status_code : Some ( 0 ) ,
536+ } ) ) ;
537+
538+ let mut command = MergePrGithubCommand :: with_runner ( "feature/test" . into ( ) , runner) ;
539+ let error = command
540+ . find_pull_request ( repo_path, "feature/test" )
541+ . unwrap_err ( ) ;
542+ assert ! ( format!( "{error}" ) . contains( "parse" ) ) ;
543+
544+ Ok ( ( ) )
545+ }
546+
474547 #[ test]
475548 fn removes_remote_branch_when_requested ( ) -> color_eyre:: Result < ( ) > {
476549 let repo_dir = TempDir :: new ( ) ?;
@@ -1014,4 +1087,58 @@ mod tests {
10141087
10151088 Ok ( ( ) )
10161089 }
1090+
1091+ #[ test]
1092+ fn command_failure_includes_stderr_and_status ( ) {
1093+ let output = CommandOutput {
1094+ stdout : String :: new ( ) ,
1095+ stderr : "fatal: bad" . into ( ) ,
1096+ success : false ,
1097+ status_code : Some ( 128 ) ,
1098+ } ;
1099+
1100+ let error = command_failure (
1101+ "git" ,
1102+ & [ "rev-parse" . into ( ) , "HEAD with spaces" . into ( ) ] ,
1103+ & output,
1104+ ) ;
1105+
1106+ let message = format ! ( "{error}" ) ;
1107+ assert ! ( message. contains( "git rev-parse" ) ) ;
1108+ assert ! ( message. contains( "'HEAD with spaces'" ) ) ;
1109+ assert ! ( message. contains( "fatal: bad" ) ) ;
1110+ assert ! ( message. contains( "128" ) ) ;
1111+ }
1112+
1113+ #[ test]
1114+ fn quote_arg_quotes_when_needed ( ) {
1115+ assert_eq ! ( quote_arg( "simple" ) , "simple" ) ;
1116+ assert_eq ! ( quote_arg( "with space" ) , "'with space'" ) ;
1117+ assert_eq ! ( quote_arg( "quote'needed" ) , "'quote'\\ ''needed'" ) ;
1118+ }
1119+
1120+ #[ test]
1121+ fn format_command_builds_shell_safe_string ( ) {
1122+ let cmd = format_command ( "git" , & [ "commit" . into ( ) , "-m" . into ( ) , "hello world" . into ( ) ] ) ;
1123+ assert_eq ! ( cmd, "git commit -m 'hello world'" ) ;
1124+ }
1125+
1126+ #[ test]
1127+ fn remote_branch_already_gone_detects_message ( ) {
1128+ let output = CommandOutput {
1129+ stdout : "remote ref does not exist" . into ( ) ,
1130+ stderr : "" . into ( ) ,
1131+ success : false ,
1132+ status_code : Some ( 1 ) ,
1133+ } ;
1134+ assert ! ( remote_branch_already_gone( & output) ) ;
1135+
1136+ let output_ok = CommandOutput {
1137+ stdout : String :: new ( ) ,
1138+ stderr : String :: new ( ) ,
1139+ success : false ,
1140+ status_code : Some ( 1 ) ,
1141+ } ;
1142+ assert ! ( !remote_branch_already_gone( & output_ok) ) ;
1143+ }
10171144}
0 commit comments