mirror of
https://github.com/jesseduffield/lazygit.git
synced 2024-12-04 10:34:55 +02:00
975d2bedb6
From the go 1.19 release notes: Command and LookPath no longer allow results from a PATH search to be found relative to the current directory. This removes a common source of security problems but may also break existing programs that depend on using, say, exec.Command("prog") to run a binary named prog (or, on Windows, prog.exe) in the current directory. See the os/exec package documentation for information about how best to update such programs.
158 lines
3.7 KiB
Go
158 lines
3.7 KiB
Go
package oscommands
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/go-errors/errors"
|
|
"github.com/samber/lo"
|
|
"golang.org/x/exp/slices"
|
|
)
|
|
|
|
// for use in testing
|
|
|
|
type FakeCmdObjRunner struct {
|
|
t *testing.T
|
|
// commands can be run in any order; mimicking the concurrent behaviour of
|
|
// production code.
|
|
expectedCmds []CmdObjMatcher
|
|
|
|
invokedCmdIndexes []int
|
|
|
|
mutex sync.Mutex
|
|
}
|
|
|
|
type CmdObjMatcher struct {
|
|
description string
|
|
// returns true if the matcher matches the command object
|
|
test func(ICmdObj) bool
|
|
|
|
// output of the command
|
|
output string
|
|
// error of the command
|
|
err error
|
|
}
|
|
|
|
var _ ICmdObjRunner = &FakeCmdObjRunner{}
|
|
|
|
func NewFakeRunner(t *testing.T) *FakeCmdObjRunner { //nolint:thelper
|
|
return &FakeCmdObjRunner{t: t}
|
|
}
|
|
|
|
func (self *FakeCmdObjRunner) remainingExpectedCmds() []CmdObjMatcher {
|
|
return lo.Filter(self.expectedCmds, func(_ CmdObjMatcher, i int) bool {
|
|
return !lo.Contains(self.invokedCmdIndexes, i)
|
|
})
|
|
}
|
|
|
|
func (self *FakeCmdObjRunner) Run(cmdObj ICmdObj) error {
|
|
_, err := self.RunWithOutput(cmdObj)
|
|
return err
|
|
}
|
|
|
|
func (self *FakeCmdObjRunner) RunWithOutput(cmdObj ICmdObj) (string, error) {
|
|
self.mutex.Lock()
|
|
defer self.mutex.Unlock()
|
|
|
|
if len(self.remainingExpectedCmds()) == 0 {
|
|
self.t.Errorf("ran too many commands. Unexpected command: `%s`", cmdObj.ToString())
|
|
return "", errors.New("ran too many commands")
|
|
}
|
|
|
|
for i := range self.expectedCmds {
|
|
if lo.Contains(self.invokedCmdIndexes, i) {
|
|
continue
|
|
}
|
|
expectedCmd := self.expectedCmds[i]
|
|
matched := expectedCmd.test(cmdObj)
|
|
if matched {
|
|
self.invokedCmdIndexes = append(self.invokedCmdIndexes, i)
|
|
return expectedCmd.output, expectedCmd.err
|
|
}
|
|
}
|
|
|
|
self.t.Errorf("Unexpected command: `%s`", cmdObj.ToString())
|
|
return "", nil
|
|
}
|
|
|
|
func (self *FakeCmdObjRunner) RunWithOutputs(cmdObj ICmdObj) (string, string, error) {
|
|
output, err := self.RunWithOutput(cmdObj)
|
|
return output, "", err
|
|
}
|
|
|
|
func (self *FakeCmdObjRunner) RunAndProcessLines(cmdObj ICmdObj, onLine func(line string) (bool, error)) error {
|
|
output, err := self.RunWithOutput(cmdObj)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
scanner := bufio.NewScanner(strings.NewReader(output))
|
|
scanner.Split(bufio.ScanLines)
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
stop, err := onLine(line)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if stop {
|
|
break
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (self *FakeCmdObjRunner) ExpectFunc(description string, fn func(cmdObj ICmdObj) bool, output string, err error) *FakeCmdObjRunner {
|
|
self.mutex.Lock()
|
|
defer self.mutex.Unlock()
|
|
|
|
self.expectedCmds = append(self.expectedCmds, CmdObjMatcher{
|
|
test: fn,
|
|
output: output,
|
|
err: err,
|
|
description: description,
|
|
})
|
|
|
|
return self
|
|
}
|
|
|
|
func (self *FakeCmdObjRunner) ExpectArgs(expectedArgs []string, output string, err error) *FakeCmdObjRunner {
|
|
description := fmt.Sprintf("matches args %s", strings.Join(expectedArgs, " "))
|
|
self.ExpectFunc(description, func(cmdObj ICmdObj) bool {
|
|
return slices.Equal(expectedArgs, cmdObj.GetCmd().Args)
|
|
}, output, err)
|
|
|
|
return self
|
|
}
|
|
|
|
func (self *FakeCmdObjRunner) ExpectGitArgs(expectedArgs []string, output string, err error) *FakeCmdObjRunner {
|
|
description := fmt.Sprintf("matches git args %s", strings.Join(expectedArgs, " "))
|
|
self.ExpectFunc(description, func(cmdObj ICmdObj) bool {
|
|
return slices.Equal(expectedArgs, cmdObj.GetCmd().Args[1:])
|
|
}, output, err)
|
|
|
|
return self
|
|
}
|
|
|
|
func (self *FakeCmdObjRunner) CheckForMissingCalls() {
|
|
self.mutex.Lock()
|
|
defer self.mutex.Unlock()
|
|
|
|
remaining := self.remainingExpectedCmds()
|
|
if len(remaining) > 0 {
|
|
self.t.Errorf(
|
|
"expected %d more command(s) to be run. Remaining commands:\n%s",
|
|
len(remaining),
|
|
strings.Join(
|
|
lo.Map(remaining, func(cmdObj CmdObjMatcher, _ int) string {
|
|
return cmdObj.description
|
|
}),
|
|
"\n",
|
|
),
|
|
)
|
|
}
|
|
}
|