From f999bbce7cbe25587cc2c3a8ccb3ccf49fbfc959 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 19 Feb 2023 11:44:17 +1100 Subject: [PATCH] add code generator for creating tests list --- pkg/integration/clients/cli.go | 2 +- pkg/integration/tests/file/gitignore.go | 2 +- .../filter_by_path/{cli.go => cli_arg.go} | 0 .../patch_building/copy_patch_to_clipboard.go | 2 +- pkg/integration/tests/tests.go | 84 ++----------- pkg/integration/tests/tests_gen.go | 76 ++++++++++++ pkg/integration/tests/tests_generator.go | 115 ++++++++++++++++++ 7 files changed, 201 insertions(+), 80 deletions(-) rename pkg/integration/tests/filter_by_path/{cli.go => cli_arg.go} (100%) create mode 100644 pkg/integration/tests/tests_gen.go create mode 100644 pkg/integration/tests/tests_generator.go diff --git a/pkg/integration/clients/cli.go b/pkg/integration/clients/cli.go index 5225f39d1..1030d7690 100644 --- a/pkg/integration/clients/cli.go +++ b/pkg/integration/clients/cli.go @@ -74,7 +74,7 @@ outer: continue outer } } - log.Fatalf("test %s not found. Perhaps you forgot to add it to `pkg/integration/integration_tests/tests.go`?", testName) + log.Fatalf("test %s not found. Perhaps you forgot to add it to `pkg/integration/integration_tests/tests_gen.go`? This can be done by running `go generate ./...` from the Lazygit root. You'll need to ensure that your test name and the file name match (where the test name is in PascalCase and the file name is in snake_case).", testName) } return testsToRun diff --git a/pkg/integration/tests/file/gitignore.go b/pkg/integration/tests/file/gitignore.go index eca835e82..7cbd3bf1e 100644 --- a/pkg/integration/tests/file/gitignore.go +++ b/pkg/integration/tests/file/gitignore.go @@ -5,7 +5,7 @@ import ( . "github.com/jesseduffield/lazygit/pkg/integration/components" ) -var GitIgnore = NewIntegrationTest(NewIntegrationTestArgs{ +var Gitignore = NewIntegrationTest(NewIntegrationTestArgs{ Description: "Verify that we can't ignore the .gitignore file, then ignore/exclude other files", ExtraCmdArgs: "", Skip: false, diff --git a/pkg/integration/tests/filter_by_path/cli.go b/pkg/integration/tests/filter_by_path/cli_arg.go similarity index 100% rename from pkg/integration/tests/filter_by_path/cli.go rename to pkg/integration/tests/filter_by_path/cli_arg.go diff --git a/pkg/integration/tests/patch_building/copy_patch_to_clipboard.go b/pkg/integration/tests/patch_building/copy_patch_to_clipboard.go index 59b38388f..609924a11 100644 --- a/pkg/integration/tests/patch_building/copy_patch_to_clipboard.go +++ b/pkg/integration/tests/patch_building/copy_patch_to_clipboard.go @@ -5,7 +5,7 @@ import ( . "github.com/jesseduffield/lazygit/pkg/integration/components" ) -var BuildPatchAndCopyToClipboard = NewIntegrationTest(NewIntegrationTestArgs{ +var CopyPatchToClipboard = NewIntegrationTest(NewIntegrationTestArgs{ Description: "Create a patch from the commits and copy the patch to clipbaord.", ExtraCmdArgs: "", Skip: true, diff --git a/pkg/integration/tests/tests.go b/pkg/integration/tests/tests.go index 955057649..4af3cb459 100644 --- a/pkg/integration/tests/tests.go +++ b/pkg/integration/tests/tests.go @@ -1,3 +1,5 @@ +//go:generate go run tests_generator.go + package tests import ( @@ -10,80 +12,8 @@ import ( "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazycore/pkg/utils" "github.com/jesseduffield/lazygit/pkg/integration/components" - "github.com/jesseduffield/lazygit/pkg/integration/tests/bisect" - "github.com/jesseduffield/lazygit/pkg/integration/tests/branch" - "github.com/jesseduffield/lazygit/pkg/integration/tests/cherry_pick" - "github.com/jesseduffield/lazygit/pkg/integration/tests/commit" - "github.com/jesseduffield/lazygit/pkg/integration/tests/config" - "github.com/jesseduffield/lazygit/pkg/integration/tests/custom_commands" - "github.com/jesseduffield/lazygit/pkg/integration/tests/diff" - "github.com/jesseduffield/lazygit/pkg/integration/tests/file" - "github.com/jesseduffield/lazygit/pkg/integration/tests/filter_by_path" - "github.com/jesseduffield/lazygit/pkg/integration/tests/interactive_rebase" - "github.com/jesseduffield/lazygit/pkg/integration/tests/misc" - "github.com/jesseduffield/lazygit/pkg/integration/tests/patch_building" - "github.com/jesseduffield/lazygit/pkg/integration/tests/stash" - "github.com/jesseduffield/lazygit/pkg/integration/tests/submodule" - "github.com/jesseduffield/lazygit/pkg/integration/tests/sync" ) -// Here is where we lists the actual tests that will run. When you create a new test, -// be sure to add it to this list. - -var tests = []*components.IntegrationTest{ - misc.ConfirmOnQuit, - bisect.Basic, - bisect.FromOtherBranch, - branch.CheckoutByName, - branch.Delete, - branch.Rebase, - branch.RebaseAndDrop, - branch.RebaseDoesNotAutosquash, - branch.Suggestions, - branch.Reset, - branch.DetachedHead, - cherry_pick.CherryPick, - cherry_pick.CherryPickConflicts, - commit.Commit, - commit.CommitMultiline, - commit.Revert, - commit.NewBranch, - commit.Staged, - commit.Unstaged, - commit.StagedWithoutHooks, - commit.DiscardOldFileChange, - commit.StageRangeOfLines, - custom_commands.Basic, - custom_commands.FormPrompts, - custom_commands.MenuFromCommand, - custom_commands.MenuFromCommandsOutput, - custom_commands.MultiplePrompts, - file.DirWithUntrackedFile, - file.DiscardChanges, - file.DiscardStagedChanges, - file.GitIgnore, - interactive_rebase.AmendMerge, - interactive_rebase.One, - stash.Rename, - stash.Stash, - stash.StashIncludingUntrackedFiles, - config.RemoteNamedStar, - diff.Diff, - diff.DiffAndApplyPatch, - diff.DiffCommits, - diff.IgnoreWhitespace, - sync.FetchPrune, - sync.RenameBranchAndPull, - filter_by_path.CliArg, - filter_by_path.SelectFile, - filter_by_path.TypeFile, - patch_building.BuildPatchAndCopyToClipboard, - submodule.Add, - submodule.Remove, - submodule.Enter, - submodule.Reset, -} - func GetTests() []*components.IntegrationTest { // first we ensure that each test in this directory has actually been added to the above list. testCount := 0 @@ -99,8 +29,8 @@ func GetTests() []*components.IntegrationTest { if err := filepath.Walk(filepath.Join(utils.GetLazyRootDirectory(), "pkg/integration/tests"), func(path string, info os.FileInfo, err error) error { if !info.IsDir() && strings.HasSuffix(path, ".go") { - // ignoring this current file - if filepath.Base(path) == "tests.go" { + // ignoring non-test files + if filepath.Base(path) == "tests.go" || filepath.Base(path) == "tests_gen.go" || filepath.Base(path) == "tests_generator.go" { return nil } @@ -121,13 +51,13 @@ func GetTests() []*components.IntegrationTest { } if len(missingTestNames) > 0 { - panic(fmt.Sprintf("The following tests are missing from the list of tests: %s. You need to add them to `pkg/integration/tests/tests.go`.", strings.Join(missingTestNames, ", "))) + panic(fmt.Sprintf("The following tests are missing from the list of tests: %s. You need to add them to `pkg/integration/tests/tests_gen.go`. Use `go generate ./...` to regenerate the tests list.", strings.Join(missingTestNames, ", "))) } if testCount > len(tests) { - panic("you have not added all of the tests to the tests list in `pkg/integration/tests/tests.go`") + panic("you have not added all of the tests to the tests list in `pkg/integration/tests/tests_gen.go`. Use `go generate ./...` to regenerate the tests list.") } else if testCount < len(tests) { - panic("There are more tests in `pkg/integration/tests/tests.go` than there are test files in the tests directory. Ensure that you only have one test per file and you haven't included the same test twice in the tests list.") + panic("There are more tests in `pkg/integration/tests/tests_gen.go` than there are test files in the tests directory. Ensure that you only have one test per file and you haven't included the same test twice in the tests list. Use `go generate ./...` to regenerate the tests list.") } return tests diff --git a/pkg/integration/tests/tests_gen.go b/pkg/integration/tests/tests_gen.go new file mode 100644 index 000000000..f9b2631a1 --- /dev/null +++ b/pkg/integration/tests/tests_gen.go @@ -0,0 +1,76 @@ +// THIS FILE IS AUTO-GENERATED. You can regenerate it by running `go generate ./...` at the root of the lazygit repo. + +package tests + +import ( + "github.com/jesseduffield/lazygit/pkg/integration/components" + "github.com/jesseduffield/lazygit/pkg/integration/tests/bisect" + "github.com/jesseduffield/lazygit/pkg/integration/tests/branch" + "github.com/jesseduffield/lazygit/pkg/integration/tests/cherry_pick" + "github.com/jesseduffield/lazygit/pkg/integration/tests/commit" + "github.com/jesseduffield/lazygit/pkg/integration/tests/config" + "github.com/jesseduffield/lazygit/pkg/integration/tests/custom_commands" + "github.com/jesseduffield/lazygit/pkg/integration/tests/diff" + "github.com/jesseduffield/lazygit/pkg/integration/tests/file" + "github.com/jesseduffield/lazygit/pkg/integration/tests/filter_by_path" + "github.com/jesseduffield/lazygit/pkg/integration/tests/interactive_rebase" + "github.com/jesseduffield/lazygit/pkg/integration/tests/misc" + "github.com/jesseduffield/lazygit/pkg/integration/tests/patch_building" + "github.com/jesseduffield/lazygit/pkg/integration/tests/stash" + "github.com/jesseduffield/lazygit/pkg/integration/tests/submodule" + "github.com/jesseduffield/lazygit/pkg/integration/tests/sync" +) + +var tests = []*components.IntegrationTest{ + bisect.Basic, + bisect.FromOtherBranch, + branch.CheckoutByName, + branch.Delete, + branch.DetachedHead, + branch.Rebase, + branch.RebaseAndDrop, + branch.RebaseDoesNotAutosquash, + branch.Reset, + branch.Suggestions, + cherry_pick.CherryPick, + cherry_pick.CherryPickConflicts, + commit.Commit, + commit.CommitMultiline, + commit.DiscardOldFileChange, + commit.NewBranch, + commit.Revert, + commit.StageRangeOfLines, + commit.Staged, + commit.StagedWithoutHooks, + commit.Unstaged, + config.RemoteNamedStar, + custom_commands.Basic, + custom_commands.FormPrompts, + custom_commands.MenuFromCommand, + custom_commands.MenuFromCommandsOutput, + custom_commands.MultiplePrompts, + diff.Diff, + diff.DiffAndApplyPatch, + diff.DiffCommits, + diff.IgnoreWhitespace, + file.DirWithUntrackedFile, + file.DiscardChanges, + file.DiscardStagedChanges, + file.Gitignore, + filter_by_path.CliArg, + filter_by_path.SelectFile, + filter_by_path.TypeFile, + interactive_rebase.AmendMerge, + interactive_rebase.One, + misc.ConfirmOnQuit, + patch_building.CopyPatchToClipboard, + stash.Rename, + stash.Stash, + stash.StashIncludingUntrackedFiles, + submodule.Add, + submodule.Enter, + submodule.Remove, + submodule.Reset, + sync.FetchPrune, + sync.RenameBranchAndPull, +} diff --git a/pkg/integration/tests/tests_generator.go b/pkg/integration/tests/tests_generator.go new file mode 100644 index 000000000..ef702221e --- /dev/null +++ b/pkg/integration/tests/tests_generator.go @@ -0,0 +1,115 @@ +//go:build ignore + +// This file is invoked with `go generate ./...` and it generates the tests_gen.go file +// The tests_gen.go file is a list of all the integration tests. +// It's annoying to have to manually add an entry in that file for each test you +// create, so this generator is here to make the process easier. + +package main + +import ( + "bytes" + "fmt" + "go/format" + "io/fs" + "io/ioutil" + "os" + "strings" + + "github.com/samber/lo" +) + +func main() { + code := generateCode() + + formattedCode, err := format.Source(code) + if err != nil { + panic(err) + } + if err := ioutil.WriteFile("tests_gen.go", formattedCode, 0o644); err != nil { + panic(err) + } +} + +func generateCode() []byte { + // traverse parent directory to get all subling directories + directories, err := ioutil.ReadDir("../tests") + if err != nil { + panic(err) + } + + directories = lo.Filter(directories, func(file os.FileInfo, _ int) bool { + // 'shared' is a special folder containing shared test code so we + // ignore it here + return file.IsDir() && file.Name() != "shared" + }) + + var buf bytes.Buffer + fmt.Fprintf(&buf, "// THIS FILE IS AUTO-GENERATED. You can regenerate it by running `go generate ./...` at the root of the lazygit repo.\n\n") + fmt.Fprintf(&buf, "package tests\n\n") + fmt.Fprintf(&buf, "import (\n") + fmt.Fprintf(&buf, "\t\"github.com/jesseduffield/lazygit/pkg/integration/components\"\n") + for _, dir := range directories { + fmt.Fprintf(&buf, "\t\"github.com/jesseduffield/lazygit/pkg/integration/tests/%s\"\n", dir.Name()) + } + fmt.Fprintf(&buf, ")\n\n") + fmt.Fprintf(&buf, "var tests = []*components.IntegrationTest{\n") + for _, dir := range directories { + appendDirTests(dir, &buf) + } + fmt.Fprintf(&buf, "}\n") + + return buf.Bytes() +} + +func appendDirTests(dir fs.FileInfo, buf *bytes.Buffer) { + files, err := ioutil.ReadDir(fmt.Sprintf("../tests/%s", dir.Name())) + if err != nil { + panic(err) + } + + for _, file := range files { + if file.IsDir() || !strings.HasSuffix(file.Name(), ".go") { + continue + } + + testName := snakeToPascal( + strings.TrimSuffix(file.Name(), ".go"), + ) + + fileContents, err := ioutil.ReadFile(fmt.Sprintf("../tests/%s/%s", dir.Name(), file.Name())) + if err != nil { + panic(err) + } + + fileContentsStr := string(fileContents) + + if !strings.Contains(fileContentsStr, "NewIntegrationTest(") { + // the file does not define a test so it probably just contains shared test code + continue + } + + if !strings.Contains(fileContentsStr, fmt.Sprintf("var %s = NewIntegrationTest(NewIntegrationTestArgs{", testName)) { + panic(fmt.Sprintf("expected test %s to be defined in file %s. Perhaps you misspelt it? The name of the test should be the name of the file but converted from snake_case to PascalCase", testName, file.Name())) + } + + fmt.Fprintf(buf, "\t%s.%s,\n", dir.Name(), testName) + } +} + +// thanks ChatGPT +func snakeToPascal(s string) string { + // Split the input string into words. + words := strings.Split(s, "_") + + // Convert the first letter of each word to uppercase and concatenate them. + var builder strings.Builder + for _, w := range words { + if len(w) > 0 { + builder.WriteString(strings.ToUpper(w[:1])) + builder.WriteString(w[1:]) + } + } + + return builder.String() +}