mirror of
https://github.com/jesseduffield/lazygit.git
synced 2024-11-24 08:52:21 +02:00
remove legacy integration tests
This commit is contained in:
parent
f82f4f6dbc
commit
8b5d59c238
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
@ -46,36 +46,6 @@ jobs:
|
||||
# we're passing -short so that we skip the integration tests, which will be run in parallel below
|
||||
run: |
|
||||
go test ./... -short
|
||||
integration-tests-old:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
parallelism: [5]
|
||||
index: [0,1,2,3,4]
|
||||
name: "Integration Tests (Old pattern) (${{ matrix.index }}/${{ matrix.parallelism }})"
|
||||
env:
|
||||
GOFLAGS: -mod=vendor
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.18.x
|
||||
- name: Cache build
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{runner.os}}-go-${{hashFiles('**/go.sum')}}-test
|
||||
restore-keys: |
|
||||
${{runner.os}}-go-
|
||||
- name: Test code
|
||||
# for file.allow thing see https://vielmetti.typepad.com/logbook/2022/10/git-security-fixes-lead-to-fatal-transport-file-not-allowed-error-in-ci-systems-cve-2022-39253.html
|
||||
run: |
|
||||
git config --global protocol.file.allow always && PARALLEL_TOTAL=${{ matrix.parallelism }} PARALLEL_INDEX=${{ matrix.index }} go test pkg/integration/deprecated/*.go
|
||||
integration-tests:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Integration Tests"
|
||||
|
9
.gitignore
vendored
9
.gitignore
vendored
@ -35,14 +35,7 @@ lazygit.exe
|
||||
|
||||
test/git_server/data
|
||||
|
||||
# we'll scrap these lines once we've fully moved over to the new integration test approach
|
||||
test/integration/*/actual/
|
||||
test/integration/*/used_config/
|
||||
# these sample hooks waste too much space
|
||||
test/integration/*/expected/**/hooks/
|
||||
test/integration/*/expected_remote/**/hooks/
|
||||
|
||||
test/integration_new/**
|
||||
test/integration/**
|
||||
|
||||
oryxBuildBinary
|
||||
__debug_bin
|
||||
|
@ -17,11 +17,6 @@ Usage:
|
||||
If you pass no test names, it runs all tests
|
||||
Accepted environment variables:
|
||||
KEY_PRESS_DELAY (e.g. 200): the number of milliseconds to wait between keypresses
|
||||
MODE:
|
||||
* ask (default): if a snapshot test fails, asks if you want to update the snapshot
|
||||
* check: if a snapshot test fails, exits with an error
|
||||
* update: if a snapshot test fails, updates the snapshot
|
||||
* sandbox: uses the test's setup step to run the test in a sandbox where you can do whatever you want
|
||||
|
||||
TUI mode:
|
||||
> go run cmd/integration_test/main.go tui
|
||||
|
@ -52,7 +52,7 @@ There are three ways to invoke a test:
|
||||
|
||||
1. go run cmd/integration_test/main.go cli [--slow or --sandbox] [testname or testpath...]
|
||||
2. go run cmd/integration_test/main.go tui
|
||||
3. go test pkg/integration/clients/go_test.go
|
||||
3. go test pkg/integration/clients/*.go
|
||||
|
||||
The first, the test runner, is for directly running a test from the command line. If you pass no arguments, it runs all tests.
|
||||
The second, the TUI, is for running tests from a terminal UI where it's easier to find a test and run it without having to copy it's name and paste it into the terminal. This is the easiest approach by far.
|
||||
@ -62,7 +62,7 @@ The name of a test is based on its path, so the name of the test at `pkg/integra
|
||||
|
||||
You can pass the KEY_PRESS_DELAY env var to the test runner in order to set a delay in milliseconds between keypresses, which helps for watching a test at a realistic speed to understand what it's doing. Or you can pass the '--slow' flag which sets a pre-set 'slow' key delay. In the tui you can press 't' to run the test in slow mode.
|
||||
|
||||
The resultant repo will be stored in `test/integration_new`, so if you're not sure what went wrong you can go there and inspect the repo.
|
||||
The resultant repo will be stored in `test/integration`, so if you're not sure what went wrong you can go there and inspect the repo.
|
||||
|
||||
### Running tests in VSCode
|
||||
|
||||
@ -78,21 +78,3 @@ The test will run in a VSCode terminal:
|
||||
Say you want to do a manual test of how lazygit handles merge-conflicts, but you can't be bothered actually finding a way to create merge conflicts in a repo. To make your life easier, you can simply run a merge-conflicts test in sandbox mode, meaning the setup step is run for you, and then instead of the test driving the lazygit session, you're allowed to drive it yourself.
|
||||
|
||||
To run a test in sandbox mode you can press 's' on a test in the test TUI or in the test runner pass the --sandbox argument.
|
||||
|
||||
## Migration process
|
||||
|
||||
You can watch how to migrate tests in this youtube [video](https://youtu.be/cJtOJu6-HcA).
|
||||
|
||||
At the time of writing, most tests are created under an old approach, where you would record yourself in a lazygit session and then the test would replay the keybindings with the same timestamps. This old approach is great for writing tests quickly, but is much harder to maintain. It has to rely on snapshots to determining if a test passes or fails, and can't do assertions along the way. It's also harder to grok what's the intention behind certain actions that take place within the test (e.g. was the recorder intentionally switching to another panel or was that just a misclick?).
|
||||
|
||||
At the moment, all the deprecated test code lives in pkg/integration/deprecated. Hopefully in the very near future we migrate everything across so that we don't need to maintain two systems.
|
||||
|
||||
We should never write any new tests under the old method, and if a given test breaks because of new functionality, it's best to simply rewrite it under the new approach. If you want to run a test for the sake of watching what it does so that you can transcribe it into the new approach, you can run:
|
||||
|
||||
```
|
||||
go run pkg/integration/deprecated/cmd/tui/main.go
|
||||
```
|
||||
|
||||
The tests in the old format live in test/integration. In the old format, test definitions are co-located with snapshots. The setup step is done in a `setup.sh` shell script and the `recording.json` file contains the recorded keypresses to be replayed during the test.
|
||||
|
||||
If you have rewritten an integration test under the new pattern, be sure to delete the old integration test directory.
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
package clients
|
||||
|
||||
// this is the new way of running tests. See pkg/integration/integration_tests/commit.go
|
||||
// for an example
|
||||
// This file allows you to use `go test` to run integration tests.
|
||||
// See See pkg/integration/README.md for more info.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -137,7 +137,7 @@ func RunTUI() {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := secureexec.Command("sh", "-c", fmt.Sprintf("code test/integration_new/%s", currentTest.Name()))
|
||||
cmd := secureexec.Command("sh", "-c", fmt.Sprintf("code test/integration/%s", currentTest.Name()))
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package components
|
||||
import "path/filepath"
|
||||
|
||||
// convenience struct for easily getting directories within our test directory.
|
||||
// We have one test directory for each test, found in test/integration_new.
|
||||
// We have one test directory for each test, found in test/integration.
|
||||
type Paths struct {
|
||||
// e.g. test/integration/test_name
|
||||
root string
|
||||
|
@ -1,65 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/deprecated"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// Deprecated: This file is part of the old way of doing things.
|
||||
|
||||
// see https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md
|
||||
// This file can be invoked directly, but you might find it easier to go through
|
||||
// test/lazyintegration/main.go, which provides a convenient gui wrapper to integration tests.
|
||||
//
|
||||
// If invoked directly, you can specify a test by passing it as the first argument.
|
||||
// You can also specify that you want to record a test by passing MODE=record
|
||||
// as an env var.
|
||||
|
||||
func main() {
|
||||
mode := deprecated.GetModeFromEnv()
|
||||
speedEnv := os.Getenv("SPEED")
|
||||
includeSkipped := os.Getenv("INCLUDE_SKIPPED") == "true"
|
||||
selectedTestName := os.Args[1]
|
||||
|
||||
err := deprecated.RunTests(
|
||||
log.Printf,
|
||||
runCmdInTerminal,
|
||||
func(test *deprecated.IntegrationTest, f func(*testing.T) error) {
|
||||
if selectedTestName != "" && test.Name != selectedTestName {
|
||||
return
|
||||
}
|
||||
if err := f(nil); err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
},
|
||||
mode,
|
||||
speedEnv,
|
||||
func(_t *testing.T, expected string, actual string, prefix string) { //nolint:thelper
|
||||
assert.Equal(MockTestingT{}, expected, actual, fmt.Sprintf("Unexpected %s. Expected:\n%s\nActual:\n%s\n", prefix, expected, actual))
|
||||
},
|
||||
includeSkipped,
|
||||
)
|
||||
if err != nil {
|
||||
log.Print(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
type MockTestingT struct{}
|
||||
|
||||
func (t MockTestingT) Errorf(format string, args ...interface{}) {
|
||||
fmt.Printf(format, args...)
|
||||
}
|
||||
|
||||
func runCmdInTerminal(cmd *exec.Cmd) error {
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
return cmd.Run()
|
||||
}
|
@ -1,422 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/jesseduffield/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/deprecated"
|
||||
"github.com/jesseduffield/lazygit/pkg/secureexec"
|
||||
)
|
||||
|
||||
// Deprecated. See lazy_integration for the new approach.
|
||||
|
||||
// this program lets you manage integration tests in a TUI. See https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md for more info.
|
||||
|
||||
type App struct {
|
||||
tests []*deprecated.IntegrationTest
|
||||
itemIdx int
|
||||
testDir string
|
||||
editing bool
|
||||
g *gocui.Gui
|
||||
}
|
||||
|
||||
func (app *App) getCurrentTest() *deprecated.IntegrationTest {
|
||||
if len(app.tests) > 0 {
|
||||
return app.tests[app.itemIdx]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (app *App) refreshTests() {
|
||||
app.loadTests()
|
||||
app.g.Update(func(*gocui.Gui) error {
|
||||
listView, err := app.g.View("list")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
listView.Clear()
|
||||
for _, test := range app.tests {
|
||||
fmt.Fprintln(listView, test.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (app *App) loadTests() {
|
||||
tests, err := deprecated.LoadTests(app.testDir)
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
app.tests = tests
|
||||
if app.itemIdx > len(app.tests)-1 {
|
||||
app.itemIdx = len(app.tests) - 1
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
rootDir := deprecated.GetRootDirectory()
|
||||
testDir := filepath.Join(rootDir, "test", "integration")
|
||||
|
||||
app := &App{testDir: testDir}
|
||||
app.loadTests()
|
||||
|
||||
g, err := gocui.NewGui(gocui.OutputTrue, false, gocui.NORMAL, false, gui.RuneReplacements)
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
g.Cursor = false
|
||||
|
||||
app.g = g
|
||||
|
||||
g.SetManagerFunc(app.layout)
|
||||
|
||||
if err := g.SetKeybinding("list", gocui.KeyArrowUp, gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
if app.itemIdx > 0 {
|
||||
app.itemIdx--
|
||||
}
|
||||
listView, err := g.View("list")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
listView.FocusPoint(0, app.itemIdx)
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", 'q', gocui.ModNone, quit); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", 'r', gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := secureexec.Command("sh", "-c", fmt.Sprintf("INCLUDE_SKIPPED=true MODE=record go run pkg/integration/deprecated/cmd/runner/main.go %s", currentTest.Name))
|
||||
app.runSubprocess(cmd)
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", 's', gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := secureexec.Command("sh", "-c", fmt.Sprintf("INCLUDE_SKIPPED=true MODE=sandbox go run pkg/integration/deprecated/cmd/runner/main.go %s", currentTest.Name))
|
||||
app.runSubprocess(cmd)
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", gocui.KeyEnter, gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := secureexec.Command("sh", "-c", fmt.Sprintf("INCLUDE_SKIPPED=true go run pkg/integration/deprecated/cmd/runner/main.go %s", currentTest.Name))
|
||||
app.runSubprocess(cmd)
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", 'u', gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := secureexec.Command("sh", "-c", fmt.Sprintf("INCLUDE_SKIPPED=true MODE=updateSnapshot go run pkg/integration/deprecated/cmd/runner/main.go %s", currentTest.Name))
|
||||
app.runSubprocess(cmd)
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", 't', gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := secureexec.Command("sh", "-c", fmt.Sprintf("INCLUDE_SKIPPED=true SPEED=1 go run pkg/integration/deprecated/cmd/runner/main.go %s", currentTest.Name))
|
||||
app.runSubprocess(cmd)
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", 'o', gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := secureexec.Command("sh", "-c", fmt.Sprintf("code -r %s/%s/test.json", app.testDir, currentTest.Name))
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", 'n', gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// need to duplicate that folder and then re-fetch our tests.
|
||||
dir := app.testDir + "/" + app.getCurrentTest().Name
|
||||
newDir := dir + "_Copy"
|
||||
|
||||
cmd := secureexec.Command("sh", "-c", fmt.Sprintf("cp -r %s %s", dir, newDir))
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
app.loadTests()
|
||||
|
||||
app.refreshTests()
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", 'm', gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
app.editing = true
|
||||
if _, err := g.SetCurrentView("editor"); err != nil {
|
||||
return err
|
||||
}
|
||||
editorView, err := g.View("editor")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
editorView.Clear()
|
||||
fmt.Fprint(editorView, currentTest.Name)
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("list", 'd', gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
dir := app.testDir + "/" + app.getCurrentTest().Name
|
||||
|
||||
cmd := secureexec.Command("sh", "-c", fmt.Sprintf("rm -rf %s", dir))
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
app.refreshTests()
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("editor", gocui.KeyEnter, gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
app.editing = false
|
||||
if _, err := g.SetCurrentView("list"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
editorView, err := g.View("editor")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dir := app.testDir + "/" + app.getCurrentTest().Name
|
||||
newDir := app.testDir + "/" + editorView.Buffer()
|
||||
|
||||
cmd := secureexec.Command("sh", "-c", fmt.Sprintf("mv %s %s", dir, newDir))
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
editorView.Clear()
|
||||
|
||||
app.refreshTests()
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
if err := g.SetKeybinding("editor", gocui.KeyEsc, gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
app.editing = false
|
||||
if _, err := g.SetCurrentView("list"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
err = g.MainLoop()
|
||||
g.Close()
|
||||
switch err {
|
||||
case gocui.ErrQuit:
|
||||
return
|
||||
default:
|
||||
log.Panicln(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (app *App) runSubprocess(cmd *exec.Cmd) {
|
||||
if err := gocui.Screen.Suspend(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdout = os.Stdout
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Println(err.Error())
|
||||
}
|
||||
cmd.Stdin = nil
|
||||
cmd.Stderr = nil
|
||||
cmd.Stdout = nil
|
||||
|
||||
fmt.Fprintf(os.Stdout, "\n%s", style.FgGreen.Sprint("press enter to return"))
|
||||
fmt.Scanln() // wait for enter press
|
||||
|
||||
if err := gocui.Screen.Resume(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (app *App) layout(g *gocui.Gui) error {
|
||||
maxX, maxY := g.Size()
|
||||
descriptionViewHeight := 7
|
||||
keybindingsViewHeight := 3
|
||||
editorViewHeight := 3
|
||||
if !app.editing {
|
||||
editorViewHeight = 0
|
||||
} else {
|
||||
descriptionViewHeight = 0
|
||||
keybindingsViewHeight = 0
|
||||
}
|
||||
g.Cursor = app.editing
|
||||
g.FgColor = gocui.ColorGreen
|
||||
listView, err := g.SetView("list", 0, 0, maxX-1, maxY-descriptionViewHeight-keybindingsViewHeight-editorViewHeight-1, 0)
|
||||
if err != nil {
|
||||
if !gocui.IsUnknownView(err) {
|
||||
return err
|
||||
}
|
||||
listView.Highlight = true
|
||||
listView.SelBgColor = gocui.ColorBlue
|
||||
listView.Clear()
|
||||
for _, test := range app.tests {
|
||||
fmt.Fprintln(listView, test.Name)
|
||||
}
|
||||
listView.Title = "Tests"
|
||||
listView.FgColor = gocui.ColorDefault
|
||||
if _, err := g.SetCurrentView("list"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
descriptionView, err := g.SetViewBeneath("description", "list", descriptionViewHeight)
|
||||
if err != nil {
|
||||
if !gocui.IsUnknownView(err) {
|
||||
return err
|
||||
}
|
||||
descriptionView.Title = "Test description"
|
||||
descriptionView.Wrap = true
|
||||
descriptionView.FgColor = gocui.ColorDefault
|
||||
}
|
||||
|
||||
keybindingsView, err := g.SetViewBeneath("keybindings", "description", keybindingsViewHeight)
|
||||
if err != nil {
|
||||
if !gocui.IsUnknownView(err) {
|
||||
return err
|
||||
}
|
||||
keybindingsView.Title = "Keybindings"
|
||||
keybindingsView.Wrap = true
|
||||
keybindingsView.FgColor = gocui.ColorDefault
|
||||
fmt.Fprintln(keybindingsView, "up/down: navigate, enter: run test, u: run test and update snapshots, r: record test, s: sandbox, o: open test config, n: duplicate test, m: rename test, d: delete test, t: run test at original speed")
|
||||
}
|
||||
|
||||
editorView, err := g.SetViewBeneath("editor", "keybindings", editorViewHeight)
|
||||
if err != nil {
|
||||
if !gocui.IsUnknownView(err) {
|
||||
return err
|
||||
}
|
||||
editorView.Title = "Enter Name"
|
||||
editorView.FgColor = gocui.ColorDefault
|
||||
editorView.Editable = true
|
||||
}
|
||||
|
||||
currentTest := app.getCurrentTest()
|
||||
if currentTest == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
descriptionView.Clear()
|
||||
fmt.Fprintf(descriptionView, "Speed: %f. %s", currentTest.Speed, currentTest.Description)
|
||||
|
||||
if err := g.SetKeybinding("list", gocui.KeyArrowDown, gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
|
||||
if app.itemIdx < len(app.tests)-1 {
|
||||
app.itemIdx++
|
||||
}
|
||||
|
||||
listView, err := g.View("list")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
listView.FocusPoint(0, app.itemIdx)
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func quit(g *gocui.Gui, v *gocui.View) error {
|
||||
return gocui.ErrQuit
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package deprecated
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/creack/pty"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// Deprecated.
|
||||
|
||||
// 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 Test(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping integration tests in short mode")
|
||||
}
|
||||
|
||||
mode := 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 := RunTests(
|
||||
t.Logf,
|
||||
runCmdHeadless,
|
||||
func(test *IntegrationTest, 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)
|
||||
}
|
||||
|
||||
func tryConvert(numStr string, defaultVal int) int {
|
||||
num, err := strconv.Atoi(numStr)
|
||||
if err != nil {
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
return num
|
||||
}
|
||||
|
||||
func runCmdHeadless(cmd *exec.Cmd) error {
|
||||
cmd.Env = append(
|
||||
cmd.Env,
|
||||
"HEADLESS=true",
|
||||
"TERM=xterm",
|
||||
)
|
||||
|
||||
// not writing stderr to the pty because we want to capture a panic if
|
||||
// there is one. But some commands will not be in tty mode if stderr is
|
||||
// not a terminal. We'll need to keep an eye out for that.
|
||||
stderr := new(bytes.Buffer)
|
||||
cmd.Stderr = stderr
|
||||
|
||||
// these rows and columns are ignored because internally we use tcell's
|
||||
// simulation screen. However we still need the pty for the sake of
|
||||
// running other commands in a pty.
|
||||
f, err := pty.StartWithSize(cmd, &pty.Winsize{Rows: 100, Cols: 100})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, _ = io.Copy(ioutil.Discard, f)
|
||||
|
||||
if cmd.Wait() != nil {
|
||||
// return an error with the stderr output
|
||||
return errors.New(stderr.String())
|
||||
}
|
||||
|
||||
return f.Close()
|
||||
}
|
@ -1,564 +0,0 @@
|
||||
package deprecated
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// Deprecated: This file is part of the old way of doing things. See pkg/integration/integration.go for the new way
|
||||
|
||||
// This package is for running our integration test suite. See https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md for more info.
|
||||
|
||||
type IntegrationTest 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, updateSnapshot, sandbox]", os.Getenv("MODE"))
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
// 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(
|
||||
logf func(format string, formatArgs ...interface{}),
|
||||
runCmd func(cmd *exec.Cmd) error,
|
||||
fnWrapper func(test *IntegrationTest, f func(*testing.T) error),
|
||||
mode Mode,
|
||||
speedEnv string,
|
||||
onFail func(t *testing.T, expected string, actual string, prefix string),
|
||||
includeSkipped bool,
|
||||
) error {
|
||||
rootDir := GetRootDirectory()
|
||||
err := os.Chdir(rootDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
testDir := filepath.Join(rootDir, "test", "integration")
|
||||
|
||||
osCommand := oscommands.NewDummyOSCommand()
|
||||
err = osCommand.Cmd.New("go build -o " + tempLazygitPath()).Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tests, err := LoadTests(testDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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)
|
||||
return nil
|
||||
}
|
||||
|
||||
speeds := getTestSpeeds(test.Speed, mode, speedEnv)
|
||||
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 := createFixture(testPath, actualRepoDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configDir := filepath.Join(testPath, "used_config")
|
||||
|
||||
cmd, err := getLazygitCommand(testPath, rootDir, mode, speed, test.ExtraCmdArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = runCmd(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if mode == UPDATE_SNAPSHOT || mode == RECORD {
|
||||
// create/update snapshot
|
||||
err = oscommands.CopyDir(actualDir, expectedDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := renameSpecialPaths(expectedDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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)
|
||||
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 err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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 := os.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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
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 {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for {
|
||||
_, err := os.Stat(filepath.Join(path, ".git"))
|
||||
|
||||
if err == nil {
|
||||
return path
|
||||
}
|
||||
|
||||
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, 0.5, 0.5)
|
||||
|
||||
return speeds
|
||||
}
|
||||
|
||||
func LoadTests(testDir string) ([]*IntegrationTest, error) {
|
||||
paths, err := filepath.Glob(filepath.Join(testDir, "/*/test.json"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tests := make([]*IntegrationTest, len(paths))
|
||||
|
||||
for i, path := range paths {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
test := &IntegrationTest{}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func findOrCreateDir(path string) {
|
||||
_, err := os.Stat(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
err = os.MkdirAll(path, 0o777)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// note that we don't actually store this snapshot in the lazygit repo.
|
||||
// Instead we store the whole expected git repo of our test, so that
|
||||
// we can easily change what we want to compare without needing to regenerate
|
||||
// snapshots for each test.
|
||||
func generateSnapshot(dir string) (string, error) {
|
||||
osCommand := oscommands.NewDummyOSCommand()
|
||||
|
||||
_, err := os.Stat(filepath.Join(dir, ".git"))
|
||||
if err != nil {
|
||||
return "git directory not found", nil
|
||||
}
|
||||
|
||||
snapshot := ""
|
||||
|
||||
cmdStrs := []string{
|
||||
`remote show -n origin`, // remote branches
|
||||
// TODO: find a way to bring this back without breaking tests
|
||||
// `ls-remote origin`,
|
||||
`status`, // file tree
|
||||
`log --pretty=%B|%an|%ae -p -1`, // log
|
||||
`tag -n`, // tags
|
||||
`stash list`, // stash
|
||||
`submodule foreach 'git status'`, // submodule status
|
||||
`submodule foreach 'git log --pretty=%B -p -1'`, // submodule log
|
||||
`submodule foreach 'git tag -n'`, // submodule tags
|
||||
`submodule foreach 'git stash list'`, // submodule stash
|
||||
}
|
||||
|
||||
for _, cmdStr := range cmdStrs {
|
||||
// ignoring error for now. If there's an error it could be that there are no results
|
||||
output, _ := osCommand.Cmd.New(fmt.Sprintf("git -C %s %s", dir, cmdStr)).RunWithOutput()
|
||||
|
||||
snapshot += fmt.Sprintf("git %s:\n%s\n", cmdStr, output)
|
||||
}
|
||||
|
||||
snapshot += "files in repo:\n"
|
||||
err = filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if f.IsDir() {
|
||||
if f.Name() == ".git" {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
bytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
relativePath, err := filepath.Rel(dir, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
snapshot += fmt.Sprintf("path: %s\ncontent:\n%s\n", relativePath, string(bytes))
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return snapshot, nil
|
||||
}
|
||||
|
||||
func generateSnapshots(actualDir string, expectedDir string) (string, string, error) {
|
||||
actual, err := generateSnapshot(actualDir)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
// there are a couple of reasons we're not generating the snapshot in expectedDir directly:
|
||||
// Firstly we don't want to have to revert our .git file back to .git_keep.
|
||||
// Secondly, the act of calling git commands like 'git status' actually changes the index
|
||||
// for some reason, and we don't want to leave your lazygit working tree dirty as a result.
|
||||
expectedDirCopyDir := filepath.Join(filepath.Dir(expectedDir), "expected_dir_test")
|
||||
err = oscommands.CopyDir(expectedDir, expectedDirCopyDir)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := os.RemoveAll(expectedDirCopyDir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := restoreSpecialPaths(expectedDirCopyDir); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
expected, err := generateSnapshot(expectedDirCopyDir)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return actual, expected, nil
|
||||
}
|
||||
|
||||
func getPathsToRename(dir string, needle string, contains string) []string {
|
||||
pathsToRename := []string{}
|
||||
|
||||
err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if f.Name() == needle && (contains == "" || strings.Contains(path, contains)) {
|
||||
pathsToRename = append(pathsToRename, path)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return pathsToRename
|
||||
}
|
||||
|
||||
var specialPathMappings = []struct{ original, new, contains string }{
|
||||
// git refuses to track .git or .gitmodules in subdirectories so we need to rename them
|
||||
{".git", ".git_keep", ""},
|
||||
{".gitmodules", ".gitmodules_keep", ""},
|
||||
// we also need git to ignore the contents of our test gitignore files so that
|
||||
// we actually commit files that are ignored within the test.
|
||||
{".gitignore", "lg_ignore_file", ""},
|
||||
// this is the .git/info/exclude file. We're being a little more specific here
|
||||
// so that we don't accidentally mess with some other file named 'exclude' in the test.
|
||||
{"exclude", "lg_exclude_file", ".git/info/exclude"},
|
||||
}
|
||||
|
||||
func renameSpecialPaths(dir string) error {
|
||||
for _, specialPath := range specialPathMappings {
|
||||
for _, path := range getPathsToRename(dir, specialPath.original, specialPath.contains) {
|
||||
err := os.Rename(path, filepath.Join(filepath.Dir(path), specialPath.new))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func restoreSpecialPaths(dir string) error {
|
||||
for _, specialPath := range specialPathMappings {
|
||||
for _, path := range getPathsToRename(dir, specialPath.new, specialPath.contains) {
|
||||
err := os.Rename(path, filepath.Join(filepath.Dir(path), specialPath.original))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getLazygitCommand(testPath string, rootDir string, mode Mode, speed float64, extraCmdArgs string) (*exec.Cmd, error) {
|
||||
osCommand := oscommands.NewDummyOSCommand()
|
||||
|
||||
replayPath := filepath.Join(testPath, "recording.json")
|
||||
templateConfigDir := filepath.Join(rootDir, "test", "default_test_config")
|
||||
actualRepoDir := filepath.Join(testPath, "actual", "repo")
|
||||
|
||||
exists, err := osCommand.FileExists(filepath.Join(testPath, "config"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
templateConfigDir = filepath.Join(testPath, "config")
|
||||
}
|
||||
|
||||
configDir := filepath.Join(testPath, "used_config")
|
||||
|
||||
err = os.RemoveAll(configDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = oscommands.CopyDir(templateConfigDir, configDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cmdStr := fmt.Sprintf("%s -debug --use-config-dir=%s --path=%s %s", tempLazygitPath(), configDir, actualRepoDir, extraCmdArgs)
|
||||
|
||||
cmdObj := osCommand.Cmd.New(cmdStr)
|
||||
cmdObj.AddEnvVars(fmt.Sprintf("SPEED=%f", speed))
|
||||
|
||||
switch mode {
|
||||
case RECORD:
|
||||
cmdObj.AddEnvVars(fmt.Sprintf("RECORD_EVENTS_TO=%s", replayPath))
|
||||
case TEST, UPDATE_SNAPSHOT:
|
||||
cmdObj.AddEnvVars(fmt.Sprintf("REPLAY_EVENTS_FROM=%s", replayPath))
|
||||
}
|
||||
|
||||
return cmdObj.GetCmd(), nil
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -ex; rm -rf repo; mkdir repo; cd repo
|
||||
|
||||
git init
|
||||
|
||||
cat <<EOT >> windowslf.txt
|
||||
asdf
|
||||
asdf
|
||||
EOT
|
||||
|
||||
cat <<EOT >> linuxlf.txt
|
||||
asdf
|
||||
asdf
|
||||
EOT
|
||||
|
||||
cat <<EOT >> bomtest.txt
|
||||
A,B,C,D,E
|
||||
F,G,H,I,J
|
||||
K,L,M,N,O
|
||||
P,Q,R,S,T
|
||||
U,V,W,X,Y
|
||||
Z,1,2,3,4
|
||||
EOT
|
@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -ex; rm -rf repo; mkdir repo; cd repo
|
||||
|
||||
git init
|
||||
git config user.email "test@example.com"
|
||||
git config user.name "Lazygit Tester"
|
||||
|
||||
|
||||
touch foo
|
||||
git add foo
|
||||
git commit -m "init"
|
||||
git branch -a
|
||||
git branch test
|
||||
git branch TEST
|
||||
git checkout TEST
|
||||
git checkout TeST
|
||||
git checkout TesT
|
||||
git checkout TEsT
|
||||
git branch -a
|
@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "test1"
|
||||
sleep 1
|
||||
echo "test2"
|
||||
sleep 1
|
||||
echo "test3"
|
@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -ex; rm -rf repo; mkdir repo; cd repo
|
||||
|
||||
git init
|
||||
git config user.email "test@example.com"
|
||||
git config user.name "Lazygit Tester"
|
||||
|
||||
|
||||
git config gpg.program $(which gpg)
|
||||
git config user.signingkey E304229F # test key
|
||||
git config commit.gpgsign true
|
||||
git config credential.helper store
|
||||
git config credential.helper cache 1
|
||||
|
||||
touch foo
|
||||
git add foo
|
||||
|
||||
touch bar
|
||||
git add bar
|
@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -ex; rm -rf repo; mkdir repo; cd repo
|
||||
|
||||
git init
|
||||
git config user.email "test@example.com"
|
||||
git config user.name "Lazygit Tester"
|
||||
|
||||
|
||||
i=2
|
||||
end=100
|
||||
while [ $i -le $end ]; do
|
||||
echo "file${i}" > file${i}
|
||||
git add file${i}
|
||||
git commit -m file${i}
|
||||
|
||||
i=$(($i+1))
|
||||
done
|
||||
|
||||
echo "unstaged change" > file100
|
@ -1,155 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -ex; rm -rf repo; mkdir repo; cd repo
|
||||
|
||||
git init
|
||||
git config user.email "test@example.com"
|
||||
git config user.name "Lazygit Tester"
|
||||
|
||||
|
||||
function add_spacing {
|
||||
for i in {1..60}
|
||||
do
|
||||
echo "..." >> $1
|
||||
done
|
||||
}
|
||||
|
||||
mkdir directory
|
||||
echo "test1" > directory/file
|
||||
echo "test1" > directory/file2
|
||||
|
||||
|
||||
echo "Here is a story that has been told throuhg the ages" >> file1
|
||||
|
||||
git add file1
|
||||
git add directory
|
||||
git commit -m "first commit"
|
||||
|
||||
git checkout -b feature/cherry-picking
|
||||
|
||||
echo "this is file number 1 that I'm going to cherry-pick" > cherrypicking1
|
||||
echo "this is file number 2 that I'm going to cherry-pick" > cherrypicking2
|
||||
|
||||
git add .
|
||||
|
||||
git commit -am "first commit freshman year"
|
||||
|
||||
echo "this is file number 3 that I'm going to cherry-pick" > cherrypicking3
|
||||
|
||||
git add .
|
||||
|
||||
git commit -am "second commit subway eat fresh"
|
||||
|
||||
echo "this is file number 4 that I'm going to cherry-pick" > cherrypicking4
|
||||
|
||||
git add .
|
||||
|
||||
git commit -am "third commit fresh"
|
||||
|
||||
echo "this is file number 5 that I'm going to cherry-pick" > cherrypicking5
|
||||
|
||||
git add .
|
||||
|
||||
git commit -am "fourth commit cool"
|
||||
|
||||
echo "this is file number 6 that I'm going to cherry-pick" > cherrypicking6
|
||||
|
||||
git add .
|
||||
|
||||
git commit -am "fifth commit nice"
|
||||
|
||||
echo "this is file number 7 that I'm going to cherry-pick" > cherrypicking7
|
||||
|
||||
git add .
|
||||
|
||||
git commit -am "sixth commit haha"
|
||||
|
||||
echo "this is file number 8 that I'm going to cherry-pick" > cherrypicking8
|
||||
|
||||
git add .
|
||||
|
||||
git commit -am "seventh commit yeah"
|
||||
|
||||
echo "this is file number 9 that I'm going to cherry-pick" > cherrypicking9
|
||||
|
||||
git add .
|
||||
|
||||
git commit -am "eighth commit woo"
|
||||
|
||||
|
||||
git checkout -b develop
|
||||
echo "once upon a time there was a dog" >> file1
|
||||
add_spacing file1
|
||||
echo "once upon a time there was another dog" >> file1
|
||||
git add file1
|
||||
echo "test2" > directory/file
|
||||
echo "test2" > directory/file2
|
||||
git add directory
|
||||
git commit -m "first commit on develop"
|
||||
|
||||
|
||||
git checkout master
|
||||
echo "once upon a time there was a cat" >> file1
|
||||
add_spacing file1
|
||||
echo "once upon a time there was another cat" >> file1
|
||||
git add file1
|
||||
echo "test3" > directory/file
|
||||
echo "test3" > directory/file2
|
||||
git add directory
|
||||
git commit -m "first commit on master"
|
||||
|
||||
|
||||
git checkout develop
|
||||
echo "once upon a time there was a mouse" >> file3
|
||||
git add file3
|
||||
git commit -m "second commit on develop"
|
||||
|
||||
|
||||
git checkout master
|
||||
echo "once upon a time there was a horse" >> file3
|
||||
git add file3
|
||||
git commit -m "second commit on master"
|
||||
|
||||
|
||||
git checkout develop
|
||||
echo "once upon a time there was a mouse" >> file4
|
||||
git add file4
|
||||
git commit -m "third commit on develop"
|
||||
|
||||
|
||||
git checkout master
|
||||
echo "once upon a time there was a horse" >> file4
|
||||
git add file4
|
||||
git commit -m "third commit on master"
|
||||
|
||||
|
||||
git checkout develop
|
||||
echo "once upon a time there was a mouse" >> file5
|
||||
git add file5
|
||||
git commit -m "fourth commit on develop"
|
||||
|
||||
|
||||
git checkout master
|
||||
echo "once upon a time there was a horse" >> file5
|
||||
git add file5
|
||||
git commit -m "fourth commit on master"
|
||||
|
||||
|
||||
# this is for the autostash feature
|
||||
|
||||
git checkout -b base_branch
|
||||
|
||||
echo "original1\noriginal2\noriginal3" > file
|
||||
git add file
|
||||
git commit -m "file"
|
||||
|
||||
git checkout -b other_branch
|
||||
|
||||
git checkout base_branch
|
||||
|
||||
echo "new1\noriginal2\noriginal3" > file
|
||||
git add file
|
||||
git commit -m "file changed"
|
||||
|
||||
git checkout other_branch
|
||||
|
||||
echo "new2\noriginal2\noriginal3" > file
|
@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -ex; rm -rf repo; mkdir repo; cd repo
|
||||
|
||||
git init
|
||||
git config user.email "test@example.com"
|
||||
git config user.name "Lazygit Tester"
|
||||
|
||||
cp ../extras/pre-commit .git/hooks/pre-commit
|
||||
chmod +x .git/hooks/pre-commit
|
||||
|
||||
echo "file" > file
|
||||
git add file
|
@ -1,22 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -ex; rm -rf repo; mkdir repo; cd repo
|
||||
|
||||
git init
|
||||
git config user.email "test@example.com"
|
||||
git config user.name "Lazygit Tester"
|
||||
|
||||
|
||||
# Add some ansi, unicode, zero width joiner characters
|
||||
cat <<EOT >> charstest.txt
|
||||
ANSI Œ (U+0152 Œ Latin capital ligature OE Latin Extended-A)
|
||||
¥ (0xA5 U+00A5 ¥ yes sign)
|
||||
ƒ (0x83 U+0192 ƒ Latin small letter f with hook)
|
||||
ZWJ https://en.wikipedia.org/wiki/Zero-width_joiner / https://unicode.org/Public/emoji/4.0/emoji-zwj-sequences.txt 👶(👨👦)
|
||||
UNICODE ☆ 🤓 え 术
|
||||
EOT
|
||||
git add charstest.txt
|
||||
git commit -m "Test chars Œ¥ƒ👶👨👦☆ 🤓 え 术👩💻👩🏻💻👩🏽💻👩🏼💻👩🏾💻👩🏿💻👨💻👨🏻💻👨🏼💻👨🏽💻👨🏾💻👨🏿💻 commit"
|
||||
echo "我喜歡編碼" >> charstest.txt
|
||||
echo "நான் குறியீடு விரும்புகிறேன்" >> charstest.txt
|
||||
git add charstest.txt
|
||||
git commit -m "Test chars 我喜歡編碼 நான் குறியீடு விரும்புகிறேன் commit"
|
@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
# For testing subprocesses that require input
|
||||
# Ask the user for login details
|
||||
read -p 'Username: ' user
|
||||
read -sp 'Password: ' pass
|
||||
echo
|
||||
echo Hello $user
|
Loading…
Reference in New Issue
Block a user