summaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/gui/assert.go88
-rw-r--r--pkg/gui/gui.go31
-rw-r--r--pkg/gui/gui_test.go34
-rw-r--r--pkg/gui/input.go93
-rw-r--r--pkg/gui/old_gui_test.go76
-rw-r--r--pkg/gui/test_mode.go63
-rw-r--r--pkg/integration/env.go46
-rw-r--r--pkg/integration/integration.go519
-rw-r--r--pkg/integration/integration_old.go564
-rw-r--r--pkg/integration/integration_tests/branch/suggestions.go40
-rw-r--r--pkg/integration/integration_tests/commit/commit.go32
-rw-r--r--pkg/integration/integration_tests/commit/new_branch.go38
-rw-r--r--pkg/integration/integration_tests/tests.go16
-rw-r--r--pkg/integration/recording.go (renamed from pkg/gui/recording.go)27
-rw-r--r--pkg/integration/shell.go53
-rw-r--r--pkg/integration/types/types.go152
-rw-r--r--pkg/utils/utils.go7
17 files changed, 1361 insertions, 518 deletions
diff --git a/pkg/gui/assert.go b/pkg/gui/assert.go
new file mode 100644
index 000000000..43ecc26d8
--- /dev/null
+++ b/pkg/gui/assert.go
@@ -0,0 +1,88 @@
+package gui
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/jesseduffield/lazygit/pkg/integration/types"
+)
+
+type AssertImpl struct {
+ gui *Gui
+}
+
+var _ types.Assert = &AssertImpl{}
+
+func (self *AssertImpl) WorkingTreeFileCount(expectedCount int) {
+ self.assertWithRetries(func() (bool, string) {
+ actualCount := len(self.gui.State.Model.Files)
+
+ return actualCount == expectedCount, fmt.Sprintf(
+ "Expected %d changed working tree files, but got %d",
+ expectedCount, actualCount,
+ )
+ })
+}
+
+func (self *AssertImpl) CommitCount(expectedCount int) {
+ self.assertWithRetries(func() (bool, string) {
+ actualCount := len(self.gui.State.Model.Commits)
+
+ return actualCount == expectedCount, fmt.Sprintf(
+ "Expected %d commits present, but got %d",
+ expectedCount, actualCount,
+ )
+ })
+}
+
+func (self *AssertImpl) HeadCommitMessage(expectedMessage string) {
+ self.assertWithRetries(func() (bool, string) {
+ if len(self.gui.State.Model.Commits) == 0 {
+ return false, "Expected at least one commit to be present"
+ }
+
+ headCommit := self.gui.State.Model.Commits[0]
+ if headCommit.Name != expectedMessage {
+ return false, fmt.Sprintf(
+ "Expected commit message to be '%s', but got '%s'",
+ expectedMessage, headCommit.Name,
+ )
+ }
+
+ return true, ""
+ })
+}
+
+func (self *AssertImpl) CurrentViewName(expectedViewName string) {
+ self.assertWithRetries(func() (bool, string) {
+ actual := self.gui.currentViewName()
+ return actual == expectedViewName, fmt.Sprintf("Expected current view name to be '%s', but got '%s'", expectedViewName, actual)
+ })
+}
+
+func (self *AssertImpl) CurrentBranchName(expectedViewName string) {
+ self.assertWithRetries(func() (bool, string) {
+ actual := self.gui.helpers.Refs.GetCheckedOutRef().Name
+ return actual == expectedViewName, fmt.Sprintf("Expected current branch name to be '%s', but got '%s'", expectedViewName, actual)
+ })
+}
+
+func (self *AssertImpl) assertWithRetries(test func() (bool, string)) {
+ waitTimes := []int{0, 100, 200, 400, 800, 1600}
+
+ var message string
+ for _, waitTime := range waitTimes {
+ time.Sleep(time.Duration(waitTime) * time.Millisecond)
+
+ var ok bool
+ ok, message = test()
+ if ok {
+ return
+ }
+ }
+
+ self.gui.g.Close()
+ // need to give the gui time to close
+ time.Sleep(time.Millisecond * 100)
+ panic(message)
+}
diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go
index bb5821a57..f7c8926f5 100644
--- a/pkg/gui/gui.go
+++ b/pkg/gui/gui.go
@@ -31,6 +31,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/gui/services/custom_commands"
"github.com/jesseduffield/lazygit/pkg/gui/style"
"github.com/jesseduffield/lazygit/pkg/gui/types"
+ "github.com/jesseduffield/lazygit/pkg/integration"
"github.com/jesseduffield/lazygit/pkg/tasks"
"github.com/jesseduffield/lazygit/pkg/theme"
"github.com/jesseduffield/lazygit/pkg/updates"
@@ -418,12 +419,14 @@ var RuneReplacements = map[rune]string{
}
func (gui *Gui) initGocui(headless bool) (*gocui.Gui, error) {
- recordEvents := recordingEvents()
+ recordEvents := integration.RecordingEvents()
playMode := gocui.NORMAL
if recordEvents {
playMode = gocui.RECORDING
- } else if replaying() {
+ } else if integration.Replaying() {
playMode = gocui.REPLAYING
+ } else if integration.IntegrationTestName() != "" {
+ playMode = gocui.REPLAYING_NEW
}
g, err := gocui.NewGui(gocui.OutputTrue, OverlappingEdges, playMode, headless, RuneReplacements)
@@ -475,7 +478,7 @@ func (gui *Gui) viewTabMap() map[string][]context.TabView {
// Run: setup the gui with keybindings and start the mainloop
func (gui *Gui) Run(startArgs types.StartArgs) error {
- g, err := gui.initGocui(headless())
+ g, err := gui.initGocui(integration.Headless())
if err != nil {
return err
}
@@ -490,23 +493,7 @@ func (gui *Gui) Run(startArgs types.StartArgs) error {
})
deadlock.Opts.Disable = !gui.Debug
- if replaying() {
- gui.g.RecordingConfig = gocui.RecordingConfig{
- Speed: getRecordingSpeed(),
- Leeway: 100,
- }
-
- var err error
- gui.g.Recording, err = gui.loadRecording()
- if err != nil {
- return err
- }
-
- go utils.Safe(func() {
- time.Sleep(time.Second * 40)
- log.Fatal("40 seconds is up, lazygit recording took too long to complete")
- })
- }
+ gui.handleTestMode()
gui.g.OnSearchEscape = gui.onSearchEscape
if err := gui.Config.ReloadUserConfig(); err != nil {
@@ -593,7 +580,7 @@ func (gui *Gui) RunAndHandleError(startArgs types.StartArgs) error {
}
}
- if err := gui.saveRecording(gui.g.Recording); err != nil {
+ if err := integration.SaveRecording(gui.g.Recording); err != nil {
return err
}
@@ -627,7 +614,7 @@ func (gui *Gui) runSubprocessWithSuspense(subprocess oscommands.ICmdObj) (bool,
gui.Mutexes.SubprocessMutex.Lock()
defer gui.Mutexes.SubprocessMutex.Unlock()
- if replaying() {
+ if integration.Replaying() {
// we do not yet support running subprocesses within integration tests. So if
// we're replaying an integration test and we're inside this method, something
// has gone wrong, so we should fail
diff --git a/pkg/gui/gui_test.go b/pkg/gui/gui_test.go
index d2345d5d0..2565392e6 100644
--- a/pkg/gui/gui_test.go
+++ b/pkg/gui/gui_test.go
@@ -3,6 +3,9 @@
package gui
+// this is the new way of running tests. See pkg/integration/integration_tests/commit.go
+// for an example
+
import (
"fmt"
"io"
@@ -14,60 +17,37 @@ import (
"github.com/creack/pty"
"github.com/jesseduffield/lazygit/pkg/integration"
+ "github.com/jesseduffield/lazygit/pkg/integration/types"
"github.com/stretchr/testify/assert"
)
-// This file is quite similar to integration/main.go. The main difference is that this file is
-// run via `go test` whereas the other is run via `test/lazyintegration/main.go` which provides
-// a convenient gui wrapper around our integration tests. The `go test` approach is better
-// for CI and for running locally in the background to ensure you haven't broken
-// anything while making changes. If you want to visually see what's happening when a test is run,
-// you'll need to take the other approach
-//
-// As for this file, to run an integration test, e.g. for test 'commit', go:
-// go test pkg/gui/gui_test.go -run /commit
-//
-// To update a snapshot for an integration test, pass UPDATE_SNAPSHOTS=true
-// UPDATE_SNAPSHOTS=true go test pkg/gui/gui_test.go -run /commit
-//
-// integration tests are run in test/integration/<test_name>/actual and the final test does
-// not clean up that directory so you can cd into it to see for yourself what
-// happened when a test fails.
-//
-// To override speed, pass e.g. `SPEED=1` as an env var. Otherwise we start each test
-// at a high speed and then drop down to lower speeds upon each failure until finally
-// trying at the original playback speed (speed 1). A speed of 2 represents twice the
-// original playback speed. Speed may be a decimal.
-
func Test(t *testing.T) {
if testing.Short() {
t.Skip("Skipping integration tests in short mode")
}
mode := integration.GetModeFromEnv()
- speedEnv := os.Getenv("SPEED")
includeSkipped := os.Getenv("INCLUDE_SKIPPED") != ""
parallelTotal := tryConvert(os.Getenv("PARALLEL_TOTAL"), 1)
parallelIndex := tryConvert(os.Getenv("PARALLEL_INDEX"), 0)
testNumber := 0
- err := integration.RunTests(
+ err := integration.RunTestsNew(
t.Logf,
runCmdHeadless,
- func(test *integration.Test, f func(*testing.T) error) {
+ func(test types.Test, f func(*testing.T) error) {
defer func() { testNumber += 1 }()
if testNumber%parallelTotal != parallelIndex {
return
}
- t.Run(test.Name, func(t *testing.T) {
+ t.Run(test.Name(), func(t *testing.T) {
err := f(t)
assert.NoError(t, err)
})
},
mode,
- speedEnv,
func(t *testing.T, expected string, actual string, prefix string) {
t.Helper()
assert.Equal(t, expected, actual, fmt.Sprintf("Unexpected %s. Expected:\n%s\nActual:\n%s\n", prefix, expected, actual))
diff --git a/pkg/gui/input.go b/pkg/gui/input.go
new file mode 100644
index 000000000..c6424c077
--- /dev/null
+++ b/pkg/gui/input.go
@@ -0,0 +1,93 @@
+package gui
+
+import (
+ "time"
+
+ "github.com/gdamore/tcell/v2"
+ "github.com/jesseduffield/gocui"
+ "github.com/jesseduffield/lazygit/pkg/config"
+ "github.com/jesseduffield/lazygit/pkg/gui/keybindings"
+ "github.com/jesseduffield/lazygit/pkg/integration/types"
+)
+
+type InputImpl struct {
+ g *gocui.Gui
+ keys config.KeybindingConfig
+}
+
+var _ types.Input = &InputImpl{}
+
+func (self *InputImpl) PushKeys(keyStrs ...string) {
+ for _, keyStr := range keyStrs {
+ self.pushKey(keyStr)
+ }
+}
+
+func (self *InputImpl) pushKey(keyStr string) {
+ key := keybindings.GetKey(keyStr)
+
+ var r rune
+ var tcellKey tcell.Key
+ switch v := key.(type) {
+ case rune:
+ r = v
+ tcellKey = tcell.KeyRune
+ case gocui.Key:
+ tcellKey = tcell.Key(v)
+ }
+
+ self.g.ReplayedEvents.Keys <- gocui.NewTcellKeyEventWrapper(
+ tcell.NewEventKey(tcellKey, r, tcell.ModNone),
+ 0,
+ )
+}
+
+func (self *InputImpl) SwitchToStatusWindow() {
+ self.pushKey(self.keys.Universal.JumpToBlock[0])
+}
+
+func (self *InputImpl) SwitchToFilesWindow() {
+ self.pushKey(self.keys.Universal.JumpToBlock[1])
+}
+
+func (self *InputImpl) SwitchToBranchesWindow() {
+ self.pushKey(self.keys.Universal.JumpToBlock[2])
+}
+
+func (self *InputImpl) SwitchToCommitsWindow() {
+ self.pushKey(self.keys.Universal.JumpToBlock[3])
+}
+
+func (self *InputImpl) SwitchToStashWindow() {
+ self.pushKey(self.keys.Universal.JumpToBlock[4])
+}
+
+func (self *InputImpl) Type(content string) {
+ for _, char := range content {
+ self.pushKey(string(char))
+ }
+}
+
+func (self *InputImpl) Confirm() {
+ self.pushKey(self.keys.Universal.Confirm)
+}
+
+func (self *InputImpl) Cancel() {
+ self.pushKey(self.keys.Universal.Return)
+}
+
+func (self *InputImpl) Select() {
+ self.pushKey(self.keys.Universal.Select)
+}
+
+func (self *InputImpl) NextItem() {
+ self.pushKey(self.keys.Universal.NextItem)
+}
+
+func (self *InputImpl) PreviousItem() {
+ self.pushKey(self.keys.Universal.PrevItem)
+}
+
+func (self *InputImpl) Wait(milliseconds int) {
+ time.Sleep(time.Duration(milliseconds) * time.Millisecond)
+}
diff --git a/pkg/gui/old_gui_test.go b/pkg/gui/old_gui_test.go
new file mode 100644
index 000000000..12e33432d
--- /dev/null
+++ b/pkg/gui/old_gui_test.go
@@ -0,0 +1,76 @@
+//go:build !windows
+// +build !windows
+
+package gui
+
+import (
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/jesseduffield/lazygit/pkg/integration"
+ "github.com/stretchr/testify/assert"
+)
+
+// Deprecated: this is the old way of running tests. See pkg/gui/gui_test.go for the new way.
+
+// This file is quite similar to integration/main.go. The main difference is that this file is
+// run via `go test` whereas the other is run via `test/lazyintegration/main.go` which provides
+// a convenient gui wrapper around our integration tests. The `go test` approach is better
+// for CI and for running locally in the background to ensure you haven't broken
+// anything while making changes. If you want to visually see what's happening when a test is run,
+// you'll need to take the other approach
+//
+// As for this file, to run an integration test, e.g. for test 'commit', go:
+// go test pkg/gui/old_gui_test.go -run /commit
+//
+// To update a snapshot for an integration test, pass UPDATE_SNAPSHOTS=true
+// UPDATE_SNAPSHOTS=true go test pkg/gui/old_gui_test.go -run /commit
+//
+// integration tests are run in test/integration/<test_name>/actual and the final test does
+// not clean up that directory so you can cd into it to see for yourself what
+// happened when a test fails.
+//
+// To override speed, pass e.g. `SPEED=1` as an env var. Otherwise we start each test
+// at a high speed and then drop down to lower speeds upon each failure until finally
+// trying at the original playback speed (speed 1). A speed of 2 represents twice the
+// original playback speed. Speed may be a decimal.
+
+func TestOld(t *testing.T) {
+ if testing.Short() {
+ t.Skip("Skipping integration tests in short mode")
+ }
+
+ mode := integration.GetModeFromEnv()
+ speedEnv := os.Getenv("SPEED")
+ includeSkipped := os.Getenv("INCLUDE_SKIPPED") != ""
+
+ parallelTotal := tryConvert(os.Getenv("PARALLEL_TOTAL"), 1)
+ parallelIndex := tryConvert(os.Getenv("PARALLEL_INDEX"), 0)
+ testNumber := 0
+
+ err := integration.RunTests(
+ t.Logf,
+ runCmdHeadless,
+ func(test *integration.Test, f func(*testing.T) error) {
+ defer func() { testNumber += 1 }()
+ if testNumber%parallelTotal != parallelIndex {
+ return
+ }
+
+ t.Run(test.Name, func(t *testing.T) {
+ err := f(t)
+ assert.NoError(t, err)
+ })
+ },
+ mode,
+ speedEnv,
+ func(t *testing.T, expected string, actual string, prefix string) {
+ t.Helper()
+ assert.Equal(t, expected, actual, fmt.Sprintf("Unexpected %s. Expected:\n%s\nActual:\n%s\n", prefix, expected, actual))
+ },
+ includeSkipped,
+ )
+
+ assert.NoError(t, err)
+}
diff --git a/pkg/gui/test_mode.go b/pkg/gui/test_mode.go
new file mode 100644
index 000000000..88e42e440
--- /dev/null
+++ b/pkg/gui/test_mode.go
@@ -0,0 +1,63 @@
+package gui
+
+import (
+ "fmt"
+ "log"
+ "time"
+
+ "github.com/jesseduffield/gocui"
+ "github.com/jesseduffield/lazygit/pkg/integration"
+ "github.com/jesseduffield/lazygit/pkg/utils"
+)
+
+func (gui *Gui) handleTestMode() {
+ if integration.PlayingIntegrationTest() {
+ test, ok := integration.CurrentIntegrationTest()
+
+ if !ok {
+ panic(fmt.Sprintf("test %s not found", integration.IntegrationTestName()))
+ }
+
+ go func() {
+ time.Sleep(time.Millisecond * 100)
+
+ test.Run(
+ &integration.ShellImpl{},
+ &InputImpl{g: gui.g, keys: gui.Config.GetUserConfig().Keybinding},
+ &AssertImpl{gui: gui},
+ gui.c.UserConfig.Keybinding,
+ )
+
+ gui.g.Update(func(*gocui.Gui) error {
+ return gocui.ErrQuit
+ })
+
+ time.Sleep(time.Second * 1)
+
+ log.Fatal("gocui should have already exited")
+ }()
+
+ go utils.Safe(func() {
+ time.Sleep(time.Second * 40)
+ log.Fatal("40 seconds is up, lazygit recording took too long to complete")
+ })
+ }
+
+ if integration.Replaying() {
+ gui.g.RecordingConfig = gocui.RecordingConfig{
+ Speed: integration.GetRecordingSpeed(),
+ Leeway: 100,
+ }
+
+ var err error
+ gui.g.Recording, err = integration.LoadRecording()
+ if err != nil {
+ panic(err)
+ }
+
+ go utils.Safe(func() {
+ time.Sleep(time.Second * 40)
+ log.Fatal("40 seconds is up, lazygit recording took too long to complete")
+ })
+ }
+}
diff --git a/pkg/integration/env.go b/pkg/integration/env.go
new file mode 100644
index 000000000..7cdc72267
--- /dev/null
+++ b/pkg/integration/env.go
@@ -0,0 +1,46 @@
+package integration
+
+import (
+ "os"
+
+ "github.com/jesseduffield/generics/slices"
+ "github.com/jesseduffield/lazygit/pkg/integration/types"
+)
+
+func Headless() bool {
+ return os.Getenv("HEADLESS") != ""
+}
+
+// NEW integration test format stuff
+
+func IntegrationTestName() string {
+ return os.Getenv("LAZYGIT_TEST_NAME")
+}
+
+func CurrentIntegrationTest() (types.Test, bool) {
+ if !PlayingIntegrationTest() {
+ return nil, false
+ }
+
+ return slices.Find(Tests, func(test types.Test) bool {
+ return test.Name() == IntegrationTestName()
+ })
+}
+
+func PlayingIntegrationTest() bool {
+ return IntegrationTestName() != ""
+}
+
+// OLD integration test format stuff
+
+func Replaying() bool {
+ return os.Getenv("REPLAY_EVENTS_FROM") != ""
+}
+
+func RecordingEvents() bool {
+ return recordEventsTo() != ""
+}
+
+func recordEventsTo() string {
+ return os.Getenv("RECORD_EVENTS_TO")
+}
diff --git a/pkg/integration/integration.go b/pkg/integration/integration.go
index 4172f3e49..853dae0d9 100644
--- a/pkg/integration/integration.go
+++ b/pkg/integration/integration.go
@@ -1,72 +1,29 @@
package integration
import (
- "encoding/json"
"errors"
"fmt"
"io/ioutil"
- "log"
"os"
"os/exec"
"path/filepath"
- "strconv"
- "strings"
"testing"
- "github.com/jesseduffield/generics/slices"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
- "github.com/jesseduffield/lazygit/pkg/secureexec"
+ "github.com/jesseduffield/lazygit/pkg/integration/integration_tests"
+ "github.com/jesseduffield/lazygit/pkg/integration/types"
)
-// This package is for running our integration test suite. See docs/Integration_Tests.md for more info
+// this is the integration runner for the new and improved integration interface
-type Test struct {
- Name string `json:"name"`
- Speed float64 `json:"speed"`
- Description string `json:"description"`
- ExtraCmdArgs string `json:"extraCmdArgs"`
- Skip bool `json:"skip"`
-}
-
-type Mode int
-
-const (
- // default: for when we're just running a test and comparing to the snapshot
- TEST = iota
- // for when we want to record a test and set the snapshot based on the result
- RECORD
- // when we just want to use the setup of the test for our own sandboxing purposes.
- // This does not record the session and does not create/update snapshots
- SANDBOX
- // running a test but updating the snapshot
- UPDATE_SNAPSHOT
-)
-
-func GetModeFromEnv() Mode {
- switch os.Getenv("MODE") {
- case "record":
- return RECORD
- case "", "test":
- return TEST
- case "updateSnapshot":
- return UPDATE_SNAPSHOT
- case "sandbox":
- return SANDBOX
- default:
- log.Fatalf("unknown test mode: %s, must be one of [test, record, update, sandbox]", os.Getenv("MODE"))
- panic("unreachable")
- }
-}
+// re-exporting this so that clients only need to import one package
+var Tests = integration_tests.Tests
-// this function is used by both `go test` and from our lazyintegration gui, but
-// errors need to be handled differently in each (for example go test is always
-// working with *testing.T) so we pass in any differences as args here.
-func RunTests(
+func RunTestsNew(
logf func(format string, formatArgs ...interface{}),
runCmd func(cmd *exec.Cmd) error,
- fnWrapper func(test *Test, f func(*testing.T) error),
+ fnWrapper func(test types.Test, f func(*testing.T) error),
mode Mode,
- speedEnv string,
onFail func(t *testing.T, expected string, actual string, prefix string),
includeSkipped bool,
) error {
@@ -76,7 +33,7 @@ func RunTests(
return err
}
- testDir := filepath.Join(rootDir, "test", "integration")
+ testDir := filepath.Join(rootDir, "test", "integration_new")
osCommand := oscommands.NewDummyOSCommand()
err = osCommand.Cmd.New("go build -o " + tempLazygitPath()).Run()
@@ -84,115 +41,94 @@ func RunTests(
return err
}
- tests, err := LoadTests(testDir)
- if err != nil {
- return err
- }
-
- for _, test := range tests {
+ for _, test := range Tests {
test := test
fnWrapper(test, func(t *testing.T) error { //nolint: thelper
- if test.Skip && !includeSkipped {
- logf("skipping test: %s", test.Name)
+ if test.Skip() && !includeSkipped {
+ logf("skipping test: %s", test.Name())
return nil
}
- speeds := getTestSpeeds(test.Speed, mode, speedEnv)
- testPath := filepath.Join(testDir, test.Name)
+ testPath := filepath.Join(testDir, test.Name())
+
actualDir := filepath.Join(testPath, "actual")
expectedDir := filepath.Join(testPath, "expected")
actualRepoDir := filepath.Join(actualDir, "repo")
logf("path: %s", testPath)
- for i, speed := range speeds {
- if mode != SANDBOX && mode != RECORD {
- logf("%s: attempting test at speed %f\n", test.Name, speed)
- }
+ findOrCreateDir(testPath)
+ prepareIntegrationTestDir(actualDir)
+ findOrCreateDir(actualRepoDir)
+ err := createFixtureNew(test, actualRepoDir, rootDir)
+ if err != nil {
+ return err
+ }
+
+ configDir := filepath.Join(testPath, "used_config")
- findOrCreateDir(testPath)
- prepareIntegrationTestDir(actualDir)
- findOrCreateDir(actualRepoDir)
- err := createFixture(testPath, actualRepoDir)
+ cmd, err := getLazygitCommandNew(test, testPath, rootDir)
+ if err != nil {
+ return err
+ }
+
+ err = runCmd(cmd)
+ if err != nil {
+ return err
+ }
+
+ if mode == UPDATE_SNAPSHOT {
+ // create/update snapshot
+ err = oscommands.CopyDir(actualDir, expectedDir)
if err != nil {
return err
}
- configDir := filepath.Join(testPath, "used_config")
+ if err := renameSpecialPaths(expectedDir); err != nil {
+ return err
+ }
- cmd, err := getLazygitCommand(testPath, rootDir, mode, speed, test.ExtraCmdArgs)
- if err != nil {
+ logf("%s", "updated snapshot")
+ } else {
+ if err := validateSameRepos(expectedDir, actualDir); err != nil {
return err
}
- err = runCmd(cmd)
+ // iterate through each repo in the expected dir and comparet to the corresponding repo in the actual dir
+ expectedFiles, err := ioutil.ReadDir(expectedDir)
if err != nil {
return err
}
- if mode == UPDATE_SNAPSHOT || mode == RECORD {
- // create/update snapshot
- err = oscommands.CopyDir(actualDir, expectedDir)
- if err != nil {
- return err
+ for _, f := range expectedFiles {
+ if !f.IsDir() {
+ return errors.New("unexpected file (as opposed to directory) in integration test 'expected' directory")
}
- if err := renameSpecialPaths(expectedDir); err != nil {
- return err
- }
+ // get corresponding file name from actual dir
+ actualRepoPath := filepath.Join(actualDir, f.Name())
+ expectedRepoPath := filepath.Join(expectedDir, f.Name())
- logf("%s", "updated snapshot")
- } else {
- if err := validateSameRepos(expectedDir, actualDir); err != nil {
- return err
- }
-
- // iterate through each repo in the expected dir and comparet to the corresponding repo in the actual dir
- expectedFiles, err := ioutil.ReadDir(expectedDir)
+ actualRepo, expectedRepo, err := generateSnapshots(actualRepoPath, expectedRepoPath)
if err != nil {
return err
}
- success := true
- for _, f := range expectedFiles {
- if !f.IsDir() {
- return errors.New("unexpected file (as opposed to directory) in integration test 'expected' directory")
- }
-
- // get corresponding file name from actual dir
- actualRepoPath := filepath.Join(actualDir, f.Name())
- expectedRepoPath := filepath.Join(expectedDir, f.Name())
-
- actualRepo, expectedRepo, err := generateSnapshots(actualRepoPath, expectedRepoPath)
+ if expectedRepo != actualRepo {
+ // get the log file and print it
+ bytes, err := ioutil.ReadFile(filepath.Join(configDir, "development.log"))
if err != nil {
return err
}
+ logf("%s", string(bytes))
- if expectedRepo != actualRepo {
- success = false
- // if the snapshot doesn't match and we haven't tried all playback speeds different we'll retry at a slower speed
- if i < len(speeds)-1 {
- break
- }
-
- // get the log file and print it
- bytes, err := ioutil.ReadFile(filepath.Join(configDir, "development.log"))
- if err != nil {
- return err
- }
- logf("%s", string(bytes))
-
- onFail(t, expectedRepo, actualRepo, f.Name())
- }
- }
-
- if success {
- logf("%s: success at speed %f\n", test.Name, speed)
- break
+ onFail(t, expectedRepo, actualRepo, f.Name())
}
}
}
+ logf("test passed: %s", test.Name())
+
return nil
})
}
@@ -200,344 +136,35 @@ func RunTests(
return nil
}
-// validates that the actual and expected dirs have the same repo names (doesn't actually check the contents of the repos)
-func validateSameRepos(expectedDir string, actualDir string) error {
- // iterate through each repo in the expected dir and compare to the corresponding repo in the actual dir
- expectedFiles, err := ioutil.ReadDir(expectedDir)
- if err != nil {
- return err
- }
-
- var actualFiles []os.FileInfo
- actualFiles, err = ioutil.ReadDir(actualDir)
- if err != nil {
- return err
- }
-
- expectedFileNames := slices.Map(expectedFiles, getFileName)
- actualFileNames := slices.Map(actualFiles, getFileName)
- if !slices.Equal(expectedFileNames, actualFileNames) {
- return fmt.Errorf("expected and actual repo dirs do not match: expected: %s, actual: %s", expectedFileNames, actualFileNames)
- }
-
- return nil
-}
-
-func getFileName(f os.FileInfo) string {
- return f.Name()
-}
-
-func prepareIntegrationTestDir(actualDir string) {
- // remove contents of integration test directory
- dir, err := ioutil.ReadDir(actualDir)
- if err != nil {
- if os.IsNotExist(err) {
- err = os.Mkdir(actualDir, 0o777)
- if err != nil {
- panic(err)
- }
- } else {
- panic(err)
- }
- }
- for _, d := range dir {
- os.RemoveAll(filepath.Join(actualDir, d.Name()))
- }
-}
-
-func GetRootDirectory() string {
- path, err := os.Getwd()
- if err != nil {
+func createFixtureNew(test types.Test, actualDir string, rootDir string) error {
+ if err := os.Chdir(actualDir); err != nil {
panic(err)
}
- for {
- _, err := os.Stat(filepath.Join(path, ".git"))
+ shell := &ShellImpl{}
+ shell.RunCommand("git init")
+ shell.RunCommand(`git config user.email "CI@example.com"`)
+ shell.RunCommand(`git config user.name "CI"`)
- if err == nil {
- return path
- }
+ test.SetupRepo(shell)
- if !os.IsNotExist(err) {
- panic(err)
- }
-
- path = filepath.Dir(path)
-
- if path == "/" {
- log.Fatal("must run in lazygit folder or child folder")
- }
- }
-}
-
-func createFixture(testPath, actualDir string) error {
- bashScriptPath := filepath.Join(testPath, "setup.sh")
- cmd := secureexec.Command("bash", bashScriptPath, actualDir)
-
- if output, err := cmd.CombinedOutput(); err != nil {
- return errors.New(string(output))
- }
-
- return nil
-}
-
-func tempLazygitPath() string {
- return filepath.Join("/tmp", "lazygit", "test_lazygit")
-}
-
-func getTestSpeeds(testStartSpeed float64, mode Mode, speedStr string) []float64 {
- if mode != TEST {
- // have to go at original speed if updating snapshots in case we go to fast and create a junk snapshot
- return []float64{1.0}
- }
-
- if speedStr != "" {
- speed, err := strconv.ParseFloat(speedStr, 64)
- if err != nil {
- panic(err)
- }
- return []float64{speed}
- }
-
- // default is 10, 5, 1
- startSpeed := 10.0
- if testStartSpeed != 0 {
- startSpeed = testStartSpeed
- }
- speeds := []float64{startSpeed}
- if startSpeed > 5 {
- speeds = append(speeds, 5)
- }
- speeds = append(speeds, 1, 1)
-
- return speeds
-}
-
-func LoadTests(testDir string) ([]*Test, error) {
- paths, err := filepath.Glob(filepath.Join(testDir, "/*/test.json"))
- if err != nil {
- return nil, err
- }
-
- tests := make([]*Test, len(paths))
-
- for i, path := range paths {
- data, err := ioutil.ReadFile(path)
- if err != nil {
- return nil, err
- }
-
- test := &Test{}
-
- err = json.Unmarshal(data, test)
- if err != nil {
- return nil, err
- }
-
- test.Name = strings.TrimPrefix(filepath.Dir(path), testDir+"/")
-
- tests[i] = test
- }
-
- return tests, nil
-}