Update tests and test coverage
This commit is contained in:
+6
-2
@@ -157,9 +157,11 @@ def projPath(fncPath):
|
||||
def mockGUI(qtbot, monkeypatch):
|
||||
"""Create a mock instance of novelWriter's main GUI class."""
|
||||
from novelwriter.gui.theme import GuiTheme
|
||||
from novelwriter.shared import _GuiAlert
|
||||
|
||||
monkeypatch.setattr(QMessageBox, "exec", lambda *a: None)
|
||||
monkeypatch.setattr(QMessageBox, "result", lambda *a: QMessageBox.StandardButton.Yes)
|
||||
monkeypatch.setattr(_GuiAlert, "exec", lambda *a: None)
|
||||
monkeypatch.setattr(_GuiAlert, "finalState", True)
|
||||
gui = MockGuiMain()
|
||||
theme = GuiTheme()
|
||||
monkeypatch.setattr(SHARED, "_gui", gui)
|
||||
@@ -182,9 +184,11 @@ def nwGUI(qtbot, monkeypatch, functionFixture):
|
||||
"""Create an instance of the novelWriter GUI."""
|
||||
from novelwriter.gui.theme import GuiTheme
|
||||
from novelwriter.guimain import GuiMain
|
||||
from novelwriter.shared import _GuiAlert
|
||||
|
||||
monkeypatch.setattr(QMessageBox, "exec", lambda *a: None)
|
||||
monkeypatch.setattr(QMessageBox, "result", lambda *a: QMessageBox.StandardButton.Yes)
|
||||
monkeypatch.setattr(_GuiAlert, "exec", lambda *a: None)
|
||||
monkeypatch.setattr(_GuiAlert, "finalState", True)
|
||||
|
||||
CONFIG.loadConfig()
|
||||
SHARED.initTheme(GuiTheme())
|
||||
|
||||
@@ -22,9 +22,12 @@ from __future__ import annotations
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from PyQt6.QtCore import QSize
|
||||
from PyQt6.QtGui import QFont, QIcon, QPixmap
|
||||
from PyQt6.QtWidgets import QWidget
|
||||
|
||||
from novelwriter.extensions.modified import NPushButton
|
||||
|
||||
|
||||
class MockGuiMain(QWidget):
|
||||
|
||||
@@ -72,6 +75,9 @@ class MockTheme:
|
||||
def getHeaderDecoration(self, *a) -> QPixmap:
|
||||
return QPixmap()
|
||||
|
||||
def getStandardButton(self, *a) -> NPushButton:
|
||||
return NPushButton(None, "", QSize(1, 1)) # type: ignore
|
||||
|
||||
def getIcon(self, *a) -> QIcon:
|
||||
return QIcon()
|
||||
|
||||
|
||||
@@ -26,10 +26,10 @@ import pytest
|
||||
|
||||
from PyQt6.QtCore import QUrl
|
||||
from PyQt6.QtGui import QDesktopServices
|
||||
from PyQt6.QtWidgets import QFileDialog, QMessageBox, QWidget
|
||||
from PyQt6.QtWidgets import QFileDialog, QWidget
|
||||
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.shared import SharedData
|
||||
from novelwriter.shared import SharedData, _GuiAlert
|
||||
|
||||
from tests.mocked import MockGuiMain, MockTheme
|
||||
from tests.tools import buildTestProject
|
||||
@@ -143,10 +143,10 @@ def testBaseSharedData_Projects(monkeypatch, caplog, fncPath):
|
||||
|
||||
|
||||
@pytest.mark.base
|
||||
def testBaseSharedData_Alerts(qtbot, monkeypatch, caplog):
|
||||
def testBaseSharedData_Alerts(qtbot, monkeypatch, caplog, mockGUI):
|
||||
"""Test SharedData class alert helper functions."""
|
||||
monkeypatch.setattr(QMessageBox, "exec", lambda *a: None)
|
||||
monkeypatch.setattr(QMessageBox, "result", lambda *a: QMessageBox.StandardButton.Yes)
|
||||
monkeypatch.setattr(_GuiAlert, "exec", lambda *a: None)
|
||||
monkeypatch.setattr(_GuiAlert, "finalState", True)
|
||||
|
||||
shared = SharedData()
|
||||
|
||||
@@ -188,3 +188,63 @@ def testBaseSharedData_Alerts(qtbot, monkeypatch, caplog):
|
||||
# Question box
|
||||
assert shared.question("Why?") is True
|
||||
assert shared.lastAlert == "Why?"
|
||||
|
||||
|
||||
@pytest.mark.base
|
||||
def testBaseSharedData_GuiAlert():
|
||||
"""Test the _GuiAlert class."""
|
||||
alert = _GuiAlert(None, MockTheme()) # type: ignore
|
||||
|
||||
# Default states
|
||||
assert alert.logMessage == ""
|
||||
assert alert.finalState is False
|
||||
|
||||
# Populate message
|
||||
text = "one"
|
||||
info = "two"
|
||||
details = "three"
|
||||
alert.setMessage(text, info, details)
|
||||
assert alert.logMessage == f"{text} {info} {details}"
|
||||
assert alert.text() == text
|
||||
assert alert.informativeText() == info
|
||||
assert alert.detailedText() == details
|
||||
|
||||
# Populate exception
|
||||
exc = Exception("oops")
|
||||
alert.setException(exc)
|
||||
assert alert.logMessage == f"{text} {info} {details}"
|
||||
assert alert.informativeText() == f"{info}<br><b>Exception</b>: {exc!s}"
|
||||
|
||||
# Alert: Info
|
||||
alert.setAlertType(_GuiAlert.INFO, False)
|
||||
assert hasattr(alert, "_btnOk")
|
||||
assert alert.windowTitle() == "Information"
|
||||
alert._btnOk.click()
|
||||
assert alert.finalState is True
|
||||
alert._state = False
|
||||
|
||||
# Alert: Warning
|
||||
alert.setAlertType(_GuiAlert.WARN, False)
|
||||
assert hasattr(alert, "_btnOk")
|
||||
assert alert.windowTitle() == "Warning"
|
||||
alert._btnOk.click()
|
||||
assert alert.finalState is True
|
||||
alert._state = False
|
||||
|
||||
# Alert: Error
|
||||
alert.setAlertType(_GuiAlert.ERROR, False)
|
||||
assert hasattr(alert, "_btnOk")
|
||||
assert alert.windowTitle() == "Error"
|
||||
alert._btnOk.click()
|
||||
assert alert.finalState is True
|
||||
alert._state = False
|
||||
|
||||
# Alert: Question
|
||||
alert.setAlertType(_GuiAlert.ASK, True)
|
||||
assert hasattr(alert, "_btnYes")
|
||||
assert hasattr(alert, "_btnNo")
|
||||
assert alert.windowTitle() == "Question"
|
||||
alert._btnYes.click()
|
||||
assert alert.finalState is True
|
||||
alert._btnNo.click()
|
||||
assert alert.finalState is False
|
||||
|
||||
@@ -25,13 +25,12 @@ from zipfile import ZipFile
|
||||
|
||||
import pytest
|
||||
|
||||
from PyQt6.QtWidgets import QMessageBox
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.constants import nwFiles
|
||||
from novelwriter.core.project import NWProject, NWProjectState
|
||||
from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter, XMLReadState
|
||||
from novelwriter.enum import nwItemClass
|
||||
from novelwriter.shared import _GuiAlert
|
||||
|
||||
from tests.mocked import causeOSError
|
||||
from tests.tools import XML_IGNORE, C, buildTestProject, cmpFiles
|
||||
@@ -274,14 +273,14 @@ def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncPath, mockRnd):
|
||||
# Won't convert legacy file
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.WAS_LEGACY))
|
||||
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.StandardButton.No)
|
||||
mp.setattr(_GuiAlert, "finalState", False)
|
||||
assert project.openProject(fncPath, clearLock=True) is False
|
||||
assert "The file format of your project is about to be" in SHARED.lastAlert
|
||||
|
||||
# Won't open project from newer version
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(ProjectXMLReader, "hexVersion", property(lambda *a: 0x99999999))
|
||||
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.StandardButton.No)
|
||||
mp.setattr(_GuiAlert, "finalState", False)
|
||||
assert project.openProject(fncPath, clearLock=True) is False
|
||||
assert "This project was saved by a newer version" in SHARED.lastAlert
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import pytest
|
||||
|
||||
from PyQt6.QtCore import Qt
|
||||
from PyQt6.QtGui import QPalette
|
||||
from PyQt6.QtWidgets import QInputDialog, QMessageBox
|
||||
from PyQt6.QtWidgets import QInputDialog
|
||||
|
||||
from novelwriter import CONFIG, SHARED, __hexversion__
|
||||
from novelwriter.common import jsonEncode
|
||||
@@ -42,6 +42,7 @@ from novelwriter.gui.doceditor import GuiDocEditor
|
||||
from novelwriter.gui.noveltree import GuiNovelView
|
||||
from novelwriter.gui.outline import GuiOutlineView
|
||||
from novelwriter.gui.projtree import GuiProjectTree
|
||||
from novelwriter.shared import _GuiAlert
|
||||
from novelwriter.tools.welcome import GuiWelcome
|
||||
from novelwriter.types import QtModCtrl, QtModShift
|
||||
|
||||
@@ -104,7 +105,7 @@ def testGuiMain_Launch(qtbot, monkeypatch, nwGUI, projPath):
|
||||
|
||||
# Check that closes can be blocked
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.StandardButton.No)
|
||||
mp.setattr(_GuiAlert, "finalState", False)
|
||||
assert nwGUI.openProject(projPath) is True
|
||||
assert nwGUI.closeMain() is False
|
||||
nwGUI.closeProject()
|
||||
@@ -841,7 +842,7 @@ def testGuiMain_OpenClose(qtbot, monkeypatch, nwGUI, projPath, fncPath, mockRnd)
|
||||
# Block closing
|
||||
assert SHARED.hasProject is True
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.StandardButton.No)
|
||||
mp.setattr(_GuiAlert, "finalState", False)
|
||||
assert nwGUI.openProject(projPath) is False
|
||||
assert SHARED.hasProject is True
|
||||
|
||||
@@ -854,7 +855,7 @@ def testGuiMain_OpenClose(qtbot, monkeypatch, nwGUI, projPath, fncPath, mockRnd)
|
||||
shutil.copyfile(lockBack, lockPath)
|
||||
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.StandardButton.No)
|
||||
mp.setattr(_GuiAlert, "finalState", False)
|
||||
assert nwGUI.openProject(projPath) is False
|
||||
|
||||
assert nwGUI.openProject(projPath) is True
|
||||
|
||||
@@ -24,7 +24,7 @@ import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from PyQt6.QtWidgets import QApplication, QDialog, QMessageBox
|
||||
from PyQt6.QtWidgets import QApplication, QDialog
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.dialogs.about import GuiAbout
|
||||
@@ -49,8 +49,6 @@ LANG_DATA = CONFIG.listLanguages(CONFIG.LANG_NW)
|
||||
def testGuiI18n_Localisation(qtbot, monkeypatch, language, nwGUI, projPath):
|
||||
"""Test loading the gui with a specific language."""
|
||||
monkeypatch.setattr(QDialog, "exec", lambda *a: None)
|
||||
monkeypatch.setattr(QMessageBox, "exec", lambda *a: None)
|
||||
monkeypatch.setattr(QMessageBox, "result", lambda *a: QMessageBox.StandardButton.Yes)
|
||||
|
||||
# Set the test language
|
||||
CONFIG.guiLocale = language
|
||||
|
||||
@@ -25,12 +25,13 @@ from unittest.mock import MagicMock
|
||||
import pytest
|
||||
|
||||
from PyQt6.QtGui import QAction, QDesktopServices, QTextBlock
|
||||
from PyQt6.QtWidgets import QFileDialog, QMessageBox
|
||||
from PyQt6.QtWidgets import QFileDialog
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.constants import nwKeyWords, nwShortcode, nwStats, nwUnicode
|
||||
from novelwriter.enum import nwDocAction, nwDocInsert
|
||||
from novelwriter.gui.doceditor import GuiDocEditor
|
||||
from novelwriter.shared import _GuiAlert
|
||||
from novelwriter.types import QtKeepAnchor, QtMoveRight, QtSelectWord
|
||||
|
||||
from tests.tools import C, buildTestProject, writeFile
|
||||
@@ -575,7 +576,7 @@ def testGuiMainMenu_Insert(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd
|
||||
|
||||
# The document isn't empty, so the message box should pop
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(QMessageBox, "result", lambda *a, **k: QMessageBox.StandardButton.No)
|
||||
mp.setattr(_GuiAlert, "finalState", False)
|
||||
assert not nwGUI.importDocument()
|
||||
assert docEditor.getText() == "Bar"
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import pytest
|
||||
|
||||
from PyQt6.QtCore import QEvent, QItemSelectionModel, QModelIndex, QPointF
|
||||
from PyQt6.QtGui import QMouseEvent
|
||||
from PyQt6.QtWidgets import QMenu, QMessageBox
|
||||
from PyQt6.QtWidgets import QMenu
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.dialogs.docmerge import GuiDocMerge
|
||||
@@ -34,6 +34,7 @@ from novelwriter.dialogs.docsplit import GuiDocSplit
|
||||
from novelwriter.dialogs.editlabel import GuiEditLabel
|
||||
from novelwriter.enum import nwDocMode, nwItemClass, nwItemLayout, nwItemType
|
||||
from novelwriter.gui.projtree import _TreeContextMenu
|
||||
from novelwriter.shared import _GuiAlert
|
||||
from novelwriter.types import (
|
||||
QtAccepted, QtModNone, QtMouseLeft, QtMouseMiddle, QtRejected,
|
||||
QtScrollAlwaysOff, QtScrollAsNeeded
|
||||
@@ -627,7 +628,7 @@ def testGuiProjTree_DeleteRequest(qtbot, caplog, monkeypatch, nwGUI, projPath, m
|
||||
|
||||
# User can cancel move to trash
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.StandardButton.No)
|
||||
mp.setattr(_GuiAlert, "finalState", False)
|
||||
projTree.processDeleteRequest(hScenes, askFirst=True)
|
||||
assert [n.item.itemName for n in tree.model.root.allChildren()] == [
|
||||
"Novel", "Title Page", "New Folder", "New Chapter", "New Scene",
|
||||
@@ -645,7 +646,7 @@ def testGuiProjTree_DeleteRequest(qtbot, caplog, monkeypatch, nwGUI, projPath, m
|
||||
|
||||
# User can block permanent deletion
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.StandardButton.No)
|
||||
mp.setattr(_GuiAlert, "finalState", False)
|
||||
projTree.processDeleteRequest(hScenes[0:2], askFirst=True)
|
||||
assert [n.item.itemName for n in tree.model.root.allChildren()] == [
|
||||
"Novel", "Title Page", "New Folder", "New Chapter", "New Scene",
|
||||
@@ -677,7 +678,7 @@ def testGuiProjTree_DeleteRequest(qtbot, caplog, monkeypatch, nwGUI, projPath, m
|
||||
|
||||
# Trash can be completely emptied, but user can block it
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.StandardButton.No)
|
||||
mp.setattr(_GuiAlert, "finalState", False)
|
||||
projTree.emptyTrash()
|
||||
assert [n.item.itemName for n in tree.model.root.allChildren()] == [
|
||||
"Novel", "Title Page", "Chapter Folder", "Plot", "Characters", "Trash",
|
||||
@@ -995,7 +996,7 @@ def testGuiProjTree_Duplicate(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
|
||||
# Duplicate title page, but select no
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(QMessageBox, "result", lambda *a: QtRejected)
|
||||
mp.setattr(_GuiAlert, "finalState", False)
|
||||
projTree.duplicateFromHandle(C.hTitlePage)
|
||||
assert [n.item.itemName for n in tree.model.root.allChildren()] == [
|
||||
"Novel", "Title Page", "New Folder", "New Chapter", "New Scene",
|
||||
@@ -1302,7 +1303,7 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
|
||||
# Click no on the dialog
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(QMessageBox, "result", lambda *a: QtRejected)
|
||||
mp.setattr(_GuiAlert, "finalState", False)
|
||||
ctxMenu._convertFolderToFile(nwItemLayout.DOCUMENT)
|
||||
assert nodeOne.item.isFolderType()
|
||||
|
||||
|
||||
@@ -26,13 +26,14 @@ import pytest
|
||||
|
||||
from PyQt6.QtCore import QUrl
|
||||
from PyQt6.QtGui import QDesktopServices
|
||||
from PyQt6.QtWidgets import QFileDialog, QListWidgetItem, QMessageBox
|
||||
from PyQt6.QtWidgets import QFileDialog, QListWidgetItem
|
||||
from pytestqt.qtbot import QtBot
|
||||
|
||||
from novelwriter.constants import nwLabels
|
||||
from novelwriter.core.buildsettings import BuildSettings
|
||||
from novelwriter.enum import nwBuildFmt
|
||||
from novelwriter.guimain import GuiMain
|
||||
from novelwriter.shared import _GuiAlert
|
||||
from novelwriter.tools.manusbuild import GuiManuscriptBuild
|
||||
from novelwriter.types import QtDialogClose
|
||||
|
||||
@@ -134,7 +135,7 @@ def testToolManuscriptBuild_Main(
|
||||
manus.buildPath.setText(str(fncPath))
|
||||
manus.buildName.setText("TestBuild")
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.StandardButton.No)
|
||||
mp.setattr(_GuiAlert, "finalState", False)
|
||||
assert manus._runBuild() is False
|
||||
|
||||
# Test that the open button works
|
||||
|
||||
Reference in New Issue
Block a user