Add test coverage

This commit is contained in:
Veronica Berglyd Olsen
2025-07-27 13:19:58 +02:00
parent d4fc440725
commit 435a72c76b
2 changed files with 144 additions and 12 deletions
+10 -10
View File
@@ -2293,16 +2293,16 @@ class TextAutoReplace:
"""Auto-replace text elements based on main configuration. """Auto-replace text elements based on main configuration.
Returns True if anything was changed. Returns True if anything was changed.
""" """
pos = cursor.positionInBlock() aPos = cursor.position()
apos = cursor.position() bPos = cursor.positionInBlock()
block = cursor.block() block = cursor.block()
length = block.length() - 1 length = block.length() - 1
if length < 1 or pos-1 > length: if length < 1 or bPos-1 > length:
return False return False
cursor.movePosition(QtMoveLeft, QtKeepAnchor, min(4, pos)) cursor.movePosition(QtMoveLeft, QtKeepAnchor, min(4, bPos))
last = cursor.selectedText() last = cursor.selectedText()
delete, insert = self._determine(last, pos) delete, insert = self._determine(last, bPos)
check = insert check = insert
if self._doPadBefore and check in self._padBefore: if self._doPadBefore and check in self._padBefore:
@@ -2320,7 +2320,7 @@ class TextAutoReplace:
insert = insert + self._padChar insert = insert + self._padChar
if delete > 0: if delete > 0:
cursor.setPosition(apos) cursor.setPosition(aPos)
cursor.movePosition(QtMoveLeft, QtKeepAnchor, delete) cursor.movePosition(QtMoveLeft, QtKeepAnchor, delete)
cursor.insertText(insert) cursor.insertText(insert)
return True return True
@@ -2365,13 +2365,13 @@ class TextAutoReplace:
elif pos == 3 and t3 == ">>'": elif pos == 3 and t3 == ">>'":
return 1, self._quoteSO return 1, self._quoteSO
elif pos == 2 and t2 == "_'": elif pos == 2 and t2 == "_'":
return 1, self._quoteDO return 1, self._quoteSO
elif t3 == " _'": elif t3 == " _'":
return 1, self._quoteDO return 1, self._quoteSO
elif pos == 3 and t3 in ("**'", "=='", "~~'"): elif pos == 3 and t3 in ("**'", "=='", "~~'"):
return 1, self._quoteDO return 1, self._quoteSO
elif t4 in (" **'", " =='", " ~~'"): elif t4 in (" **'", " =='", " ~~'"):
return 1, self._quoteDO return 1, self._quoteSO
else: else:
return 1, self._quoteSC return 1, self._quoteSC
+134 -2
View File
@@ -27,7 +27,8 @@ import pytest
from PyQt6.QtCore import QEvent, QMimeData, QPointF, Qt, QThreadPool, QUrl from PyQt6.QtCore import QEvent, QMimeData, QPointF, Qt, QThreadPool, QUrl
from PyQt6.QtGui import ( from PyQt6.QtGui import (
QAction, QClipboard, QDesktopServices, QDragEnterEvent, QDragMoveEvent, QAction, QClipboard, QDesktopServices, QDragEnterEvent, QDragMoveEvent,
QDropEvent, QFont, QMouseEvent, QTextBlock, QTextCursor, QTextOption QDropEvent, QFont, QMouseEvent, QTextBlock, QTextCursor, QTextDocument,
QTextOption
) )
from PyQt6.QtWidgets import QApplication, QMenu, QPlainTextEdit from PyQt6.QtWidgets import QApplication, QMenu, QPlainTextEdit
@@ -36,7 +37,7 @@ from novelwriter.common import decodeMimeHandles
from novelwriter.constants import nwKeyWords, nwUnicode from novelwriter.constants import nwKeyWords, nwUnicode
from novelwriter.dialogs.editlabel import GuiEditLabel from novelwriter.dialogs.editlabel import GuiEditLabel
from novelwriter.enum import nwDocAction, nwDocInsert, nwItemClass, nwItemLayout from novelwriter.enum import nwDocAction, nwDocInsert, nwItemClass, nwItemLayout
from novelwriter.gui.doceditor import GuiDocEditor, _TagAction from novelwriter.gui.doceditor import GuiDocEditor, TextAutoReplace, _TagAction
from novelwriter.gui.dochighlight import TextBlockData from novelwriter.gui.dochighlight import TextBlockData
from novelwriter.text.counting import standardCounter from novelwriter.text.counting import standardCounter
from novelwriter.types import ( from novelwriter.types import (
@@ -2342,3 +2343,134 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, prjLipsum):
assert docEditor.textCursor().selectedText() == "" assert docEditor.textCursor().selectedText() == ""
# qtbot.stop() # qtbot.stop()
@pytest.mark.gui
def testGuiEditor_TextAutoReplaceSymbols():
"""Test the editor auto-replace functionality."""
CONFIG.fmtSQuoteOpen = nwUnicode.U_LSQUO
CONFIG.fmtSQuoteClose = nwUnicode.U_RSQUO
CONFIG.fmtDQuoteOpen = nwUnicode.U_LDQUO
CONFIG.fmtDQuoteClose = nwUnicode.U_RDQUO
CONFIG.doReplaceSQuote = True
CONFIG.doReplaceDQuote = True
CONFIG.doReplaceDash = True
CONFIG.doReplaceDots = True
ar = TextAutoReplace()
def prep(text: str) -> tuple[str, int]:
return text, len(text)
# Double Quote Open
assert ar._determine(*prep('"')) == (1, nwUnicode.U_LDQUO)
assert ar._determine(*prep('Stuff "')) == (1, nwUnicode.U_LDQUO)
assert ar._determine(*prep('>"')) == (1, nwUnicode.U_LDQUO)
assert ar._determine(*prep('>>"')) == (1, nwUnicode.U_LDQUO)
assert ar._determine(*prep('_"')) == (1, nwUnicode.U_LDQUO)
assert ar._determine(*prep(' _"')) == (1, nwUnicode.U_LDQUO)
assert ar._determine(*prep('**"')) == (1, nwUnicode.U_LDQUO)
assert ar._determine(*prep(' **"')) == (1, nwUnicode.U_LDQUO)
assert ar._determine(*prep('=="')) == (1, nwUnicode.U_LDQUO)
assert ar._determine(*prep(' =="')) == (1, nwUnicode.U_LDQUO)
assert ar._determine(*prep('~~"')) == (1, nwUnicode.U_LDQUO)
assert ar._determine(*prep(' ~~"')) == (1, nwUnicode.U_LDQUO)
# Double Quote Close
assert ar._determine(*prep('Stuff"')) == (1, nwUnicode.U_RDQUO)
# Single Quote Open
assert ar._determine(*prep("'")) == (1, nwUnicode.U_LSQUO)
assert ar._determine(*prep("Stuff '")) == (1, nwUnicode.U_LSQUO)
assert ar._determine(*prep(">'")) == (1, nwUnicode.U_LSQUO)
assert ar._determine(*prep(">>'")) == (1, nwUnicode.U_LSQUO)
assert ar._determine(*prep("_'")) == (1, nwUnicode.U_LSQUO)
assert ar._determine(*prep(" _'")) == (1, nwUnicode.U_LSQUO)
assert ar._determine(*prep("**'")) == (1, nwUnicode.U_LSQUO)
assert ar._determine(*prep(" **'")) == (1, nwUnicode.U_LSQUO)
assert ar._determine(*prep("=='")) == (1, nwUnicode.U_LSQUO)
assert ar._determine(*prep(" =='")) == (1, nwUnicode.U_LSQUO)
assert ar._determine(*prep("~~'")) == (1, nwUnicode.U_LSQUO)
assert ar._determine(*prep(" ~~'")) == (1, nwUnicode.U_LSQUO)
# Single Quote Close
assert ar._determine(*prep("Stuff'")) == (1, nwUnicode.U_RSQUO)
# Dashes
assert ar._determine(*prep("-")) == (0, "-")
assert ar._determine(*prep("--")) == (2, nwUnicode.U_ENDASH)
assert ar._determine(*prep("---")) == (3, nwUnicode.U_EMDASH)
assert ar._determine(*prep("----")) == (4, nwUnicode.U_HBAR)
assert ar._determine(*prep("\u2013-")) == (2, nwUnicode.U_EMDASH)
assert ar._determine(*prep("\u2014-")) == (2, nwUnicode.U_HBAR)
# Ellipsis
assert ar._determine(*prep(".")) == (0, ".")
assert ar._determine(*prep("..")) == (0, ".")
assert ar._determine(*prep("...")) == (3, nwUnicode.U_HELLIP)
# Block Typed Line Separator (#1150)
assert ar._determine(*prep("Text\u2028")) == (1, nwUnicode.U_PSEP)
@pytest.mark.gui
def testGuiEditor_TextAutoReplaceProcess():
"""Test the editor auto-replace functionality."""
CONFIG.fmtDQuoteOpen = nwUnicode.U_LAQUO
CONFIG.fmtDQuoteClose = nwUnicode.U_RAQUO
CONFIG.doReplaceDQuote = True
CONFIG.doReplaceDots = True
ar = TextAutoReplace()
doc = QTextDocument()
def prep(text: str) -> tuple[str, QTextCursor]:
doc.setPlainText(text)
cursor = QTextCursor(doc)
cursor.setPosition(len(text))
return text, cursor
# Nothing to Process
assert ar.process(*prep("")) is False
# Standard Auto-Replace
assert ar.process(*prep("Text ...")) is True
assert doc.toRawText() == "Text \u2026"
# Pad Before, Normal
CONFIG.fmtPadBefore = ":\u00bb"
CONFIG.fmtPadThin = False
ar.initSettings()
assert ar.process(*prep("Text:")) is True
assert doc.toRawText() == "Text\u00a0:"
assert ar.process(*prep("Text :")) is True # See #1061
assert doc.toRawText() == "Text\u00a0:"
assert ar.process(*prep('Text"')) is True
assert doc.toRawText() == "Text\u00a0»"
assert ar.process(*prep("@Synopsis:")) is False
assert doc.toRawText() == "@Synopsis:"
# Pad Before, Thin
CONFIG.fmtPadBefore = ":\u00bb"
CONFIG.fmtPadThin = True
ar.initSettings()
assert ar.process(*prep("Text:")) is True
assert doc.toRawText() == "Text\u202f:"
assert ar.process(*prep("Text :")) is True # See #1061
assert doc.toRawText() == "Text\u202f:"
# Pad After, Normal
CONFIG.fmtPadAfter = "\u00ab"
CONFIG.fmtPadThin = False
ar.initSettings()
assert ar.process(*prep('Text "')) is True
assert doc.toRawText() == "Text «\u00a0"
# Pad After, Thin
CONFIG.fmtPadAfter = "\u00ab"
CONFIG.fmtPadThin = True
ar.initSettings()
assert ar.process(*prep('Text "')) is True
assert doc.toRawText() == "Text «\u202f"