@@ -3,6 +3,7 @@ package run
33import (
44 "fmt"
55 "os/exec"
6+ "path/filepath"
67 "regexp"
78 "strings"
89)
@@ -12,9 +13,11 @@ type T interface {
1213 Errorf (string , ... interface {})
1314}
1415
16+ // Stub installs a catch-all for all external commands invoked from gh. It returns a restore func that, when
17+ // invoked from tests, fails the current test if some stubs that were registered were never matched.
1518func Stub () (* CommandStubber , func (T )) {
1619 cs := & CommandStubber {}
17- teardown := SetPrepareCmd (func (cmd * exec.Cmd ) Runnable {
20+ teardown := setPrepareCmd (func (cmd * exec.Cmd ) Runnable {
1821 s := cs .find (cmd .Args )
1922 if s == nil {
2023 panic (fmt .Sprintf ("no exec stub for `%s`" , strings .Join (cmd .Args , " " )))
@@ -43,13 +46,33 @@ func Stub() (*CommandStubber, func(T)) {
4346 }
4447}
4548
49+ func setPrepareCmd (fn func (* exec.Cmd ) Runnable ) func () {
50+ origPrepare := PrepareCmd
51+ PrepareCmd = func (cmd * exec.Cmd ) Runnable {
52+ // normalize git executable name for consistency in tests
53+ if baseName := filepath .Base (cmd .Args [0 ]); baseName == "git" || baseName == "git.exe" {
54+ cmd .Args [0 ] = "git"
55+ }
56+ return fn (cmd )
57+ }
58+ return func () {
59+ PrepareCmd = origPrepare
60+ }
61+ }
62+
63+ // CommandStubber stubs out invocations to external commands.
4664type CommandStubber struct {
4765 stubs []* commandStub
4866}
4967
50- func (cs * CommandStubber ) Register (p string , exitStatus int , output string , callbacks ... CommandCallback ) {
68+ // Register a stub for an external command. Pattern is a regular expression, output is the standard output
69+ // from a command. Pass callbacks to inspect raw arguments that the command was invoked with.
70+ func (cs * CommandStubber ) Register (pattern string , exitStatus int , output string , callbacks ... CommandCallback ) {
71+ if len (pattern ) < 1 {
72+ panic ("cannot use empty regexp pattern" )
73+ }
5174 cs .stubs = append (cs .stubs , & commandStub {
52- pattern : regexp .MustCompile (p ),
75+ pattern : regexp .MustCompile (pattern ),
5376 exitStatus : exitStatus ,
5477 stdout : output ,
5578 callbacks : callbacks ,
@@ -76,13 +99,15 @@ type commandStub struct {
7699 callbacks []CommandCallback
77100}
78101
102+ // Run satisfies Runnable
79103func (s * commandStub ) Run () error {
80104 if s .exitStatus != 0 {
81105 return fmt .Errorf ("%s exited with status %d" , s .pattern , s .exitStatus )
82106 }
83107 return nil
84108}
85109
110+ // Output satisfies Runnable
86111func (s * commandStub ) Output () ([]byte , error ) {
87112 if s .exitStatus != 0 {
88113 return []byte (nil ), fmt .Errorf ("%s exited with status %d" , s .pattern , s .exitStatus )
0 commit comments