mirror of
				https://github.com/jesseduffield/lazygit.git
				synced 2025-10-30 23:57:43 +02:00 
			
		
		
		
	Add tests
I can't do my usual "add the tests first, with EXPECTED/ACTUAL sections that document the bug" method here, because the tests would hang without the bug being fixed. We need two different tests here: one where a cherry-picked commit simply becomes empty "by itself", because the change is already present on the destination branch (this was only a problem with git versions older than 2.45), and the other where the cherry-pick stops with conflicts, and the user resolves them such that no changes are left, and then continues the cherry-pick. This would still fail even with git 2.45 or later. The fix is the same for both cases though. The tests show that the selection behavior after skipping an empty cherry-picked commit is not ideal, but since that's only a minor cosmetic problem we don't bother fixing it here.
This commit is contained in:
		| @@ -0,0 +1,99 @@ | ||||
| package cherry_pick | ||||
|  | ||||
| import ( | ||||
| 	"github.com/jesseduffield/lazygit/pkg/config" | ||||
| 	. "github.com/jesseduffield/lazygit/pkg/integration/components" | ||||
| ) | ||||
|  | ||||
| var CherryPickCommitThatBecomesEmpty = NewIntegrationTest(NewIntegrationTestArgs{ | ||||
| 	Description:  "Cherry-pick a commit that becomes empty at the destination", | ||||
| 	ExtraCmdArgs: []string{}, | ||||
| 	Skip:         false, | ||||
| 	SetupConfig:  func(config *config.AppConfig) {}, | ||||
| 	SetupRepo: func(shell *Shell) { | ||||
| 		shell. | ||||
| 			EmptyCommit("base"). | ||||
| 			CreateFileAndAdd("file1", "change 1\n"). | ||||
| 			CreateFileAndAdd("file2", "change 2\n"). | ||||
| 			Commit("two changes in one commit"). | ||||
| 			NewBranchFrom("branch", "HEAD^"). | ||||
| 			CreateFileAndAdd("file1", "change 1\n"). | ||||
| 			Commit("single change"). | ||||
| 			CreateFileAndAdd("file3", "change 3\n"). | ||||
| 			Commit("unrelated change"). | ||||
| 			Checkout("master") | ||||
| 	}, | ||||
| 	Run: func(t *TestDriver, keys config.KeybindingConfig) { | ||||
| 		t.Views().Branches(). | ||||
| 			Focus(). | ||||
| 			Lines( | ||||
| 				Contains("master").IsSelected(), | ||||
| 				Contains("branch"), | ||||
| 			). | ||||
| 			SelectNextItem(). | ||||
| 			PressEnter() | ||||
|  | ||||
| 		t.Views().SubCommits(). | ||||
| 			IsFocused(). | ||||
| 			Lines( | ||||
| 				Contains("unrelated change").IsSelected(), | ||||
| 				Contains("single change"), | ||||
| 				Contains("base"), | ||||
| 			). | ||||
| 			Press(keys.Universal.RangeSelectDown). | ||||
| 			Press(keys.Commits.CherryPickCopy). | ||||
| 			Tap(func() { | ||||
| 				t.Views().Information().Content(Contains("2 commits copied")) | ||||
| 			}) | ||||
|  | ||||
| 		t.Views().Commits(). | ||||
| 			Focus(). | ||||
| 			Lines( | ||||
| 				Contains("two changes in one commit").IsSelected(), | ||||
| 				Contains("base"), | ||||
| 			). | ||||
| 			Press(keys.Commits.PasteCommits). | ||||
| 			Tap(func() { | ||||
| 				t.ExpectPopup().Alert(). | ||||
| 					Title(Equals("Cherry-pick")). | ||||
| 					Content(Contains("Are you sure you want to cherry-pick the 2 copied commit(s) onto this branch?")). | ||||
| 					Confirm() | ||||
| 			}) | ||||
|  | ||||
| 		if t.Git().Version().IsAtLeast(2, 45, 0) { | ||||
| 			t.Views().Commits(). | ||||
| 				Lines( | ||||
| 					Contains("unrelated change"), | ||||
| 					Contains("single change"), | ||||
| 					Contains("two changes in one commit").IsSelected(), | ||||
| 					Contains("base"), | ||||
| 				). | ||||
| 				SelectPreviousItem() | ||||
|  | ||||
| 			// Cherry-picked commit is empty | ||||
| 			t.Views().Main().Content(DoesNotContain("diff --git")) | ||||
| 		} else { | ||||
| 			t.Views().Commits(). | ||||
| 				// We have a bug with how the selection is updated in this case; normally you would | ||||
| 				// expect the "two changes in one commit" commit to be selected because it was | ||||
| 				// selected before pasting, and we try to maintain that selection. This is broken | ||||
| 				// for two reasons: | ||||
| 				// 1. We increment the selected line index after pasting by the number of pasted | ||||
| 				// commits; this is wrong because we skipped the commit that became empty. So | ||||
| 				// according to this bug, the "base" commit should be selected. | ||||
| 				// 2. We only update the selected line index after pasting if the currently selected | ||||
| 				// commit is not a rebase TODO commit, on the assumption that if it is, we are in a | ||||
| 				// rebase and the cherry-picked commits end up below the selection. In this case, | ||||
| 				// however, we still think we are cherry-picking because the final refresh after the | ||||
| 				// CheckMergeOrRebase in CherryPickHelper.Paste is async and hasn't completed yet; | ||||
| 				// so the "unrelated change" still has a "pick" action. | ||||
| 				// | ||||
| 				// Since this only happens for older git versions, we don't bother fixing it. | ||||
| 				Lines( | ||||
| 					Contains("unrelated change").IsSelected(), | ||||
| 					Contains("two changes in one commit"), | ||||
| 					Contains("base"), | ||||
| 				) | ||||
| 		} | ||||
| 	}, | ||||
| }) | ||||
| @@ -0,0 +1,92 @@ | ||||
| package cherry_pick | ||||
|  | ||||
| import ( | ||||
| 	"github.com/jesseduffield/lazygit/pkg/config" | ||||
| 	. "github.com/jesseduffield/lazygit/pkg/integration/components" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/integration/tests/shared" | ||||
| ) | ||||
|  | ||||
| var CherryPickConflictsEmptyCommitAfterResolving = NewIntegrationTest(NewIntegrationTestArgs{ | ||||
| 	Description:  "Cherry pick commits with conflicts, resolve them so that the commit becomes empty", | ||||
| 	ExtraCmdArgs: []string{}, | ||||
| 	Skip:         false, | ||||
| 	SetupConfig: func(config *config.AppConfig) { | ||||
| 		config.GetUserConfig().Git.LocalBranchSortOrder = "recency" | ||||
| 	}, | ||||
| 	SetupRepo: func(shell *Shell) { | ||||
| 		shared.MergeConflictsSetup(shell) | ||||
| 	}, | ||||
| 	Run: func(t *TestDriver, keys config.KeybindingConfig) { | ||||
| 		t.Views().Branches(). | ||||
| 			Focus(). | ||||
| 			Lines( | ||||
| 				Contains("first-change-branch"), | ||||
| 				Contains("second-change-branch"), | ||||
| 				Contains("original-branch"), | ||||
| 			). | ||||
| 			SelectNextItem(). | ||||
| 			PressEnter() | ||||
|  | ||||
| 		t.Views().SubCommits(). | ||||
| 			IsFocused(). | ||||
| 			TopLines( | ||||
| 				Contains("second-change-branch unrelated change"), | ||||
| 				Contains("second change"), | ||||
| 			). | ||||
| 			Press(keys.Universal.RangeSelectDown). | ||||
| 			Press(keys.Commits.CherryPickCopy) | ||||
|  | ||||
| 		t.Views().Information().Content(Contains("2 commits copied")) | ||||
|  | ||||
| 		t.Views().Commits(). | ||||
| 			Focus(). | ||||
| 			TopLines( | ||||
| 				Contains("first change").IsSelected(), | ||||
| 			). | ||||
| 			Press(keys.Commits.PasteCommits) | ||||
|  | ||||
| 		t.ExpectPopup().Alert(). | ||||
| 			Title(Equals("Cherry-pick")). | ||||
| 			Content(Contains("Are you sure you want to cherry-pick the 2 copied commit(s) onto this branch?")). | ||||
| 			Confirm() | ||||
|  | ||||
| 		t.Common().AcknowledgeConflicts() | ||||
|  | ||||
| 		t.Views().Files(). | ||||
| 			IsFocused(). | ||||
| 			SelectedLine(Contains("file")). | ||||
| 			Press(keys.Universal.Remove) | ||||
|  | ||||
| 		t.ExpectPopup().Menu(). | ||||
| 			Title(Equals("Discard changes")). | ||||
| 			Select(Contains("Discard all changes")). | ||||
| 			Confirm() | ||||
|  | ||||
| 		t.Common().ContinueOnConflictsResolved("cherry-pick") | ||||
|  | ||||
| 		t.Views().Files().IsEmpty() | ||||
|  | ||||
| 		t.Views().Commits(). | ||||
| 			Focus(). | ||||
| 			TopLines( | ||||
| 				// We have a bug with how the selection is updated in this case; normally you would | ||||
| 				// expect the "first change" commit to be selected because it was selected before | ||||
| 				// pasting, and we try to maintain that selection. This is broken for two reasons: | ||||
| 				// 1. We increment the selected line index after pasting by the number of pasted | ||||
| 				// commits; this is wrong because we skipped the commit that became empty. So | ||||
| 				// according to this bug, the "original" commit should be selected. | ||||
| 				// 2. We only update the selected line index after pasting if the currently selected | ||||
| 				// commit is not a rebase TODO commit, on the assumption that if it is, we are in a | ||||
| 				// rebase and the cherry-picked commits end up below the selection. In this case, | ||||
| 				// however, we still think we are cherry-picking because the final refresh after the | ||||
| 				// CheckMergeOrRebase in CherryPickHelper.Paste is async and hasn't completed yet; | ||||
| 				// so the "second-change-branch unrelated change" still has a "pick" action. | ||||
| 				// | ||||
| 				// We don't bother fixing it for now because it's a pretty niche case, and the | ||||
| 				// nature of the problem is only cosmetic. | ||||
| 				Contains("second-change-branch unrelated change").IsSelected(), | ||||
| 				Contains("first change"), | ||||
| 				Contains("original"), | ||||
| 			) | ||||
| 	}, | ||||
| }) | ||||
| @@ -86,7 +86,9 @@ var tests = []*components.IntegrationTest{ | ||||
| 	branch.Suggestions, | ||||
| 	branch.UnsetUpstream, | ||||
| 	cherry_pick.CherryPick, | ||||
| 	cherry_pick.CherryPickCommitThatBecomesEmpty, | ||||
| 	cherry_pick.CherryPickConflicts, | ||||
| 	cherry_pick.CherryPickConflictsEmptyCommitAfterResolving, | ||||
| 	cherry_pick.CherryPickDuringRebase, | ||||
| 	cherry_pick.CherryPickMerge, | ||||
| 	cherry_pick.CherryPickRange, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user