summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2020-10-04 18:41:33 +1100
committerJesse Duffield <jessedduffield@gmail.com>2020-10-10 00:23:01 +1100
commitf76196937a6d4e5dfe86736ab06f521180a0c7ce (patch)
treebfead5cfd07322b6647aaceae047fc5879c2fd35
parentece93e5eef487f6a8455205c7dbb919ccca43647 (diff)
support integration testing
WIP
-rw-r--r--.gitignore3
-rw-r--r--pkg/gui/gui_test.go224
-rw-r--r--pkg/gui/recording.go17
-rw-r--r--test/integration/commit/recording.json226
-rw-r--r--test/integration/commit/snapshot.txt13
-rw-r--r--test/integration/squash/recording.json1
-rw-r--r--test/integration/squash/snapshot.txt42
7 files changed, 521 insertions, 5 deletions
diff --git a/.gitignore b/.gitignore
index 42ef840fe..d6b15ef10 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,4 +25,5 @@ lazygit
!.circleci/
!.github/
-test/git_server/data \ No newline at end of file
+test/git_server/data
+test/integration_test/
diff --git a/pkg/gui/gui_test.go b/pkg/gui/gui_test.go
new file mode 100644
index 000000000..d0a22710a
--- /dev/null
+++ b/pkg/gui/gui_test.go
@@ -0,0 +1,224 @@
+package gui
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "testing"
+
+ "github.com/go-errors/errors"
+ "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
+ "github.com/stretchr/testify/assert"
+)
+
+// To run an integration test, e.g. for test 'commit', go:
+// go test pkg/gui/gui_test.go -run /commit
+//
+// To record keypresses for an integration test, pass RECORD_EVENTS=true like so:
+// RECORD_EVENTS=true go test pkg/gui/gui_test.go -run /commit
+//
+// To update a snapshot for an integration test, pass UPDATE_SNAPSHOT=true
+// UPDATE_SNAPSHOT=true go test pkg/gui/gui_test.go -run /commit
+//
+// When RECORD_EVENTS is true, updates will be updated automatically
+//
+// integration tests are run in test/integration_test 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 failed.
+//
+// TODO: support passing an env var for playback speed, given it's currently pretty fast
+
+type integrationTest struct {
+ name string
+ prepare func() error
+}
+
+func generateSnapshot(t *testing.T) string {
+ osCommand := oscommands.NewDummyOSCommand()
+ cmd := `sh -c "git status; cat ./*; git log --pretty=%B -p"`
+
+ snapshot, err := osCommand.RunCommandWithOutput(cmd)
+ assert.NoError(t, err)
+
+ return snapshot
+}
+
+func findOrCreateDir(path string) {
+ _, err := os.Stat(path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ err = os.MkdirAll(path, 0777)
+ if err != nil {
+ panic(err)
+ }
+ } else {
+ panic(err)
+ }
+ }
+}
+
+func Test(t *testing.T) {
+ tests := []integrationTest{
+ {
+ name: "commit",
+ prepare: createFixture1,
+ },
+ {
+ name: "squash",
+ prepare: createFixture2,
+ },
+ }
+
+ gotoRootDirectory()
+
+ rootDir, err := os.Getwd()
+ if err != nil {
+ panic(err)
+ }
+
+ for _, test := range tests {
+ test := test
+ t.Run(test.name, func(t *testing.T) {
+ testPath := filepath.Join(rootDir, "test", "integration", test.name)
+ findOrCreateDir(testPath)
+
+ replayPath := filepath.Join(testPath, "recording.json")
+ snapshotPath := filepath.Join(testPath, "snapshot.txt")
+
+ err := os.Chdir(rootDir)
+ assert.NoError(t, err)
+
+ prepareIntegrationTestDir()
+
+ err = test.prepare()
+ assert.NoError(t, err)
+
+ record := os.Getenv("RECORD_EVENTS") != ""
+ runLazygit(t, replayPath, record)
+
+ updateSnapshot := os.Getenv("UPDATE_SNAPSHOT") != ""
+
+ actual := generateSnapshot(t)
+
+ if updateSnapshot {
+ err := ioutil.WriteFile(snapshotPath, []byte(actual), 0600)
+ assert.NoError(t, err)
+ }
+
+ expectedBytes, err := ioutil.ReadFile(snapshotPath)
+ assert.NoError(t, err)
+ expected := string(expectedBytes)
+
+ assert.Equal(t, expected, actual, fmt.Sprintf("expected:\n%s\nactual:\n%s\n", expected, actual))
+ })
+ }
+}
+
+func createFixture1() error {
+ cmds := []string{
+ "git init",
+ `sh -c "echo test > myfile"`,
+ }
+
+ return runCommands(cmds)
+}
+
+func createFixture2() error {
+ cmds := []string{
+ "git init",
+ `sh -c "echo test1 > myfile1"`,
+ `git add .`,
+ `git commit -am "myfile1"`,
+ `sh -c "echo test2 > myfile2"`,
+ `git add .`,
+ `git commit -am "myfile2"`,
+ `sh -c "echo test3 > myfile3"`,
+ `git add .`,
+ `git commit -am "myfile3"`,
+ `sh -c "echo test4 > myfile4"`,
+ `git add .`,
+ `git commit -am "myfile4"`,
+ `sh -c "echo test5 > myfile5"`,
+ `git add .`,
+ `git commit -am "myfile5"`,
+ }
+
+ return runCommands(cmds)
+}
+
+func runCommands(cmds []string) error {
+ osCommand := oscommands.NewDummyOSCommand()
+
+ for _, cmd := range cmds {
+ if err := osCommand.RunCommand(cmd); err != nil {
+ return errors.New(fmt.Sprintf("error running command `%s`: %v", cmd, err))
+ }
+ }
+
+ return nil
+}
+
+func gotoRootDirectory() {
+ for {
+ _, err := os.Stat(".git")
+
+ if err == nil {
+ return
+ }
+
+ if !os.IsNotExist(err) {
+ panic(err)
+ }
+
+ if err = os.Chdir(".."); err != nil {
+ panic(err)
+ }
+ }
+}
+
+func runLazygit(t *testing.T, replayPath string, record bool) {
+ osCommand := oscommands.NewDummyOSCommand()
+
+ var cmd *exec.Cmd
+ if record {
+ cmd = osCommand.ExecutableFromString("lazygit")
+ cmd.Env = append(
+ cmd.Env,
+ fmt.Sprintf("RECORD_EVENTS_TO=%s", replayPath),
+ )
+ } else {
+ cmd = osCommand.ExecutableFromString("lazygit")
+ cmd.Env = append(
+ cmd.Env,
+ fmt.Sprintf("REPLAY_EVENTS_FROM=%s", replayPath),
+ )
+ }
+ err := osCommand.RunExecutable(cmd)
+ assert.NoError(t, err)
+}
+
+func prepareIntegrationTestDir() {
+ path := filepath.Join("test", "integration_test")
+
+ // remove contents of integration test directory
+ dir, err := ioutil.ReadDir(path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ err = os.Mkdir(path, 0777)
+ if err != nil {
+ panic(err)
+ }
+ } else {
+ panic(err)
+ }
+ }
+ for _, d := range dir {
+ os.RemoveAll(filepath.Join(path, d.Name()))
+ }
+
+ if err := os.Chdir(path); err != nil {
+ panic(err)
+ }
+}
diff --git a/pkg/gui/recording.go b/pkg/gui/recording.go
index 5e0914303..57bf27948 100644
--- a/pkg/gui/recording.go
+++ b/pkg/gui/recording.go
@@ -9,7 +9,11 @@ import (
)
func recordingEvents() bool {
- return os.Getenv("RECORD_EVENTS") == "true"
+ return recordEventsTo() != ""
+}
+
+func recordEventsTo() string {
+ return os.Getenv("RECORD_EVENTS_TO")
}
func (gui *Gui) timeSinceStart() int64 {
@@ -29,11 +33,14 @@ func (gui *Gui) replayRecordedEvents() {
ticker := time.NewTicker(time.Millisecond)
defer ticker.Stop()
- var leeway int64 = 1000
+ // might need to add leeway if this ends up flakey
+ var leeway int64 = 0
+ // humans are slow so this speeds things up.
+ var speed int64 = 5
for _, event := range events {
for range ticker.C {
- now := gui.timeSinceStart() - leeway
+ now := gui.timeSinceStart()*speed - leeway
if gui.g != nil && now >= event.Timestamp {
gui.g.ReplayedEvents <- *event.Event
break
@@ -70,7 +77,9 @@ func (gui *Gui) saveRecordedEvents() error {
return err
}
- return ioutil.WriteFile("recorded_events.json", jsonEvents, 0600)
+ path := recordEventsTo()
+
+ return ioutil.WriteFile(path, jsonEvents, 0600)
}
func (gui *Gui) recordEvents() {
diff --git a/test/integration/commit/recording.json b/test/integration/commit/recording.json
new file mode 100644
index 000000000..d362b0271
--- /dev/null
+++ b/test/integration/commit/recording.json
@@ -0,0 +1,226 @@
+[
+ {
+ "Timestamp": 41,
+ "Event": {
+ "Type": 1,
+ "Mod": 0,
+ "Key": 0,
+ "Ch": 0,
+ "Width": 0,
+ "Height": 0,
+ "Err": null,
+ "MouseX": 0,
+ "MouseY": 0,
+ "N": 0,
+ "Bytes": null
+ }
+ },
+ {
+ "Timestamp": 1042,
+ "Event": {
+ "Type": 0,
+ "Mod": 0,
+ "Key": 32,
+ "Ch": 0,
+ "Width": 0,
+ "Height": 0,
+ "Err": null,
+ "MouseX": 0,
+ "MouseY": 0,
+ "N": 1,
+ "Bytes": "IA=="
+ }
+ },
+ {
+ "Timestamp": 1602,
+ "Event": {
+ "Type": 0,
+ "Mod": 0,
+ "Key": 0,
+ "Ch": 99,
+ "Width": 0,
+ "Height": 0,
+ "Err": null,
+ "MouseX": 0,
+ "MouseY": 0,
+ "N": 1,
+ "Bytes": "Yw=="
+ }
+ },
+ {
+ "Timestamp": 2010,
+ "Event": {
+ "Type": 0,
+ "Mod": 0,
+ "Key": 0,
+ "Ch": 109,
+ "Width": 0,
+ "Height": 0,
+ "Err": null,
+ "MouseX": 0,
+ "MouseY": 0,
+ "N": 1,
+ "Bytes": "bQ=="
+ }
+ },
+ {
+ "Timestamp": 2170,
+ "Event": {
+ "Type": 0,
+ "Mod": 0,
+ "Key": 0,
+ "Ch": 121,
+ "Width": 0,
+ "Height": 0,
+ "Err": null,
+ "MouseX": 0,
+ "MouseY": 0,
+ "N": 1,
+ "Bytes": "eQ=="
+ }
+ },
+ {
+ "Timestamp": 2234,
+ "Event": {
+ "Type": 0,
+ "Mod": 0,
+ "Key": 32,
+ "Ch": 0,
+ "Width": 0,
+ "Height": 0,
+ "Err": null,
+ "MouseX": 0,
+ "MouseY": 0,
+ "N": 1,
+ "Bytes": "IA=="
+ }
+ },
+ {
+ "Timestamp": 2354,
+ "Event": {
+ "Type": 0,
+ "Mod": 0,
+ "Key": 0,
+ "Ch": 99,
+ "Width": 0,
+ "Height": 0,
+ "Err": null,
+ "MouseX": 0,
+ "MouseY": 0,
+ "N": 1,
+ "Bytes": "Yw=="
+ }
+ },
+ {
+ "Timestamp": 2410,
+ "Event": {
+ "Type": 0,
+ "Mod": 0,
+ "Key": 0,
+ "Ch": 111,
+ "Width": 0,
+ "Height": 0,
+ "Err": null,
+ "MouseX": 0,
+ "MouseY": 0,
+ "N": 1,
+ "Bytes": "bw=="
+ }
+ },
+ {
+ "Timestamp": 2578,
+ "Event": {
+ "Type": 0,
+ "Mod": 0,
+ "Key": 0,
+ "Ch": 109,
+ "Width": 0,
+ "Height": 0,
+ "Err": null,
+ "MouseX": 0,
+ "MouseY": 0,
+ "N": 1,
+ "Bytes": "bQ=="
+ }
+ },
+ {
+ "Timestamp": 2690,
+ "Event": {
+ "Type": 0,
+ "Mod": 0,
+ "Key": 0,
+ "Ch": 109,
+ "Width": 0,
+ "Height": 0,
+ "Err": null,
+ "MouseX": 0,
+ "MouseY": 0,
+ "N": 1,
+ "Bytes": "bQ=="
+ }
+ },
+ {
+ "Timestamp": 2730,
+ "Event": {
+ "Type": 0,
+ "Mod": 0,
+ "Key": 0,
+ "Ch": 105,
+ "Width": 0,
+ "Height": 0,
+ "Err": null,
+ "MouseX": 0,
+ "MouseY": 0,
+ "N": 1,
+ "Bytes": "aQ=="
+ }
+ },
+ {
+ "Timestamp": 2850,
+ "Event": {
+ "Type": 0,
+ "Mod": 0,
+ "Key": 0,
+ "Ch": 116,
+ "Width": 0,
+ "Height": 0,
+ "Err": null,
+ "MouseX": 0,
+ "MouseY": 0,
+ "N": 1,
+ "Bytes": "dA=="
+ }
+ },
+ {
+ "Timestamp": 2954,
+ "Event": {
+ "Type": 0,
+ "Mod": 0,
+ "Key": 13,
+ "Ch": 0,
+ "Width": 0,
+ "Height": 0,
+ "Err": null,
+ "MouseX": 0,
+ "MouseY": 0,
+ "N": 1,
+ "Bytes": "DQ=="
+ }
+ },
+ {
+ "Timestamp": 3625,
+ "Event": {
+ "Type": 0,
+ "Mod": 0,
+ "Key": 0,
+ "Ch": 113,
+ "Width": 0,
+ "Height": 0,
+ "Err": null,
+ "MouseX": 0,
+ "MouseY": 0,
+ "N": 1,
+ "Bytes": "cQ=="
+ }
+ }
+]
diff --git a/test/integration/commit/snapshot.txt b/test/integration/commit/snapshot.txt
new file mode 100644
index 000000000..0c50ae828
--- /dev/null
+++ b/test/integration/commit/snapshot.txt
@@ -0,0 +1,13 @@
+On branch master
+nothing to commit, working tree clean
+test
+my commit
+
+
+diff --git a/myfile b/myfile
+new file mode 100644
+index 0000000..9daeafb
+--- /dev/null
++++ b/myfile
+@@ -0,0 +1 @@
++test
diff --git a/test/integration/squash/recording.json b/test/integration/squash/recording.json
new file mode 100644
index 000000000..5bb4996b7
--- /dev/null
+++ b/test/integration/squash/recording.json
@@ -0,0 +1 @@
+[{"Timestamp":14,"Event":{"Type":1,"Mod":0,"Key":0,"Ch":0,"Width":0,"Height":0,"Err":null,"MouseX":0,"MouseY":0,"N":0,"Bytes":null}},{"Timestamp":482,"Event":{"Type":0,"Mod":0,"Key":65514,"Ch":0,"Width":0,"Height":0,"Err":null,"MouseX":0,"MouseY":0,"N":3,"Bytes":"G09D"}},{"Timestamp":626,"Event":{"Type":0,"Mod":0,"Key":65514,"Ch":0,"Width":0,"Height":0,"Err":null,"MouseX":0,"MouseY":0,"N":3,"Bytes":"G09D"}},{"Timestamp":810,"Event":{"Type":0,"Mod":0,"Key":65516,"Ch":0,"Width":0,"Height":0,"Err":null,"MouseX":0,"MouseY":0,"N":3,"Bytes":"G09C"}},{"Timestamp":937,"Event":{"Type":0,"Mod":0,"Key":65516,"Ch":0,"Width":0,"Height":0,"Err":null,"MouseX":0,"MouseY":0,"N":3,"Bytes":"G09C"}},{"Timestamp":1065,"Event":{"Type":0,"Mod":0,"Key":65516,"Ch":0,"Width":0,"Height":0,"Err":null,"MouseX":0,"MouseY":0,"N":3,"Bytes":"G09C"}},{"Timestamp":1591,"Event":{"Type":0,"Mod":0,"Key":0,"Ch":101,"Width":0,"Height":0,"Err":null,"MouseX":0,"MouseY":0,"N":1,"Bytes":"ZQ=="}},{"Timestamp":2034,"Event":{"Type":0,"Mod":0,"Key":65517,"Ch":0,"Width":0,"Height":0,"Err":null,"MouseX":0,"MouseY":0,"N":3,"Bytes":"G09B"}},{"Timestamp":2243,"Event":{"Type":0,"Mod":0,"Key":0,"Ch":115,"Width":0,"Height":0,"Err":null,"MouseX":0,"MouseY":0,"N":1,"Bytes":"cw=="}},{"Timestamp":2554,"Event":{"Type":0,"Mod":0,"Key":65517,"Ch":0,"Width":0,"Height":0,"Err":null,"MouseX":0,"MouseY":0,"N":3,"Bytes":"G09B"}},{"Timestamp":2803,"Event":{"Type":0,"Mod":0,"Key":0,"Ch":100,"Width":0,"Height":0,"Err":null,"MouseX":0,"MouseY":0,"N":1,"Bytes":"ZA=="}},{"Timestamp":3209,"Event":{"Type":0,"Mod":0,"Key":65517,"Ch":0,"Width":0,"Height":0,"Err":null,"MouseX":0,"MouseY":0,"N":3,"Bytes":"G09B"}},{"Timestamp":3522,"Event":{"Type":0,"Mod":0,"Key":0,"Ch":102,"Width":0,"Height":0,"Err":null,"MouseX":0,"MouseY":0,"N":1,"Bytes":"Zg=="}},{"Timestamp":4066,"Event":{"Type":0,"Mod":0,"Key":0,"Ch":109,"Width":0,"Height":0,"Err":null,"MouseX":0,"MouseY":0,"N":1,"Bytes":"bQ=="}},{"Timestamp":5091,"Event":{"Type":0,"Mod":0,"Key":13,"Ch":0,"Width":0,"Height":0,"Err":null,"MouseX":0,"MouseY":0,"N":1,"Bytes":"DQ=="}},{"Timestamp":5834,"Event":{"Type":0,"Mod":0,"Key":0,"Ch":113,"Width":0,"Height":0,"Err":null,"MouseX":0,"MouseY":0,"N":1,"Bytes":"cQ=="}}] \ No newline at end of file
diff --git a/test/integration/squash/snapshot.txt b/test/integration/squash/snapshot.txt
new file mode 100644
index 000000000..445bf0f96
--- /dev/null
+++ b/test/integration/squash/snapshot.txt
@@ -0,0 +1,42 @@
+On branch master
+nothing to commit, working tree clean
+test1
+test2
+test3
+test5
+myfile2
+
+myfile3
+
+
+diff --git a/myfile2 b/myfile2
+new file mode 100644
+index 0000000..180cf83
+--- /dev/null
++++ b/myfile2
+@@ -0,0 +1 @@
++test2
+diff --git a/myfile3 b/myfile3
+new file mode 100644
+index 0000000..df6b0d2
+--- /dev/null
++++ b/myfile3
+@@ -0,0 +1 @@
++test3
+diff --git a/myfile5 b/myfile5
+new file mode 100644
+index 0000000..4f346f1
+--- /dev/null
++++ b/myfile5
+@@ -0,0 +1 @@
++test5
+myfile1
+
+
+diff --git a/myfile1 b/myfile1
+new file mode 100644
+index 0000000..a5bce3f
+--- /dev/null
++++ b/myfile1
+@@ -0,0 +1 @@
++test1