mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-03-21 21:47:32 +02:00
I don't know if this is a hack or not: we run a git command and increment the pending action count to 1 but at some point the command requests a username or password, so we need to prompt the user to enter that. At that point we don't want to say that there is a pending action, so we decrement the action count before prompting the user and then re-increment it again afterward. Given that we panic when the counter goes below zero, it's important that it's not zero when we run the git command (should be impossible anyway). I toyed with a different approach using channels and a long-running goroutine that handles all commands that request credentials but it feels over-engineered compared to this commit's approach.
122 lines
3.2 KiB
Go
122 lines
3.2 KiB
Go
package oscommands
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
)
|
|
|
|
func getRunner() *cmdObjRunner {
|
|
log := utils.NewDummyLog()
|
|
return &cmdObjRunner{
|
|
log: log,
|
|
guiIO: NewNullGuiIO(log),
|
|
}
|
|
}
|
|
|
|
func toChanFn(f func(ct CredentialType) string) func(CredentialType) <-chan string {
|
|
return func(ct CredentialType) <-chan string {
|
|
ch := make(chan string)
|
|
|
|
go func() {
|
|
ch <- f(ct)
|
|
}()
|
|
|
|
return ch
|
|
}
|
|
}
|
|
|
|
func TestProcessOutput(t *testing.T) {
|
|
defaultPromptUserForCredential := func(ct CredentialType) string {
|
|
switch ct {
|
|
case Password:
|
|
return "password"
|
|
case Username:
|
|
return "username"
|
|
case Passphrase:
|
|
return "passphrase"
|
|
case PIN:
|
|
return "pin"
|
|
default:
|
|
panic("unexpected credential type")
|
|
}
|
|
}
|
|
|
|
scenarios := []struct {
|
|
name string
|
|
promptUserForCredential func(CredentialType) string
|
|
output string
|
|
expectedToWrite string
|
|
}{
|
|
{
|
|
name: "no output",
|
|
promptUserForCredential: defaultPromptUserForCredential,
|
|
output: "",
|
|
expectedToWrite: "",
|
|
},
|
|
{
|
|
name: "password prompt",
|
|
promptUserForCredential: defaultPromptUserForCredential,
|
|
output: "Password:",
|
|
expectedToWrite: "password",
|
|
},
|
|
{
|
|
name: "password prompt 2",
|
|
promptUserForCredential: defaultPromptUserForCredential,
|
|
output: "Bill's password:",
|
|
expectedToWrite: "password",
|
|
},
|
|
{
|
|
name: "password prompt 3",
|
|
promptUserForCredential: defaultPromptUserForCredential,
|
|
output: "Password for 'Bill':",
|
|
expectedToWrite: "password",
|
|
},
|
|
{
|
|
name: "username prompt",
|
|
promptUserForCredential: defaultPromptUserForCredential,
|
|
output: "Username for 'Bill':",
|
|
expectedToWrite: "username",
|
|
},
|
|
{
|
|
name: "passphrase prompt",
|
|
promptUserForCredential: defaultPromptUserForCredential,
|
|
output: "Enter passphrase for key '123':",
|
|
expectedToWrite: "passphrase",
|
|
},
|
|
{
|
|
name: "pin prompt",
|
|
promptUserForCredential: defaultPromptUserForCredential,
|
|
output: "Enter PIN for key '123':",
|
|
expectedToWrite: "pin",
|
|
},
|
|
{
|
|
name: "username and password prompt",
|
|
promptUserForCredential: defaultPromptUserForCredential,
|
|
output: "Password:\nUsername for 'Alice':\n",
|
|
expectedToWrite: "passwordusername",
|
|
},
|
|
{
|
|
name: "user submits empty credential",
|
|
promptUserForCredential: func(ct CredentialType) string { return "" },
|
|
output: "Password:\n",
|
|
expectedToWrite: "",
|
|
},
|
|
}
|
|
|
|
for _, scenario := range scenarios {
|
|
t.Run(scenario.name, func(t *testing.T) {
|
|
runner := getRunner()
|
|
reader := strings.NewReader(scenario.output)
|
|
writer := &strings.Builder{}
|
|
|
|
runner.processOutput(reader, writer, toChanFn(scenario.promptUserForCredential))
|
|
|
|
if writer.String() != scenario.expectedToWrite {
|
|
t.Errorf("expected to write '%s' but got '%s'", scenario.expectedToWrite, writer.String())
|
|
}
|
|
})
|
|
}
|
|
}
|