summaryrefslogtreecommitdiffstats
path: root/pkg/integration
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2023-02-25 13:08:45 +1100
committerJesse Duffield <jessedduffield@gmail.com>2023-02-25 21:37:16 +1100
commitdd1bf629b87db297a6336511a4e1ba39ba7afbc8 (patch)
treec12fb83f36821eb2faf2cbe357a2876997605f74 /pkg/integration
parent6c0b805137dbed6d8d89d2e10cb7018776b55321 (diff)
migrate patch building tests
Diffstat (limited to 'pkg/integration')
-rw-r--r--pkg/integration/components/actions.go6
-rw-r--r--pkg/integration/components/alert_driver.go4
-rw-r--r--pkg/integration/components/assertion_helper.go2
-rw-r--r--pkg/integration/components/commit_message_panel_driver.go2
-rw-r--r--pkg/integration/components/confirmation_driver.go4
-rw-r--r--pkg/integration/components/file_system.go2
-rw-r--r--pkg/integration/components/matcher.go48
-rw-r--r--pkg/integration/components/menu_driver.go8
-rw-r--r--pkg/integration/components/prompt_driver.go10
-rw-r--r--pkg/integration/components/search_driver.go2
-rw-r--r--pkg/integration/components/shell.go4
-rw-r--r--pkg/integration/components/test_driver.go64
-rw-r--r--pkg/integration/components/viewDriver.go302
-rw-r--r--pkg/integration/components/views.go101
-rw-r--r--pkg/integration/tests/patch_building/apply.go64
-rw-r--r--pkg/integration/tests/patch_building/apply_in_reverse.go49
-rw-r--r--pkg/integration/tests/patch_building/copy_patch_to_clipboard.go8
-rw-r--r--pkg/integration/tests/patch_building/move_to_index.go66
-rw-r--r--pkg/integration/tests/patch_building/move_to_index_partial.go98
-rw-r--r--pkg/integration/tests/patch_building/move_to_index_with_conflict.go89
-rw-r--r--pkg/integration/tests/patch_building/move_to_new_commit.go70
-rw-r--r--pkg/integration/tests/patch_building/remove_from_commit.go57
-rw-r--r--pkg/integration/tests/patch_building/reset_with_escape.go43
-rw-r--r--pkg/integration/tests/patch_building/select_all_files.go42
-rw-r--r--pkg/integration/tests/patch_building/specific_selection.go167
-rw-r--r--pkg/integration/tests/patch_building/start_new_patch.go62
-rw-r--r--pkg/integration/tests/tests_gen.go11
27 files changed, 1167 insertions, 218 deletions
diff --git a/pkg/integration/components/actions.go b/pkg/integration/components/actions.go
index 50564233a..5e37fc966 100644
--- a/pkg/integration/components/actions.go
+++ b/pkg/integration/components/actions.go
@@ -38,3 +38,9 @@ func (self *Actions) ConfirmDiscardLines() {
Content(Contains("Are you sure you want to delete the selected lines")).
Confirm()
}
+
+func (self *Actions) SelectPatchOption(matcher *Matcher) {
+ self.t.GlobalPress(self.t.keys.Universal.CreatePatchOptionsMenu)
+
+ self.t.ExpectPopup().Menu().Title(Equals("Patch Options")).Select(matcher).Confirm()
+}
diff --git a/pkg/integration/components/alert_driver.go b/pkg/integration/components/alert_driver.go
index 78247760a..7e1623041 100644
--- a/pkg/integration/components/alert_driver.go
+++ b/pkg/integration/components/alert_driver.go
@@ -11,7 +11,7 @@ func (self *AlertDriver) getViewDriver() *ViewDriver {
}
// asserts that the alert view has the expected title
-func (self *AlertDriver) Title(expected *matcher) *AlertDriver {
+func (self *AlertDriver) Title(expected *Matcher) *AlertDriver {
self.getViewDriver().Title(expected)
self.hasCheckedTitle = true
@@ -20,7 +20,7 @@ func (self *AlertDriver) Title(expected *matcher) *AlertDriver {
}
// asserts that the alert view has the expected content
-func (self *AlertDriver) Content(expected *matcher) *AlertDriver {
+func (self *AlertDriver) Content(expected *Matcher) *AlertDriver {
self.getViewDriver().Content(expected)
self.hasCheckedContent = true
diff --git a/pkg/integration/components/assertion_helper.go b/pkg/integration/components/assertion_helper.go
index 70f2ff182..23539a8d3 100644
--- a/pkg/integration/components/assertion_helper.go
+++ b/pkg/integration/components/assertion_helper.go
@@ -13,7 +13,7 @@ type assertionHelper struct {
// milliseconds we'll wait when an assertion fails.
var retryWaitTimes = []int{0, 1, 1, 1, 1, 1, 5, 10, 20, 40, 100, 200, 500, 1000, 2000, 4000}
-func (self *assertionHelper) matchString(matcher *matcher, context string, getValue func() string) {
+func (self *assertionHelper) matchString(matcher *Matcher, context string, getValue func() string) {
self.assertWithRetries(func() (bool, string) {
value := getValue()
return matcher.context(context).test(value)
diff --git a/pkg/integration/components/commit_message_panel_driver.go b/pkg/integration/components/commit_message_panel_driver.go
index b44a6c1dc..e420334bf 100644
--- a/pkg/integration/components/commit_message_panel_driver.go
+++ b/pkg/integration/components/commit_message_panel_driver.go
@@ -9,7 +9,7 @@ func (self *CommitMessagePanelDriver) getViewDriver() *ViewDriver {
}
// asserts on the text initially present in the prompt
-func (self *CommitMessagePanelDriver) InitialText(expected *matcher) *CommitMessagePanelDriver {
+func (self *CommitMessagePanelDriver) InitialText(expected *Matcher) *CommitMessagePanelDriver {
self.getViewDriver().Content(expected)
return self
diff --git a/pkg/integration/components/confirmation_driver.go b/pkg/integration/components/confirmation_driver.go
index 5f9500c56..687523833 100644
--- a/pkg/integration/components/confirmation_driver.go
+++ b/pkg/integration/components/confirmation_driver.go
@@ -11,7 +11,7 @@ func (self *ConfirmationDriver) getViewDriver() *ViewDriver {
}
// asserts that the confirmation view has the expected title
-func (self *ConfirmationDriver) Title(expected *matcher) *ConfirmationDriver {
+func (self *ConfirmationDriver) Title(expected *Matcher) *ConfirmationDriver {
self.getViewDriver().Title(expected)
self.hasCheckedTitle = true
@@ -20,7 +20,7 @@ func (self *ConfirmationDriver) Title(expected *matcher) *ConfirmationDriver {
}
// asserts that the confirmation view has the expected content
-func (self *ConfirmationDriver) Content(expected *matcher) *ConfirmationDriver {
+func (self *ConfirmationDriver) Content(expected *Matcher) *ConfirmationDriver {
self.getViewDriver().Content(expected)
self.hasCheckedContent = true
diff --git a/pkg/integration/components/file_system.go b/pkg/integration/components/file_system.go
index 4ac064838..cdc7413fb 100644
--- a/pkg/integration/components/file_system.go
+++ b/pkg/integration/components/file_system.go
@@ -26,7 +26,7 @@ func (self *FileSystem) PathNotPresent(path string) {
}
// Asserts that the file at the given path has the given content
-func (self *FileSystem) FileContent(path string, matcher *matcher) {
+func (self *FileSystem) FileContent(path string, matcher *Matcher) {
self.assertWithRetries(func() (bool, string) {
_, err := os.Stat(path)
if os.IsNotExist(err) {
diff --git a/pkg/integration/components/matcher.go b/pkg/integration/components/matcher.go
index ebec084a8..a87234654 100644
--- a/pkg/integration/components/matcher.go
+++ b/pkg/integration/components/matcher.go
@@ -9,7 +9,7 @@ import (
)
// for making assertions on string values
-type matcher struct {
+type Matcher struct {
rules []matcherRule
// this is printed when there's an error so that it's clear what the context of the assertion is
@@ -24,12 +24,12 @@ type matcherRule struct {
testFn func(string) (bool, string)
}
-func NewMatcher(name string, testFn func(string) (bool, string)) *matcher {
+func NewMatcher(name string, testFn func(string) (bool, string)) *Matcher {
rules := []matcherRule{{name: name, testFn: testFn}}
- return &matcher{rules: rules}
+ return &Matcher{rules: rules}
}
-func (self *matcher) name() string {
+func (self *Matcher) name() string {
if len(self.rules) == 0 {
return "anything"
}
@@ -40,7 +40,7 @@ func (self *matcher) name() string {
)
}
-func (self *matcher) test(value string) (bool, string) {
+func (self *Matcher) test(value string) (bool, string) {
for _, rule := range self.rules {
ok, message := rule.testFn(value)
if ok {
@@ -57,7 +57,7 @@ func (self *matcher) test(value string) (bool, string) {
return true, ""
}
-func (self *matcher) Contains(target string) *matcher {
+func (self *Matcher) Contains(target string) *Matcher {
return self.appendRule(matcherRule{
name: fmt.Sprintf("contains '%s'", target),
testFn: func(value string) (bool, string) {
@@ -71,7 +71,7 @@ func (self *matcher) Contains(target string) *matcher {
})
}
-func (self *matcher) DoesNotContain(target string) *matcher {
+func (self *Matcher) DoesNotContain(target string) *Matcher {
return self.appendRule(matcherRule{
name: fmt.Sprintf("does not contain '%s'", target),
testFn: func(value string) (bool, string) {
@@ -80,7 +80,7 @@ func (self *matcher) DoesNotContain(target string) *matcher {
})
}
-func (self *matcher) MatchesRegexp(target string) *matcher {
+func (self *Matcher) MatchesRegexp(target string) *Matcher {
return self.appendRule(matcherRule{
name: fmt.Sprintf("matches regular expression '%s'", target),
testFn: func(value string) (bool, string) {
@@ -93,7 +93,7 @@ func (self *matcher) MatchesRegexp(target string) *matcher {
})
}
-func (self *matcher) Equals(target string) *matcher {
+func (self *Matcher) Equals(target string) *Matcher {
return self.appendRule(matcherRule{
name: fmt.Sprintf("equals '%s'", target),
testFn: func(value string) (bool, string) {
@@ -106,7 +106,7 @@ const IS_SELECTED_RULE_NAME = "is selected"
// special rule that is only to be used in the TopLines and Lines methods, as a way of
// asserting that a given line is selected.
-func (self *matcher) IsSelected() *matcher {
+func (self *Matcher) IsSelected() *Matcher {
return self.appendRule(matcherRule{
name: IS_SELECTED_RULE_NAME,
testFn: func(value string) (bool, string) {
@@ -115,7 +115,7 @@ func (self *matcher) IsSelected() *matcher {
})
}
-func (self *matcher) appendRule(rule matcherRule) *matcher {
+func (self *Matcher) appendRule(rule matcherRule) *Matcher {
self.rules = append(self.rules, rule)
return self
@@ -123,39 +123,43 @@ func (self *matcher) appendRule(rule matcherRule) *matcher {
// adds context so that if the matcher test(s) fails, we understand what we were trying to test.
// E.g. prefix: "Unexpected content in view 'files'."
-func (self *matcher) context(prefix string) *matcher {
+func (self *Matcher) context(prefix string) *Matcher {
self.prefix = prefix
return self
}
// if the matcher has an `IsSelected` rule, it returns true, along with the matcher after that rule has been removed
-func (self *matcher) checkIsSelected() (bool, *matcher) {
- check := lo.ContainsBy(self.rules, func(rule matcherRule) bool { return rule.name == IS_SELECTED_RULE_NAME })
+func (self *Matcher) checkIsSelected() (bool, *Matcher) {
+ // copying into a new matcher in case we want to re-use the original later
+ newMatcher := &Matcher{}
+ *newMatcher = *self
- self.rules = lo.Filter(self.rules, func(rule matcherRule, _ int) bool { return rule.name != IS_SELECTED_RULE_NAME })
+ check := lo.ContainsBy(newMatcher.rules, func(rule matcherRule) bool { return rule.name == IS_SELECTED_RULE_NAME })
- return check, self
+ newMatcher.rules = lo.Filter(newMatcher.rules, func(rule matcherRule, _ int) bool { return rule.name != IS_SELECTED_RULE_NAME })
+
+ return check, newMatcher
}
// this matcher has no rules meaning it always passes the test. Use this
// when you don't care what value you're dealing with.
-func Anything() *matcher {
- return &matcher{}
+func Anything() *Matcher {
+ return &Matcher{}
}
-func Contains(target string) *matcher {
+func Contains(target string) *Matcher {
return Anything().Contains(target)
}
-func DoesNotContain(target string) *matcher {
+func DoesNotContain(target string) *Matcher {
return Anything().DoesNotContain(target)
}
-func MatchesRegexp(target string) *matcher {
+func MatchesRegexp(target string) *Matcher {
return Anything().MatchesRegexp(target)
}
-func Equals(target string) *matcher {
+func Equals(target string) *Matcher {
return Anything().Equals(target)
}
diff --git a/pkg/integration/components/menu_driver.go b/pkg/integration/components/menu_driver.go
index b8155aaf7..326435f52 100644
--- a/pkg/integration/components/menu_driver.go
+++ b/pkg/integration/components/menu_driver.go
@@ -10,7 +10,7 @@ func (self *MenuDriver) getViewDriver() *ViewDriver {
}
// asserts that the popup has the expected title
-func (self *MenuDriver) Title(expected *matcher) *MenuDriver {
+func (self *MenuDriver) Title(expected *Matcher) *MenuDriver {
self.getViewDriver().Title(expected)
self.hasCheckedTitle = true
@@ -30,19 +30,19 @@ func (self *MenuDriver) Cancel() {
self.getViewDriver().PressEscape()
}
-func (self *MenuDriver) Select(option *matcher) *MenuDriver {
+func (self *MenuDriver) Select(option *Matcher) *MenuDriver {
self.getViewDriver().NavigateToListItem(option)
return self
}
-func (self *MenuDriver) Lines(matchers ...*matcher) *MenuDriver {
+func (self *MenuDriver) Lines(matchers ...*Matcher) *MenuDriver {
self.getViewDriver().Lines(matchers...)
return self
}
-func (self *MenuDriver) TopLines(matchers ...*matcher) *MenuDriver {
+func (self *MenuDriver) TopLines(matchers ...*Matcher) *MenuDriver {
self.getViewDriver().TopLines(matchers...)
return self
diff --git a/pkg/integration/components/prompt_driver.go b/pkg/integration/components/prompt_driver.go
index 59e3587ef..58051bc70 100644
--- a/pkg/integration/components/prompt_driver.go
+++ b/pkg/integration/components/prompt_driver.go
@@ -10,7 +10,7 @@ func (self *PromptDriver) getViewDriver() *ViewDriver {
}
// asserts that the popup has the expected title
-func (self *PromptDriver) Title(expected *matcher) *PromptDriver {
+func (self *PromptDriver) Title(expected *Matcher) *PromptDriver {
self.getViewDriver().Title(expected)
self.hasCheckedTitle = true
@@ -19,7 +19,7 @@ func (self *PromptDriver) Title(expected *matcher) *PromptDriver {
}
// asserts on the text initially present in the prompt
-func (self *PromptDriver) InitialText(expected *matcher) *PromptDriver {
+func (self *PromptDriver) InitialText(expected *Matcher) *PromptDriver {
self.getViewDriver().Content(expected)
return self
@@ -55,13 +55,13 @@ func (self *PromptDriver) checkNecessaryChecksCompleted() {
}
}
-func (self *PromptDriver) SuggestionLines(matchers ...*matcher) *PromptDriver {
+func (self *PromptDriver) SuggestionLines(matchers ...*Matcher) *PromptDriver {
self.t.Views().Suggestions().Lines(matchers...)
return self
}
-func (self *PromptDriver) SuggestionTopLines(matchers ...*matcher) *PromptDriver {
+func (self *PromptDriver) SuggestionTopLines(matchers ...*Matcher) *PromptDriver {
self.t.Views().Suggestions().TopLines(matchers...)
return self
@@ -75,7 +75,7 @@ func (self *PromptDriver) ConfirmFirstSuggestion() {
PressEnter()
}
-func (self *PromptDriver) ConfirmSuggestion(matcher *matcher) {
+func (self *PromptDriver) ConfirmSuggestion(matcher *Matcher) {
self.t.press(self.t.keys.Universal.TogglePanel)
self.t.Views().Suggestions().
IsFocused().
diff --git a/pkg/integration/components/search_driver.go b/pkg/integration/components/search_driver.go
index 4ab4a4103..66a2fae41 100644
--- a/pkg/integration/components/search_driver.go
+++ b/pkg/integration/components/search_driver.go
@@ -12,7 +12,7 @@ func (self *SearchDriver) getViewDriver() *ViewDriver {
}
// asserts on the text initially present in the prompt
-func (self *SearchDriver) InitialText(expected *matcher) *SearchDriver {
+func (self *SearchDriver) InitialText(expected *Matcher) *SearchDriver {
self.getViewDriver().Content(expected)
return self
diff --git a/pkg/integration/components/shell.go b/pkg/integration/components/shell.go
index 8d47083ad..2f2d4b719 100644
--- a/pkg/integration/components/shell.go
+++ b/pkg/integration/components/shell.go
@@ -136,6 +136,10 @@ func (self *Shell) EmptyCommit(message string) *Shell {
return self.RunCommand(fmt.Sprintf("git commit --allow-empty -m \"%s\"", message))
}
+func (self *Shell) Revert(ref string) *Shell {
+ return self.RunCommand(fmt.Sprintf("git revert %s", ref))
+}
+
func (self *Shell) CreateLightweightTag(name string, ref string) *Shell {
return self.RunCommand(fmt.Sprintf("git tag %s %s", name, ref))
}
diff --git a/pkg/integration/components/test_driver.go b/pkg/integration/components/test_driver.go
index 694a59dbf..d645b7f0a 100644
--- a/pkg/integration/components/test_driver.go
+++ b/pkg/integration/components/test_driver.go
@@ -2,7 +2,6 @@ package components
import (
"fmt"
- "strings"
"time"
"github.com/atotto/clipboard"
@@ -71,65 +70,6 @@ func (self *TestDriver) Shell() *Shell {
return self.shell
}
-// this will look for a list item in the current panel and if it finds it, it will
-// enter the keypresses required to navigate to it.
-// The test will fail if:
-// - the user is not in a list item
-// - no list item is found containing the given text
-// - multiple list items are found containing the given text in the initial page of items
-//
-// NOTE: this currently assumes that ViewBufferLines returns all the lines that can be accessed.
-// If this changes in future, we'll need to update this code to first attempt to find the item
-// in the current page and failing that, jump to the top of the view and iterate through all of it,
-// looking for the item.
-func (self *TestDriver) navigateToListItem(matcher *matcher) {
- currentContext := self.gui.CurrentContext()
-
- view := currentContext.GetView()
-
- var matchIndex int
-
- self.assertWithRetries(func() (bool, string) {
- matchIndex = -1
- var matches []string
- lines := view.ViewBufferLines()
- // first we look for a duplicate on the current screen. We won't bother looking beyond that though.
- for i, line := range lines {
- ok, _ := matcher.test(line)
- if ok {
- matches = append(matches, line)
- matchIndex = i
- }
- }
- if len(matches) > 1 {
- return false, fmt.Sprintf("Found %d matches for `%s`, expected only a single match. Matching lines:\n%s", len(matches), matcher.name(), strings.Join(matches, "\n"))
- } else if len(matches) == 0 {
- return false, fmt.Sprintf("Could not find item matching: %s. Lines:\n%s", matcher.name(), strings.Join(lines, "\n"))
- } else {
- return true, ""
- }
- })
-
- selectedLineIdx := view.SelectedLineIdx()
- if selectedLineIdx == matchIndex {
- self.Views().current().SelectedLine(matcher)
- return
- }
- if selectedLineIdx < matchIndex {
- for i := selectedLineIdx; i < matchIndex; i++ {
- self.Views().current().SelectNextItem()
- }
- self.Views().current().SelectedLine(matcher)
- return
- } else {
- for i := selectedLineIdx; i > matchIndex; i-- {
- self.Views().current().SelectPreviousItem()
- }
- self.Views().current().SelectedLine(matcher)
- return
- }
-}
-
// for making assertions on lazygit views
func (self *TestDriver) Views() *Views {
return &Views{t: self}
@@ -140,11 +80,11 @@ func (self *TestDriver) ExpectPopup() *Popup {
return &Popup{t: self}
}
-func (self *TestDriver) ExpectToast(matcher *matcher) {
+func (self *TestDriver) ExpectToast(matcher *Matcher) {
self.Views().AppStatus().Content(matcher)
}
-func (self *TestDriver) ExpectClipboard(matcher *matcher) {
+func (self *TestDriver) ExpectClipboard(matcher *Matcher) {
self.assertWithRetries(func() (bool, string) {
text, err := clipboard.ReadAll()
if err != nil {
diff --git a/pkg/integration/components/viewDriver.go b/pkg/integration/components/viewDriver.go
index 3f0b9726b..5060a4d1d 100644
--- a/pkg/integration/components/viewDriver.go
+++ b/pkg/integration/components/viewDriver.go
@@ -10,14 +10,49 @@ import (
type ViewDriver struct {
// context is prepended to any error messages e.g. 'context: "current view"'
- context string
- getView func() *gocui.View
- t *TestDriver
- getSelectedLinesFn func() ([]string, error)
+ context string
+ getView func() *gocui.View
+ t *TestDriver
+ getSelectedLinesFn func() ([]string, error)
+ getSelectedRangeFn func() (int, int, error)
+ getSelectedLineIdxFn func() (int, error)
+}
+
+func (self *ViewDriver) getSelectedLines() ([]string, error) {
+ if self.getSelectedLinesFn == nil {
+ view := self.t.gui.View(self.getView().Name())
+
+ return []string{view.SelectedLine()}, nil
+ }
+
+ return self.getSelectedLinesFn()
+}
+
+func (self *ViewDriver) getSelectedRange() (int, int, error) {
+ if self.getSelectedRangeFn == nil {
+ view := self.t.gui.View(self.getView().Name())
+ idx := view.SelectedLineIdx()
+
+ return idx, idx, nil
+ }
+
+ return self.getSelectedRangeFn()
+}
+
+// even if you have a selected range, there may still be a line within that range
+// which the cursor points at. This function returns that line index.
+func (self *ViewDriver) getSelectedLineIdx() (int, error) {
+ if self.getSelectedLineIdxFn == nil {
+ view := self.t.gui.View(self.getView().Name())
+
+ return view.SelectedLineIdx(), nil
+ }
+
+ return self.getSelectedLineIdxFn()
}
// asserts that the view has the expected title
-func (self *ViewDriver) Title(expected *matcher) *ViewDriver {
+func (self *ViewDriver) Title(expected *Matcher) *ViewDriver {
self.t.assertWithRetries(func() (bool, string) {
actual := self.getView().Title
return expected.context(fmt.Sprintf("%s title", self.context)).test(actual)
@@ -26,42 +61,81 @@ func (self *ViewDriver) Title(expected *matcher) *ViewDriver {
return self
}
+// asserts that the view has lines matching the given matchers. One matcher must be passed for each line.
+// If you only care about the top n lines, use the TopLines method instead.
+func (self *ViewDriver) Lines(matchers ...*Matcher) *ViewDriver {
+ self.validateMatchersPassed(matchers)
+ self.LineCount(len(matchers))
+
+ return self.assertLines(0, matchers...)
+}
+
// asserts that the view has lines matching the given matchers. So if three matchers
// are passed, we only check the first three lines of the view.
// This method is convenient when you have a list of commits but you only want to
// assert on the first couple of commits.
-func (self *ViewDriver) TopLines(matchers ...*matcher) *ViewDriver {
- if len(matchers) < 1 {
- self.t.fail("TopLines method requires at least one matcher. If you are trying to assert that there are no lines, use .IsEmpty()")
- }
-
- self.t.assertWithRetries(func() (bool, string) {
- lines := self.getView().BufferLines()
- return len(lines) >= len(matchers), fmt.Sprintf("unexpected number of lines in view. Expected at least %d, got %d", len(matchers), len(lines))
- })
+func (self *ViewDriver) TopLines(matchers ...*Matcher) *ViewDriver {
+ self.validateMatchersPassed(matchers)
+ self.validateEnoughLines(matchers)
- return self.assertLines(matchers...)
+ return self.assertLines(0, matchers...)
}
-// asserts that the view has lines matching the given matchers. One matcher must be passed for each line.
-// If you only care about the top n lines, use the TopLines method instead.
-func (self *ViewDriver) Lines(matchers ...*matcher) *ViewDriver {
- self.LineCount(len(matchers))
+func (self *ViewDriver) ContainsLines(matchers ...*Matcher) *ViewDriver {
+ self.validateMatchersPassed(matchers)
+ self.validateEnoughLines(matchers)
- return self.assertLines(matchers...)
-}
+ self.t.assertWithRetries(func() (bool, string) {
+ content := self.getView().Buffer()
+ lines := strings.Split(content, "\n")
-func (self *ViewDriver) getSelectedLines() ([]string, error) {
- if self.getSelectedLinesFn == nil {
- view := self.t.gui.View(self.getView().Name())
+ startIdx, endIdx, err := self.getSelectedRange()
- return []string{view.SelectedLine()}, nil
- }
+ for i := 0; i < len(lines)-len(matchers)+1; i++ {
+ matches := true
+ for j, matcher := range matchers {
+ checkIsSelected, matcher := matcher.checkIsSelected() // strip the IsSelected matcher out
+ lineIdx := i + j
+ ok, _ := matcher.test(lines[lineIdx])
+ if !ok {
+ matches = false
+ break
+ }
+ if checkIsSelected {
+ if err != nil {
+ matches = false
+ break
+ }
+ if lineIdx < startIdx || lineIdx > endIdx {
+ matches = false
+ break
+ }
+ }
+ }
+ if matches {
+ return true, ""
+ }
+ }
- return self.getSelectedLinesFn()
+ expectedContent := expectedContentFromMatchers(matchers)
+
+ return false, fmt.Sprintf(
+ "Expected the following to be contained in the staging panel:\n-----\n%s\n-----\nBut got:\n-----\n%s\n-----\nSelected range: %d-%d",
+ expectedContent,
+ content,
+ startIdx,
+ endIdx,
+ )
+ })
+
+ return self
}
-func (self *ViewDriver) SelectedLines(matchers ...*matcher) *ViewDriver {
+// asserts on the lines that are selected in the view.
+func (self *ViewDriver) SelectedLines(matchers ...*Matcher) *ViewDriver {
+ self.validateMatchersPassed(matchers)
+ self.validateEnoughLines(matchers)
+
self.t.assertWithRetries(func() (bool, string) {
selectedLines, err := self.getSelectedLines()
if err != nil {
@@ -76,7 +150,12 @@ func (self *ViewDriver) SelectedLines(matchers ...*matcher) *ViewDriver {
}
for i, line := range selectedLines {
- ok, message := matchers[i].test(line)
+ checkIsSelected, matcher := matchers[i].checkIsSelected()
+ if checkIsSelected {
+ self.t.fail("You cannot use the IsSelected matcher with the SelectedLines method")
+ }
+
+ ok, message := matcher.test(line)
if !ok {
return false, fmt.Sprintf("Error: %s. Expected the following to be selected:\n-----\n%s\n-----\nBut got:\n-----\n%s\n-----", message, expectedContent, selectedContent)
}
@@ -88,53 +167,51 @@ func (self *ViewDriver) SelectedLines(matchers ...*matcher) *ViewDriver {
return self
}
-func (self *ViewDriver) ContainsLines(matchers ...*matcher) *ViewDriver {
- self.t.assertWithRetries(func() (bool, string) {
- content := self.getView().Buffer()
- lines := strings.Split(content, "\n")
-
- for i := 0; i < len(lines)-len(matchers)+1; i++ {
- matches := true
- for j, matcher := range matchers {
- ok, _ := matcher.test(lines[i+j])
- if !ok {
- matches = false
-