Improve test coverage of editor search

This commit is contained in:
Veronica Berglyd Olsen
2024-03-03 17:14:46 +01:00
parent 8859fc7b6b
commit d97ce592f8
2 changed files with 190 additions and 129 deletions
+16 -27
View File
@@ -1034,23 +1034,20 @@ class GuiDocEditor(QPlainTextEdit):
if not self.wcTimerDoc.isActive(): if not self.wcTimerDoc.isActive():
self.wcTimerDoc.start() self.wcTimerDoc.start()
block = self._qDocument.findBlock(pos) if (block := self._qDocument.findBlock(pos)).isValid():
if not block.isValid(): text = block.text()
return if text.startswith("@") and added + removed == 1:
# Only run on single keypresses, otherwise it will trigger
text = block.text() # at unwanted times when other changes are made to the document
if text.startswith("@") and added + removed == 1: cursor = self.textCursor()
# Only run on single keypresses, otherwise it will trigger bPos = cursor.positionInBlock()
# at unwanted times when other changes are made to the document if bPos > 0:
cursor = self.textCursor() show = self._completer.updateText(text, bPos)
bPos = cursor.positionInBlock() point = self.cursorRect().bottomRight()
if bPos > 0: self._completer.move(self.viewport().mapToGlobal(point))
show = self._completer.updateText(text, bPos) self._completer.setVisible(show)
point = self.cursorRect().bottomRight() else:
self._completer.move(self.viewport().mapToGlobal(point)) self._completer.setVisible(False)
self._completer.setVisible(show)
else:
self._completer.setVisible(False)
if self._doReplace and added == 1: if self._doReplace and added == 1:
self._docAutoReplace(text) self._docAutoReplace(text)
@@ -1428,13 +1425,7 @@ class GuiDocEditor(QPlainTextEdit):
# Make sure the selected text was selected by an actual find # Make sure the selected text was selected by an actual find
# call, and not the user. # call, and not the user.
try: if self._lastFind == (cursor.selectionStart(), cursor.selectionEnd()):
isFind = self._lastFind[0] == cursor.selectionStart()
isFind &= self._lastFind[1] == cursor.selectionEnd()
except Exception:
isFind = False
if isFind:
cursor.beginEditBlock() cursor.beginEditBlock()
cursor.removeSelectedText() cursor.removeSelectedText()
cursor.insertText(replWith) cursor.insertText(replWith)
@@ -1443,10 +1434,8 @@ class GuiDocEditor(QPlainTextEdit):
self.setTextCursor(cursor) self.setTextCursor(cursor)
logger.debug( logger.debug(
"Replaced occurrence of '%s' with '%s' on line %d", "Replaced occurrence of '%s' with '%s' on line %d",
searchFor, replWith, cursor.blockNumber() searchFor, replWith, cursor.blockNumber() + 1
) )
else:
logger.error("The selected text is not a search result, skipping replace")
self.findNext() self.findNext()
+174 -102
View File
@@ -1739,201 +1739,273 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, prjLipsum):
assert nwGUI.openProject(prjLipsum) is True assert nwGUI.openProject(prjLipsum) is True
assert nwGUI.openDocument("4c4f28287af27") is True assert nwGUI.openDocument("4c4f28287af27") is True
origText = nwGUI.docEditor.getText() docEditor = nwGUI.docEditor
docSearch = docEditor.docSearch
origText = docEditor.getText()
# Select the Word "est" # Select the Word "est"
nwGUI.docEditor.setCursorPosition(645) docEditor.setCursorPosition(645)
nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor) docEditor._makeSelection(QTextCursor.WordUnderCursor)
cursor = nwGUI.docEditor.textCursor() cursor = docEditor.textCursor()
assert cursor.selectedText() == "est" assert cursor.selectedText() == "est"
# Activate search # Activate search
nwGUI.mainMenu.aFind.activate(QAction.Trigger) nwGUI.mainMenu.aFind.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.isVisible() assert docSearch.isVisible()
assert nwGUI.docEditor.docSearch.searchText == "est" assert docSearch.searchText == "est"
# Find next by enter key # Find next by enter key
monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: True) monkeypatch.setattr(docSearch.searchBox, "hasFocus", lambda: True)
qtbot.keyClick(nwGUI.docEditor.docSearch.searchBox, Qt.Key_Return, delay=KEY_DELAY) qtbot.keyClick(docSearch.searchBox, Qt.Key_Return, delay=KEY_DELAY)
assert abs(nwGUI.docEditor.getCursorPosition() - 1299) < 3 assert abs(docEditor.getCursorPosition() - 1299) < 3
# Find next by button # Find next by button
qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=KEY_DELAY) qtbot.mouseClick(docSearch.searchButton, Qt.LeftButton, delay=KEY_DELAY)
assert abs(nwGUI.docEditor.getCursorPosition() - 1513) < 3 assert abs(docEditor.getCursorPosition() - 1513) < 3
# Activate loop search # Activate loop search
nwGUI.docEditor.docSearch.toggleLoop.activate(QAction.Trigger) docSearch.toggleLoop.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.toggleLoop.isChecked() assert docSearch.toggleLoop.isChecked()
assert nwGUI.docEditor.docSearch.doLoop is True assert docSearch.doLoop is True
# Find next by menu Search > Find Next # Find next by menu Search > Find Next
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 647) < 3 assert abs(docEditor.getCursorPosition() - 647) < 3
# Close search # Close search
nwGUI.docEditor.docSearch.cancelSearch.activate(QAction.Trigger) docSearch.cancelSearch.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.isVisible() is False assert docSearch.isVisible() is False
nwGUI.docEditor.setCursorPosition(15) docEditor.setCursorPosition(15)
# Toggle search again with header button # Toggle search again with header button
qtbot.mouseClick(nwGUI.docEditor.docHeader.searchButton, Qt.LeftButton, delay=KEY_DELAY) qtbot.mouseClick(docEditor.docHeader.searchButton, Qt.LeftButton, delay=KEY_DELAY)
nwGUI.docEditor.docSearch.setSearchText("") docSearch.setSearchText("")
assert nwGUI.docEditor.docSearch.isVisible() is True assert docSearch.isVisible() is True
# Search for non-existing # Search for non-existing
nwGUI.docEditor.setCursorPosition(0) docEditor.setCursorPosition(0)
nwGUI.docEditor.docSearch.setSearchText("abcdef") docSearch.setSearchText("abcdef")
qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=KEY_DELAY) qtbot.mouseClick(docSearch.searchButton, Qt.LeftButton, delay=KEY_DELAY)
assert nwGUI.docEditor.getCursorPosition() < 3 # No result assert docEditor.getCursorPosition() < 3 # No result
# Enable RegEx search # Enable RegEx search
nwGUI.docEditor.docSearch.toggleRegEx.activate(QAction.Trigger) docSearch.toggleRegEx.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.toggleRegEx.isChecked() assert docSearch.toggleRegEx.isChecked()
assert nwGUI.docEditor.docSearch.isRegEx is True assert docSearch.isRegEx is True
# Set invalid RegEx # Set invalid RegEx
nwGUI.docEditor.setCursorPosition(0) docEditor.setCursorPosition(0)
nwGUI.docEditor.docSearch.setSearchText(r"\bSus[") docSearch.setSearchText(r"\bSus[")
qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=KEY_DELAY) qtbot.mouseClick(docSearch.searchButton, Qt.LeftButton, delay=KEY_DELAY)
assert nwGUI.docEditor.getCursorPosition() < 3 # No result assert docEditor.getCursorPosition() < 3 # No result
# Set dangerous RegEx (issue #1015) # Set dangerous RegEx (issue #1015)
# If this doesn't get caught, the app will hang # If this doesn't get caught, the app will hang
nwGUI.docEditor.setCursorPosition(0) docEditor.setCursorPosition(0)
nwGUI.docEditor.docSearch.setSearchText(r".*") docSearch.setSearchText(r".*")
qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=KEY_DELAY) qtbot.mouseClick(docSearch.searchButton, Qt.LeftButton, delay=KEY_DELAY)
assert abs(nwGUI.docEditor.getCursorPosition() - 14) < 3 assert abs(docEditor.getCursorPosition() - 14) < 3
# Set valid RegEx # Set valid RegEx
nwGUI.docEditor.docSearch.setSearchText(r"\bSus") docSearch.setSearchText(r"\bSus")
qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=KEY_DELAY) qtbot.mouseClick(docSearch.searchButton, Qt.LeftButton, delay=KEY_DELAY)
assert abs(nwGUI.docEditor.getCursorPosition() - 223) < 3 assert abs(docEditor.getCursorPosition() - 223) < 3
# Find next and then prev # Find next and then prev
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 324) < 3 assert abs(docEditor.getCursorPosition() - 324) < 3
nwGUI.mainMenu.aFindPrev.activate(QAction.Trigger) nwGUI.mainMenu.aFindPrev.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 223) < 3 assert abs(docEditor.getCursorPosition() - 223) < 3
# Make RegEx case sensitive # Make RegEx case sensitive
nwGUI.docEditor.docSearch.toggleCase.activate(QAction.Trigger) docSearch.toggleCase.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.toggleCase.isChecked() assert docSearch.toggleCase.isChecked()
assert nwGUI.docEditor.docSearch.isCaseSense is True assert docSearch.isCaseSense is True
# Find next/prev (one result) # Find next/prev (one result)
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 626) < 3 assert abs(docEditor.getCursorPosition() - 626) < 3
nwGUI.mainMenu.aFindPrev.activate(QAction.Trigger) nwGUI.mainMenu.aFindPrev.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 626) < 3 assert abs(docEditor.getCursorPosition() - 626) < 3
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 626) < 3 assert abs(docEditor.getCursorPosition() - 626) < 3
# Trigger replace # Trigger replace
nwGUI.mainMenu.aReplace.activate(QAction.Trigger) nwGUI.mainMenu.aReplace.activate(QAction.Trigger)
nwGUI.docEditor.docSearch.setReplaceText("foo") docSearch.setReplaceText("foo")
# Disable RegEx case sensitive # Disable RegEx case sensitive
nwGUI.docEditor.docSearch.toggleCase.activate(QAction.Trigger) docSearch.toggleCase.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.toggleCase.isChecked() is False assert docSearch.toggleCase.isChecked() is False
assert nwGUI.docEditor.docSearch.isCaseSense is False assert docSearch.isCaseSense is False
# Toggle replace preserve case # Toggle replace preserve case
nwGUI.docEditor.docSearch.toggleMatchCap.activate(QAction.Trigger) docSearch.toggleMatchCap.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.toggleMatchCap.isChecked() assert docSearch.toggleMatchCap.isChecked()
assert nwGUI.docEditor.docSearch.doMatchCap is True assert docSearch.doMatchCap is True
# Replace "Sus" with "Foo" via menu # Replace "Sus" with "Foo" via menu
nwGUI.docEditor.setCursorPosition(605) docEditor.setCursorPosition(605)
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
nwGUI.mainMenu.aReplaceNext.activate(QAction.Trigger) nwGUI.mainMenu.aReplaceNext.activate(QAction.Trigger)
assert nwGUI.docEditor.getText()[623:634] == "Foopendisse" assert docEditor.getText()[623:634] == "Foopendisse"
# Find next/prev to loop file # Find next/prev to loop file
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 223) < 3 assert abs(docEditor.getCursorPosition() - 223) < 3
nwGUI.mainMenu.aFindPrev.activate(QAction.Trigger) nwGUI.mainMenu.aFindPrev.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 1805) < 3 assert abs(docEditor.getCursorPosition() - 1805) < 3
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 223) < 3 assert abs(docEditor.getCursorPosition() - 223) < 3
# Replace "sus" with "foo" via replace button # Replace "sus" with "foo" via replace button
qtbot.mouseClick(nwGUI.docEditor.docSearch.replaceButton, Qt.LeftButton, delay=KEY_DELAY) qtbot.mouseClick(docSearch.replaceButton, Qt.LeftButton, delay=KEY_DELAY)
assert nwGUI.docEditor.getText()[220:228] == "foocipit" assert docEditor.getText()[220:228] == "foocipit"
# Revert last two replaces # Revert last two replaces
assert nwGUI.docEditor.docAction(nwDocAction.UNDO) assert docEditor.docAction(nwDocAction.UNDO)
assert nwGUI.docEditor.docAction(nwDocAction.UNDO) assert docEditor.docAction(nwDocAction.UNDO)
assert nwGUI.docEditor.getText() == origText assert docEditor.getText() == origText
# Disable RegEx search # Disable RegEx search
nwGUI.docEditor.docSearch.toggleRegEx.activate(QAction.Trigger) docSearch.toggleRegEx.activate(QAction.Trigger)
assert not nwGUI.docEditor.docSearch.toggleRegEx.isChecked() assert not docSearch.toggleRegEx.isChecked()
assert nwGUI.docEditor.docSearch.isRegEx is False assert docSearch.isRegEx is False
# Close search and select "est" again # Close search and select "est" again
nwGUI.docEditor.docSearch.cancelSearch.activate(QAction.Trigger) docSearch.cancelSearch.activate(QAction.Trigger)
nwGUI.docEditor.setCursorPosition(645) docEditor.setCursorPosition(645)
nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor) docEditor._makeSelection(QTextCursor.WordUnderCursor)
cursor = nwGUI.docEditor.textCursor() cursor = docEditor.textCursor()
assert cursor.selectedText() == "est" assert cursor.selectedText() == "est"
# Activate search again # Activate search again
nwGUI.mainMenu.aFind.activate(QAction.Trigger) nwGUI.mainMenu.aFind.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.isVisible() assert docSearch.isVisible()
assert nwGUI.docEditor.docSearch.searchText == "est" assert docSearch.searchText == "est"
# Enable full word search # Enable full word search
nwGUI.docEditor.docSearch.toggleWord.activate(QAction.Trigger) docSearch.toggleWord.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.toggleWord.isChecked() assert docSearch.toggleWord.isChecked()
assert nwGUI.docEditor.docSearch.isWholeWord is True assert docSearch.isWholeWord is True
# Only one match # Only one match
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 647) < 3 assert abs(docEditor.getCursorPosition() - 647) < 3
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 647) < 3 assert abs(docEditor.getCursorPosition() - 647) < 3
# Enable next doc search # Enable next doc search
nwGUI.docEditor.docSearch.toggleProject.activate(QAction.Trigger) docSearch.toggleProject.activate(QAction.Trigger)
assert nwGUI.docEditor.docSearch.toggleProject.isChecked() assert docSearch.toggleProject.isChecked()
assert nwGUI.docEditor.docSearch.doNextFile is True assert docSearch.doNextFile is True
# Next match # Next match
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert nwGUI.docEditor.docHandle == "2426c6f0ca922" # Next document assert docEditor.docHandle == "2426c6f0ca922" # Next document
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 620) < 3 assert abs(docEditor.getCursorPosition() - 620) < 3
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert abs(nwGUI.docEditor.getCursorPosition() - 1127) < 3 assert abs(docEditor.getCursorPosition() - 1127) < 3
# Next doc, no match # Next doc, no match
assert nwGUI.docEditor.docSearch.doNextFile is True assert docSearch.doNextFile is True
nwGUI.docEditor.docSearch.setSearchText("abcdef") docSearch.setSearchText("abcdef")
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert nwGUI.docEditor.docHandle != "2426c6f0ca922" assert docEditor.docHandle != "2426c6f0ca922"
assert nwGUI.docEditor.docHandle == "04468803b92e1" assert docEditor.docHandle == "04468803b92e1"
nwGUI.mainMenu.aFindNext.activate(QAction.Trigger) nwGUI.mainMenu.aFindNext.activate(QAction.Trigger)
assert nwGUI.docEditor.docHandle != "04468803b92e1" assert docEditor.docHandle != "04468803b92e1"
assert nwGUI.docEditor.docHandle == "7a992350f3eb6" assert docEditor.docHandle == "7a992350f3eb6"
# Toggle Replace # Toggle Replace
nwGUI.docEditor.beginReplace() docEditor.beginReplace()
# MonkeyPatch the focus cycle. We can't really test this very well, other than # MonkeyPatch the focus cycle. We can't really test this very well, other than
# check that the tabs aren't captured when the main editor has focus # check that the tabs aren't captured when the main editor has focus
monkeypatch.setattr(nwGUI.docEditor, "hasFocus", lambda: True) with monkeypatch.context() as mp:
monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: False) mp.setattr(docEditor, "hasFocus", lambda: True)
monkeypatch.setattr(nwGUI.docEditor.docSearch.replaceBox, "hasFocus", lambda: False) mp.setattr(docSearch.searchBox, "hasFocus", lambda: False)
assert nwGUI.docEditor.focusNextPrevChild(True) is False mp.setattr(docSearch.replaceBox, "hasFocus", lambda: False)
assert docEditor.focusNextPrevChild(True) is False
assert docSearch.cycleFocus(True) is False
monkeypatch.setattr(nwGUI.docEditor, "hasFocus", lambda: False) with monkeypatch.context() as mp:
monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: True) mp.setattr(docEditor, "hasFocus", lambda: False)
monkeypatch.setattr(nwGUI.docEditor.docSearch.replaceBox, "hasFocus", lambda: False) mp.setattr(docSearch.searchBox, "hasFocus", lambda: True)
assert nwGUI.docEditor.focusNextPrevChild(True) is True mp.setattr(docSearch.replaceBox, "hasFocus", lambda: False)
assert docEditor.focusNextPrevChild(True) is True
assert docSearch.cycleFocus(True) is True
monkeypatch.setattr(nwGUI.docEditor.docSearch.searchBox, "hasFocus", lambda: False) with monkeypatch.context() as mp:
monkeypatch.setattr(nwGUI.docEditor.docSearch.replaceBox, "hasFocus", lambda: True) mp.setattr(docEditor, "hasFocus", lambda: False)
assert nwGUI.docEditor.focusNextPrevChild(True) is True mp.setattr(docSearch.searchBox, "hasFocus", lambda: False)
mp.setattr(docSearch.replaceBox, "hasFocus", lambda: True)
assert docEditor.focusNextPrevChild(True) is True
assert docSearch.cycleFocus(True) is True
docSearch.closeSearch()
assert docSearch.isVisible() is False
assert docEditor.focusNextPrevChild(True) is True
# Replace Text
# ============
docSearch.toggleCase.setChecked(True)
docSearch.toggleWord.setChecked(False)
docSearch.toggleRegEx.setChecked(False)
docSearch.toggleLoop.setChecked(False)
docSearch.toggleProject.setChecked(False)
docEditor.setCursorPosition(0)
# Replace Next
docSearch.searchBox.setText("a")
docSearch.replaceBox.setText("A")
# No focus
with monkeypatch.context() as mp:
mp.setattr(docEditor, "anyFocus", lambda: False)
docEditor.findNext()
assert docEditor.textCursor().selectedText() == ""
docEditor.replaceNext()
assert docEditor.textCursor().selectedText() == ""
# Search not open
docSearch.closeSearch()
assert docSearch.isVisible() is False
docEditor.findNext()
assert docSearch.isVisible() is True
docSearch.closeSearch()
assert docSearch.isVisible() is False
docEditor.replaceNext()
assert docSearch.isVisible() is True
docEditor.toggleSearch()
assert docSearch.isVisible() is False
docEditor.toggleSearch()
assert docSearch.isVisible() is True
# Find first entry
docEditor.replaceNext()
assert docEditor.textCursor().selectedText() == "a"
assert docEditor.getCursorPosition() == 64
# Treat the search as a user selection
docEditor._lastFind = None
docEditor.replaceNext()
assert docEditor.textCursor().selectedText() == "a"
assert docEditor.getCursorPosition() == 92
# Iterate through the rest
finds = [104, 123, 175, 197, 206, 211, 220, 238, 250, 250]
for i in range(10):
docEditor.replaceNext()
assert docEditor.textCursor().selectedText() == "a"
assert docEditor.getCursorPosition() == finds[i]
assert docEditor._lastFind == (249, 250)
# Search for something that doesn't exist
docSearch.searchBox.setText("x")
docEditor._lastFind = None
docEditor.replaceNext()
assert docEditor.textCursor().selectedText() == ""
# qtbot.stop() # qtbot.stop()