Remove dependence of main GUI class in project class
This commit is contained in:
@@ -344,7 +344,7 @@ class ProjectBuilder:
|
|||||||
logger.error("No project path set for the new project")
|
logger.error("No project path set for the new project")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
project = NWProject(self.mainGui)
|
project = NWProject()
|
||||||
if not project.storage.openProjectInPlace(projPath, newProject=True):
|
if not project.storage.openProjectInPlace(projPath, newProject=True):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
+24
-40
@@ -33,8 +33,8 @@ from functools import partial
|
|||||||
|
|
||||||
from PyQt5.QtCore import QCoreApplication, QObject, pyqtSignal
|
from PyQt5.QtCore import QCoreApplication, QObject, pyqtSignal
|
||||||
|
|
||||||
from novelwriter import CONFIG, __version__, __hexversion__
|
from novelwriter import CONFIG, SHARED, __version__, __hexversion__
|
||||||
from novelwriter.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert
|
from novelwriter.enum import nwItemType, nwItemClass, nwItemLayout
|
||||||
from novelwriter.error import logException
|
from novelwriter.error import logException
|
||||||
from novelwriter.constants import trConst, nwLabels
|
from novelwriter.constants import trConst, nwLabels
|
||||||
from novelwriter.core.tree import NWTree
|
from novelwriter.core.tree import NWTree
|
||||||
@@ -49,7 +49,6 @@ from novelwriter.common import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING: # pragma: no cover
|
if TYPE_CHECKING: # pragma: no cover
|
||||||
from novelwriter.guimain import GuiMain
|
|
||||||
from novelwriter.core.item import NWItem
|
from novelwriter.core.item import NWItem
|
||||||
from novelwriter.core.status import NWStatus
|
from novelwriter.core.status import NWStatus
|
||||||
|
|
||||||
@@ -61,11 +60,8 @@ class NWProject(QObject):
|
|||||||
statusChanged = pyqtSignal(bool)
|
statusChanged = pyqtSignal(bool)
|
||||||
statusMessage = pyqtSignal(str)
|
statusMessage = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, mainGui: GuiMain) -> None:
|
def __init__(self, parent: QObject | None = None) -> None:
|
||||||
super().__init__(parent=mainGui)
|
super().__init__(parent=parent)
|
||||||
|
|
||||||
# Internal
|
|
||||||
self.mainGui = mainGui
|
|
||||||
|
|
||||||
# Core Elements
|
# Core Elements
|
||||||
self._options = OptionState(self) # Project-specific GUI options
|
self._options = OptionState(self) # Project-specific GUI options
|
||||||
@@ -197,9 +193,9 @@ class NWProject(QObject):
|
|||||||
if self._tree.checkType(tHandle, nwItemType.FILE):
|
if self._tree.checkType(tHandle, nwItemType.FILE):
|
||||||
delDoc = self._storage.getDocument(tHandle)
|
delDoc = self._storage.getDocument(tHandle)
|
||||||
if not delDoc.deleteDocument():
|
if not delDoc.deleteDocument():
|
||||||
self.mainGui.makeAlert(
|
SHARED.error(
|
||||||
self.tr("Could not delete document file."),
|
self.tr("Could not delete document file."),
|
||||||
info=delDoc.getError(), level=nwAlert.ERROR
|
info=delDoc.getError()
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -228,9 +224,7 @@ class NWProject(QObject):
|
|||||||
"""
|
"""
|
||||||
logger.info("Opening project: %s", projPath)
|
logger.info("Opening project: %s", projPath)
|
||||||
if not self._storage.openProjectInPlace(projPath):
|
if not self._storage.openProjectInPlace(projPath):
|
||||||
self.mainGui.makeAlert(self.tr(
|
SHARED.error(self.tr("Could not open project with path: {0}").format(projPath))
|
||||||
"Could not open project with path: {0}"
|
|
||||||
).format(projPath), level=nwAlert.ERROR)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Project Lock
|
# Project Lock
|
||||||
@@ -262,26 +256,24 @@ class NWProject(QObject):
|
|||||||
|
|
||||||
if not xmlParsed:
|
if not xmlParsed:
|
||||||
if xmlReader.state == XMLReadState.NOT_NWX_FILE:
|
if xmlReader.state == XMLReadState.NOT_NWX_FILE:
|
||||||
self.mainGui.makeAlert(self.tr(
|
SHARED.error(self.tr(
|
||||||
"Project file does not appear to be a novelWriterXML file."
|
"Project file does not appear to be a novelWriterXML file."
|
||||||
), level=nwAlert.ERROR)
|
))
|
||||||
elif xmlReader.state == XMLReadState.UNKNOWN_VERSION:
|
elif xmlReader.state == XMLReadState.UNKNOWN_VERSION:
|
||||||
self.mainGui.makeAlert(self.tr(
|
SHARED.error(self.tr(
|
||||||
"Unknown or unsupported novelWriter project file format. "
|
"Unknown or unsupported novelWriter project file format. "
|
||||||
"The project cannot be opened by this version of novelWriter. "
|
"The project cannot be opened by this version of novelWriter. "
|
||||||
"The file was saved with novelWriter version {0}."
|
"The file was saved with novelWriter version {0}."
|
||||||
).format(appVersion), level=nwAlert.ERROR)
|
).format(appVersion))
|
||||||
else:
|
else:
|
||||||
self.mainGui.makeAlert(self.tr(
|
SHARED.error(self.tr("Failed to parse project xml."))
|
||||||
"Failed to parse project xml."
|
|
||||||
), level=nwAlert.ERROR)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Check Legacy Upgrade
|
# Check Legacy Upgrade
|
||||||
# ====================
|
# ====================
|
||||||
|
|
||||||
if xmlReader.state == XMLReadState.WAS_LEGACY:
|
if xmlReader.state == XMLReadState.WAS_LEGACY:
|
||||||
msgYes = self.mainGui.askQuestion(self.tr(
|
msgYes = SHARED.question(self.tr(
|
||||||
"The file format of your project is about to be updated. "
|
"The file format of your project is about to be updated. "
|
||||||
"If you proceed, older versions of novelWriter will no "
|
"If you proceed, older versions of novelWriter will no "
|
||||||
"longer be able to open this project. Continue?"
|
"longer be able to open this project. Continue?"
|
||||||
@@ -293,13 +285,13 @@ class NWProject(QObject):
|
|||||||
# =========================
|
# =========================
|
||||||
|
|
||||||
if xmlReader.hexVersion > hexToInt(__hexversion__):
|
if xmlReader.hexVersion > hexToInt(__hexversion__):
|
||||||
msgYes = self.mainGui.askQuestion(self.tr(
|
msgYes = SHARED.question(self.tr(
|
||||||
"This project was saved by a newer version of "
|
"This project was saved by a newer version of "
|
||||||
"novelWriter, version {0}. This is version {1}. If you "
|
"novelWriter, version {0}. This is version {1}. If you "
|
||||||
"continue to open the project, some attributes and "
|
"continue to open the project, some attributes and "
|
||||||
"settings may not be preserved, but the overall project "
|
"settings may not be preserved, but the overall project "
|
||||||
"should be fine. Continue opening the project?"
|
"should be fine. Continue opening the project?"
|
||||||
).format(appVersion, __version__))
|
).format(appVersion, __version__), warn=True)
|
||||||
if not msgYes:
|
if not msgYes:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -321,9 +313,9 @@ class NWProject(QObject):
|
|||||||
# This also handles any orphaned files found
|
# This also handles any orphaned files found
|
||||||
orphans, recovered = self._tree.checkConsistency(self.tr("Recovered"))
|
orphans, recovered = self._tree.checkConsistency(self.tr("Recovered"))
|
||||||
if orphans > 0:
|
if orphans > 0:
|
||||||
self.mainGui.makeAlert(self.tr(
|
SHARED.warn(self.tr(
|
||||||
"Found {0} orphaned file(s) in the project. {1} file(s) were recovered."
|
"Found {0} orphaned file(s) in the project. {1} file(s) were recovered."
|
||||||
).format(orphans, recovered), level=nwAlert.WARN)
|
).format(orphans, recovered))
|
||||||
|
|
||||||
self._index.loadIndex()
|
self._index.loadIndex()
|
||||||
if xmlReader.state == XMLReadState.WAS_LEGACY:
|
if xmlReader.state == XMLReadState.WAS_LEGACY:
|
||||||
@@ -347,9 +339,7 @@ class NWProject(QObject):
|
|||||||
file.
|
file.
|
||||||
"""
|
"""
|
||||||
if not self._storage.isOpen():
|
if not self._storage.isOpen():
|
||||||
self.mainGui.makeAlert(self.tr(
|
SHARED.error(self.tr("There is no project open."))
|
||||||
"There is no project open."
|
|
||||||
), level=nwAlert.ERROR)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
saveTime = time()
|
saveTime = time()
|
||||||
@@ -372,9 +362,7 @@ class NWProject(QObject):
|
|||||||
editTime = self._data.editTime + max(round(saveTime - self._session.start), 0)
|
editTime = self._data.editTime + max(round(saveTime - self._session.start), 0)
|
||||||
content = self._tree.pack()
|
content = self._tree.pack()
|
||||||
if not xmlWriter.write(self._data, content, saveTime, editTime):
|
if not xmlWriter.write(self._data, content, saveTime, editTime):
|
||||||
self.mainGui.makeAlert(self.tr(
|
SHARED.error(self.tr("Failed to save project."), exc=xmlWriter.error)
|
||||||
"Failed to save project."
|
|
||||||
), level=nwAlert.ERROR, exc=xmlWriter.error)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Save other project data
|
# Save other project data
|
||||||
@@ -415,10 +403,10 @@ class NWProject(QObject):
|
|||||||
self.statusMessage.emit(self.tr("Backing up project ..."))
|
self.statusMessage.emit(self.tr("Backing up project ..."))
|
||||||
|
|
||||||
if not self._data.name:
|
if not self._data.name:
|
||||||
self.mainGui.makeAlert(self.tr(
|
SHARED.error(self.tr(
|
||||||
"Cannot backup project because no project name is set. "
|
"Cannot backup project because no project name is set. "
|
||||||
"Please set a Project Name in Project Settings."
|
"Please set a Project Name in Project Settings."
|
||||||
), level=nwAlert.ERROR)
|
))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
cleanName = makeFileNameSafe(self._data.name)
|
cleanName = makeFileNameSafe(self._data.name)
|
||||||
@@ -427,9 +415,7 @@ class NWProject(QObject):
|
|||||||
try:
|
try:
|
||||||
baseDir.mkdir(exist_ok=True, parents=True)
|
baseDir.mkdir(exist_ok=True, parents=True)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self.mainGui.makeAlert(self.tr(
|
SHARED.error(self.tr("Could not create backup folder."), exc=exc)
|
||||||
"Could not create backup folder."
|
|
||||||
), level=nwAlert.ERROR, exc=exc)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
timeStamp = formatTimeStamp(time(), fileSafe=True)
|
timeStamp = formatTimeStamp(time(), fileSafe=True)
|
||||||
@@ -437,14 +423,12 @@ class NWProject(QObject):
|
|||||||
if self._storage.zipIt(archName, compression=2):
|
if self._storage.zipIt(archName, compression=2):
|
||||||
size = formatInt(archName.stat().st_size)
|
size = formatInt(archName.stat().st_size)
|
||||||
if doNotify:
|
if doNotify:
|
||||||
self.mainGui.makeAlert(
|
SHARED.info(
|
||||||
self.tr("Created a backup of your project of size {0}B.").format(size),
|
self.tr("Created a backup of your project of size {0}B.").format(size),
|
||||||
info=self.tr("Path: {0}").format(str(backupPath))
|
info=self.tr("Path: {0}").format(str(backupPath))
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.mainGui.makeAlert(self.tr(
|
SHARED.error(self.tr("Could not write backup archive."))
|
||||||
"Could not write backup archive."
|
|
||||||
), level=nwAlert.ERROR)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.statusMessage.emit(self.tr("Project backed up to '{0}'").format(str(archName)))
|
self.statusMessage.emit(self.tr("Project backed up to '{0}'").format(str(archName)))
|
||||||
|
|||||||
+110
-1
@@ -29,6 +29,7 @@ from typing import TYPE_CHECKING
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot
|
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot
|
||||||
|
from PyQt5.QtWidgets import QMessageBox, QWidget
|
||||||
|
|
||||||
if TYPE_CHECKING: # pragma: no cover
|
if TYPE_CHECKING: # pragma: no cover
|
||||||
from novelwriter.guimain import GuiMain
|
from novelwriter.guimain import GuiMain
|
||||||
@@ -49,6 +50,7 @@ class SharedData(QObject):
|
|||||||
self._theme = None
|
self._theme = None
|
||||||
self._project = None
|
self._project = None
|
||||||
self._lockedBy = None
|
self._lockedBy = None
|
||||||
|
self._alert = None
|
||||||
return
|
return
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -74,12 +76,19 @@ class SharedData(QObject):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def hasProject(self) -> bool:
|
def hasProject(self) -> bool:
|
||||||
|
"""Return True of the project instance is populated."""
|
||||||
return self.project.isValid
|
return self.project.isValid
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def projectLock(self) -> list | None:
|
def projectLock(self) -> list | None:
|
||||||
|
"""Return cached lock information for the last project."""
|
||||||
return self._lockedBy
|
return self._lockedBy
|
||||||
|
|
||||||
|
@property
|
||||||
|
def alert(self) -> _GuiAlert | None:
|
||||||
|
"""Return a pointer to the last alert box."""
|
||||||
|
return self._alert
|
||||||
|
|
||||||
##
|
##
|
||||||
# Methods
|
# Methods
|
||||||
##
|
##
|
||||||
@@ -127,6 +136,48 @@ class SharedData(QObject):
|
|||||||
"""Remove the project lock."""
|
"""Remove the project lock."""
|
||||||
return self.project.storage.clearLockFile()
|
return self.project.storage.clearLockFile()
|
||||||
|
|
||||||
|
##
|
||||||
|
# Alert Boxes
|
||||||
|
##
|
||||||
|
|
||||||
|
def info(self, text: str, info: str = "", details: str = "") -> None:
|
||||||
|
"""Open an information alert box."""
|
||||||
|
self._alert = _GuiAlert(self.mainGui, self.theme)
|
||||||
|
self._alert.setMessage(text, info, details)
|
||||||
|
self._alert.setAlertType(_GuiAlert.INFO, False)
|
||||||
|
logger.info(self._alert.logMessage, stacklevel=2)
|
||||||
|
self._alert.exec_()
|
||||||
|
return
|
||||||
|
|
||||||
|
def warn(self, text: str, info: str = "", details: str = "") -> None:
|
||||||
|
"""Open a warning alert box."""
|
||||||
|
self._alert = _GuiAlert(self.mainGui, self.theme)
|
||||||
|
self._alert.setMessage(text, info, details)
|
||||||
|
self._alert.setAlertType(_GuiAlert.WARN, False)
|
||||||
|
logger.warning(self._alert.logMessage, stacklevel=2)
|
||||||
|
self._alert.exec_()
|
||||||
|
return
|
||||||
|
|
||||||
|
def error(self, text: str, info: str = "", details: str = "",
|
||||||
|
exc: Exception | None = None) -> None:
|
||||||
|
"""Open an error alert box."""
|
||||||
|
self._alert = _GuiAlert(self.mainGui, self.theme)
|
||||||
|
self._alert.setMessage(text, info, details)
|
||||||
|
self._alert.setAlertType(_GuiAlert.ERROR, False)
|
||||||
|
if exc:
|
||||||
|
self._alert.setException(exc)
|
||||||
|
logger.error(self._alert.logMessage, stacklevel=2)
|
||||||
|
self._alert.exec_()
|
||||||
|
return
|
||||||
|
|
||||||
|
def question(self, text: str, info: str = "", details: str = "", warn: bool = False) -> bool:
|
||||||
|
"""Open an error alert box."""
|
||||||
|
self._alert = _GuiAlert(self.mainGui, self.theme)
|
||||||
|
self._alert.setMessage(text, info, details)
|
||||||
|
self._alert.setAlertType(_GuiAlert.ERROR, True)
|
||||||
|
self._alert.exec_()
|
||||||
|
return self._alert.result() == QMessageBox.Yes
|
||||||
|
|
||||||
##
|
##
|
||||||
# Internal Slots
|
# Internal Slots
|
||||||
##
|
##
|
||||||
@@ -154,9 +205,67 @@ class SharedData(QObject):
|
|||||||
self._project.statusChanged.disconnect()
|
self._project.statusChanged.disconnect()
|
||||||
self._project.statusMessage.disconnect()
|
self._project.statusMessage.disconnect()
|
||||||
self._project.deleteLater()
|
self._project.deleteLater()
|
||||||
self._project = NWProject(self.mainGui)
|
self._project = NWProject(self)
|
||||||
self._project.statusChanged.connect(self._emitProjectStatusChange)
|
self._project.statusChanged.connect(self._emitProjectStatusChange)
|
||||||
self._project.statusMessage.connect(self._emitProjectStatusMeesage)
|
self._project.statusMessage.connect(self._emitProjectStatusMeesage)
|
||||||
return
|
return
|
||||||
|
|
||||||
# END Class SharedData
|
# END Class SharedData
|
||||||
|
|
||||||
|
|
||||||
|
class _GuiAlert(QMessageBox):
|
||||||
|
|
||||||
|
INFO = 0
|
||||||
|
WARN = 1
|
||||||
|
ERROR = 2
|
||||||
|
ASK = 3
|
||||||
|
|
||||||
|
def __init__(self, parent: QWidget, theme: GuiTheme) -> None:
|
||||||
|
super().__init__(parent=parent)
|
||||||
|
self._theme = theme
|
||||||
|
self._message = ""
|
||||||
|
return
|
||||||
|
|
||||||
|
@property
|
||||||
|
def logMessage(self) -> str:
|
||||||
|
return self._message
|
||||||
|
|
||||||
|
def setMessage(self, text: str, info: str, details: str) -> None:
|
||||||
|
"""Set the alert box message."""
|
||||||
|
self._message = " ".join(filter(None, [text, info, details]))
|
||||||
|
self.setText(text)
|
||||||
|
self.setInformativeText(info)
|
||||||
|
self.setDetailedText(details)
|
||||||
|
return
|
||||||
|
|
||||||
|
def setException(self, exception: Exception) -> None:
|
||||||
|
"""Add exception details."""
|
||||||
|
info = self.informativeText()
|
||||||
|
text = f"<b>{type(exception).__name__}</b>: {str(exception)}"
|
||||||
|
self.setInformativeText(f"{info}<br>{text}" if info else text)
|
||||||
|
return
|
||||||
|
|
||||||
|
def setAlertType(self, level: int, isYesNo: bool) -> None:
|
||||||
|
"""Set the type of alert and whether the dialog should have
|
||||||
|
Yes/No buttons or just an Ok button.
|
||||||
|
"""
|
||||||
|
if isYesNo:
|
||||||
|
self.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
|
||||||
|
else:
|
||||||
|
self.setStandardButtons(QMessageBox.Ok)
|
||||||
|
pSz = 2*self._theme.baseIconSize
|
||||||
|
if level == self.INFO:
|
||||||
|
self.setIconPixmap(self._theme.getPixmap("alert_info", (pSz, pSz)))
|
||||||
|
self.setWindowTitle(self.tr("Information"))
|
||||||
|
elif level == self.WARN:
|
||||||
|
self.setIconPixmap(self._theme.getPixmap("alert_warn", (pSz, pSz)))
|
||||||
|
self.setWindowTitle(self.tr("Warning"))
|
||||||
|
elif level == self.ERROR:
|
||||||
|
self.setIconPixmap(self._theme.getPixmap("alert_error", (pSz, pSz)))
|
||||||
|
self.setWindowTitle(self.tr("Error"))
|
||||||
|
elif level == self.ASK:
|
||||||
|
self.setIconPixmap(self._theme.getPixmap("alert_question", (pSz, pSz)))
|
||||||
|
self.setWindowTitle(self.tr("Question"))
|
||||||
|
return
|
||||||
|
|
||||||
|
# END Class _GuiAlert
|
||||||
|
|||||||
+10
-5
@@ -25,14 +25,14 @@ import shutil
|
|||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from mocked import MockGuiMain
|
|
||||||
from tools import cleanProject
|
from tools import cleanProject
|
||||||
|
from mocked import MockGuiMain, MockTheme
|
||||||
|
|
||||||
from PyQt5.QtWidgets import QMessageBox
|
from PyQt5.QtWidgets import QMessageBox
|
||||||
|
|
||||||
sys.path.insert(1, str(Path(__file__).parent.parent.absolute()))
|
sys.path.insert(1, str(Path(__file__).parent.parent.absolute()))
|
||||||
|
|
||||||
from novelwriter import CONFIG, main # noqa: E402
|
from novelwriter import CONFIG, SHARED, main # noqa: E402
|
||||||
|
|
||||||
_TST_ROOT = Path(__file__).parent
|
_TST_ROOT = Path(__file__).parent
|
||||||
_TMP_ROOT = _TST_ROOT / "temp"
|
_TMP_ROOT = _TST_ROOT / "temp"
|
||||||
@@ -136,10 +136,15 @@ def projPath(fncPath):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
def mockGUI():
|
def mockGUI(qtbot, monkeypatch):
|
||||||
"""Create a mock instance of novelWriter's main GUI class."""
|
"""Create a mock instance of novelWriter's main GUI class."""
|
||||||
theGui = MockGuiMain()
|
monkeypatch.setattr(QMessageBox, "exec_", lambda *a: None)
|
||||||
return theGui
|
monkeypatch.setattr(QMessageBox, "result", lambda *a: QMessageBox.Yes)
|
||||||
|
gui = MockGuiMain()
|
||||||
|
theme = MockTheme()
|
||||||
|
monkeypatch.setattr(SHARED, "_gui", gui)
|
||||||
|
monkeypatch.setattr(SHARED, "_theme", theme)
|
||||||
|
return gui
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
|
|||||||
+15
-2
@@ -19,14 +19,15 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject
|
from PyQt5.QtGui import QPixmap
|
||||||
|
from PyQt5.QtWidgets import QWidget
|
||||||
|
|
||||||
|
|
||||||
# =========================================================================== #
|
# =========================================================================== #
|
||||||
# Mock GUI
|
# Mock GUI
|
||||||
# =========================================================================== #
|
# =========================================================================== #
|
||||||
|
|
||||||
class MockGuiMain(QObject):
|
class MockGuiMain(QWidget):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@@ -98,6 +99,18 @@ class MockStatusBar:
|
|||||||
# END Class MockStatusBar
|
# END Class MockStatusBar
|
||||||
|
|
||||||
|
|
||||||
|
class MockTheme:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.baseIconSize = 10
|
||||||
|
return
|
||||||
|
|
||||||
|
def getPixmap(self, *a):
|
||||||
|
return QPixmap()
|
||||||
|
|
||||||
|
# END Class MockTheme
|
||||||
|
|
||||||
|
|
||||||
class MockApp:
|
class MockApp:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ def testCoreBuildSettings_BuildValues():
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreBuildSettings_Filters(mockGUI, fncPath: Path, mockRnd):
|
def testCoreBuildSettings_Filters(mockGUI, fncPath: Path, mockRnd):
|
||||||
"""Test filters for project items."""
|
"""Test filters for project items."""
|
||||||
project = NWProject(mockGUI)
|
project = NWProject()
|
||||||
buildTestProject(project, fncPath)
|
buildTestProject(project, fncPath)
|
||||||
build = BuildSettings()
|
build = BuildSettings()
|
||||||
|
|
||||||
@@ -368,7 +368,7 @@ def testCoreBuildSettings_Filters(mockGUI, fncPath: Path, mockRnd):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreBuildSettings_Collection(monkeypatch, mockGUI, fncPath: Path, mockRnd):
|
def testCoreBuildSettings_Collection(monkeypatch, mockGUI, fncPath: Path, mockRnd):
|
||||||
"""Test the collections class for builds."""
|
"""Test the collections class for builds."""
|
||||||
project = NWProject(mockGUI)
|
project = NWProject()
|
||||||
buildTestProject(project, fncPath)
|
buildTestProject(project, fncPath)
|
||||||
buildsFile = project.storage.getMetaFile(nwFiles.BUILDS_FILE)
|
buildsFile = project.storage.getMetaFile(nwFiles.BUILDS_FILE)
|
||||||
assert isinstance(buildsFile, Path)
|
assert isinstance(buildsFile, Path)
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ from novelwriter.core.coretools import DocDuplicator, DocMerger, DocSplitter, Pr
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTools_DocMerger(monkeypatch, mockGUI, fncPath, tstPaths, mockRnd, ipsumText):
|
def testCoreTools_DocMerger(monkeypatch, mockGUI, fncPath, tstPaths, mockRnd, ipsumText):
|
||||||
"""Test the DocMerger utility."""
|
"""Test the DocMerger utility."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ def testCoreTools_DocMerger(monkeypatch, mockGUI, fncPath, tstPaths, mockRnd, ip
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTools_DocSplitter(monkeypatch, mockGUI, fncPath, mockRnd, ipsumText):
|
def testCoreTools_DocSplitter(monkeypatch, mockGUI, fncPath, mockRnd, ipsumText):
|
||||||
"""Test the DocSplitter utility."""
|
"""Test the DocSplitter utility."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
|
|
||||||
@@ -265,7 +265,7 @@ def testCoreTools_DocSplitter(monkeypatch, mockGUI, fncPath, mockRnd, ipsumText)
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTools_DocDuplicator(mockGUI, fncPath, tstPaths, mockRnd):
|
def testCoreTools_DocDuplicator(mockGUI, fncPath, tstPaths, mockRnd):
|
||||||
"""Test the DocDuplicator utility."""
|
"""Test the DocDuplicator utility."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ BUILD_CONF = {
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreDocBuild_OpenDocument(monkeypatch, mockGUI, prjLipsum, fncPath, tstPaths):
|
def testCoreDocBuild_OpenDocument(monkeypatch, mockGUI, prjLipsum, fncPath, tstPaths):
|
||||||
"""Test building an open document manuscript."""
|
"""Test building an open document manuscript."""
|
||||||
project = NWProject(mockGUI)
|
project = NWProject()
|
||||||
project.openProject(prjLipsum)
|
project.openProject(prjLipsum)
|
||||||
|
|
||||||
build = BuildSettings()
|
build = BuildSettings()
|
||||||
@@ -180,7 +180,7 @@ def testCoreDocBuild_OpenDocument(monkeypatch, mockGUI, prjLipsum, fncPath, tstP
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreDocBuild_HTML(monkeypatch, mockGUI, prjLipsum, fncPath, tstPaths):
|
def testCoreDocBuild_HTML(monkeypatch, mockGUI, prjLipsum, fncPath, tstPaths):
|
||||||
"""Test building an HTML manuscript."""
|
"""Test building an HTML manuscript."""
|
||||||
project = NWProject(mockGUI)
|
project = NWProject()
|
||||||
project.openProject(prjLipsum)
|
project.openProject(prjLipsum)
|
||||||
|
|
||||||
build = BuildSettings()
|
build = BuildSettings()
|
||||||
@@ -250,7 +250,7 @@ def testCoreDocBuild_HTML(monkeypatch, mockGUI, prjLipsum, fncPath, tstPaths):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreDocBuild_Markdown(monkeypatch, mockGUI, prjLipsum, fncPath, tstPaths):
|
def testCoreDocBuild_Markdown(monkeypatch, mockGUI, prjLipsum, fncPath, tstPaths):
|
||||||
"""Test building an Markdown manuscript."""
|
"""Test building an Markdown manuscript."""
|
||||||
project = NWProject(mockGUI)
|
project = NWProject()
|
||||||
project.openProject(prjLipsum)
|
project.openProject(prjLipsum)
|
||||||
|
|
||||||
build = BuildSettings()
|
build = BuildSettings()
|
||||||
@@ -320,7 +320,7 @@ def testCoreDocBuild_Markdown(monkeypatch, mockGUI, prjLipsum, fncPath, tstPaths
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreDocBuild_NWD(monkeypatch, mockGUI, prjLipsum, fncPath, tstPaths):
|
def testCoreDocBuild_NWD(monkeypatch, mockGUI, prjLipsum, fncPath, tstPaths):
|
||||||
"""Test building a NWD manuscript."""
|
"""Test building a NWD manuscript."""
|
||||||
project = NWProject(mockGUI)
|
project = NWProject()
|
||||||
project.openProject(prjLipsum)
|
project.openProject(prjLipsum)
|
||||||
|
|
||||||
build = BuildSettings()
|
build = BuildSettings()
|
||||||
@@ -390,7 +390,7 @@ def testCoreDocBuild_NWD(monkeypatch, mockGUI, prjLipsum, fncPath, tstPaths):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreDocBuild_Custom(mockGUI, fncPath: Path):
|
def testCoreDocBuild_Custom(mockGUI, fncPath: Path):
|
||||||
"""Test custom builds and some error handling."""
|
"""Test custom builds and some error handling."""
|
||||||
project = NWProject(mockGUI)
|
project = NWProject()
|
||||||
buildTestProject(project, fncPath)
|
buildTestProject(project, fncPath)
|
||||||
|
|
||||||
build = BuildSettings()
|
build = BuildSettings()
|
||||||
@@ -455,7 +455,7 @@ def testCoreDocBuild_Custom(mockGUI, fncPath: Path):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreDocBuild_IterBuild(mockGUI, fncPath: Path, mockRnd):
|
def testCoreDocBuild_IterBuild(mockGUI, fncPath: Path, mockRnd):
|
||||||
"""Test iter build wrapper."""
|
"""Test iter build wrapper."""
|
||||||
project = NWProject(mockGUI)
|
project = NWProject()
|
||||||
buildTestProject(project, fncPath)
|
buildTestProject(project, fncPath)
|
||||||
build = BuildSettings()
|
build = BuildSettings()
|
||||||
build.unpack(BUILD_CONF)
|
build.unpack(BUILD_CONF)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ from novelwriter.core.document import NWDocument
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreDocument_LoadSave(monkeypatch, mockGUI, fncPath, mockRnd):
|
def testCoreDocument_LoadSave(monkeypatch, mockGUI, fncPath, mockRnd):
|
||||||
"""Test loading and saving a document with the NWDocument class."""
|
"""Test loading and saving a document with the NWDocument class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
|
|
||||||
@@ -173,7 +173,7 @@ def testCoreDocument_LoadSave(monkeypatch, mockGUI, fncPath, mockRnd):
|
|||||||
def testCoreDocument_Methods(mockGUI, fncPath, mockRnd):
|
def testCoreDocument_Methods(mockGUI, fncPath, mockRnd):
|
||||||
"""Test other methods of the NWDocument class.
|
"""Test other methods of the NWDocument class.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ def testCoreIndex_LoadSave(monkeypatch, prjLipsum, mockGUI, tstPaths):
|
|||||||
testFile = tstPaths.outDir / "coreIndex_LoadSave_tagsIndex.json"
|
testFile = tstPaths.outDir / "coreIndex_LoadSave_tagsIndex.json"
|
||||||
compFile = tstPaths.refDir / "coreIndex_LoadSave_tagsIndex.json"
|
compFile = tstPaths.refDir / "coreIndex_LoadSave_tagsIndex.json"
|
||||||
|
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
assert theProject.openProject(prjLipsum)
|
assert theProject.openProject(prjLipsum)
|
||||||
|
|
||||||
theIndex = NWIndex(theProject)
|
theIndex = NWIndex(theProject)
|
||||||
@@ -155,7 +155,7 @@ def testCoreIndex_LoadSave(monkeypatch, prjLipsum, mockGUI, tstPaths):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreIndex_ScanThis(mockGUI):
|
def testCoreIndex_ScanThis(mockGUI):
|
||||||
"""Test the tag scanner function scanThis."""
|
"""Test the tag scanner function scanThis."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theIndex = theProject.index
|
theIndex = theProject.index
|
||||||
|
|
||||||
isValid, theBits, thePos = theIndex.scanThis("tag: this, and this")
|
isValid, theBits, thePos = theIndex.scanThis("tag: this, and this")
|
||||||
@@ -204,7 +204,7 @@ def testCoreIndex_ScanThis(mockGUI):
|
|||||||
def testCoreIndex_CheckThese(mockGUI, fncPath, mockRnd):
|
def testCoreIndex_CheckThese(mockGUI, fncPath, mockRnd):
|
||||||
"""Test the tag checker function checkThese.
|
"""Test the tag checker function checkThese.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
theIndex = theProject.index
|
theIndex = theProject.index
|
||||||
@@ -281,7 +281,7 @@ def testCoreIndex_CheckThese(mockGUI, fncPath, mockRnd):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreIndex_ScanText(mockGUI, fncPath, mockRnd):
|
def testCoreIndex_ScanText(mockGUI, fncPath, mockRnd):
|
||||||
"""Check the index text scanner."""
|
"""Check the index text scanner."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
theIndex = theProject.index
|
theIndex = theProject.index
|
||||||
@@ -502,7 +502,7 @@ def testCoreIndex_ScanText(mockGUI, fncPath, mockRnd):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreIndex_ExtractData(mockGUI, fncPath, mockRnd):
|
def testCoreIndex_ExtractData(mockGUI, fncPath, mockRnd):
|
||||||
"""Check the index data extraction functions."""
|
"""Check the index data extraction functions."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
|
|
||||||
@@ -941,7 +941,7 @@ def testCoreIndex_TagsIndex():
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreIndex_ItemIndex(mockGUI, fncPath, mockRnd):
|
def testCoreIndex_ItemIndex(mockGUI, fncPath, mockRnd):
|
||||||
"""Check the ItemIndex class."""
|
"""Check the ItemIndex class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
theProject.index.clearIndex()
|
theProject.index.clearIndex()
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ from novelwriter.core.project import NWProject
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreItem_Setters(mockGUI, mockRnd, fncPath):
|
def testCoreItem_Setters(mockGUI, mockRnd, fncPath):
|
||||||
"""Test all the simple setters for the NWItem class."""
|
"""Test all the simple setters for the NWItem class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
theItem = NWItem(theProject, "0000000000000")
|
theItem = NWItem(theProject, "0000000000000")
|
||||||
@@ -185,7 +185,7 @@ def testCoreItem_Setters(mockGUI, mockRnd, fncPath):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreItem_Methods(mockGUI, mockRnd, fncPath):
|
def testCoreItem_Methods(mockGUI, mockRnd, fncPath):
|
||||||
"""Test the simple methods of the NWItem class."""
|
"""Test the simple methods of the NWItem class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
theItem = NWItem(theProject, "0000000000000")
|
theItem = NWItem(theProject, "0000000000000")
|
||||||
@@ -333,7 +333,7 @@ def testCoreItem_TypeSetter(mockGUI):
|
|||||||
"""Test the setter for all the nwItemType values for the NWItem
|
"""Test the setter for all the nwItemType values for the NWItem
|
||||||
class.
|
class.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theItem = NWItem(theProject, "0000000000000")
|
theItem = NWItem(theProject, "0000000000000")
|
||||||
|
|
||||||
# Type
|
# Type
|
||||||
@@ -362,7 +362,7 @@ def testCoreItem_ClassSetter(mockGUI):
|
|||||||
"""Test the setter for all the nwItemClass values for the NWItem
|
"""Test the setter for all the nwItemClass values for the NWItem
|
||||||
class.
|
class.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theItem = NWItem(theProject, "0000000000000")
|
theItem = NWItem(theProject, "0000000000000")
|
||||||
|
|
||||||
# Class
|
# Class
|
||||||
@@ -449,7 +449,7 @@ def testCoreItem_LayoutSetter(mockGUI):
|
|||||||
"""Test the setter for all the nwItemLayout values for the NWItem
|
"""Test the setter for all the nwItemLayout values for the NWItem
|
||||||
class.
|
class.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theItem = NWItem(theProject, "0000000000000")
|
theItem = NWItem(theProject, "0000000000000")
|
||||||
|
|
||||||
# Faulty Layouts
|
# Faulty Layouts
|
||||||
@@ -477,7 +477,7 @@ def testCoreItem_LayoutSetter(mockGUI):
|
|||||||
def testCoreItem_ClassDefaults(mockGUI):
|
def testCoreItem_ClassDefaults(mockGUI):
|
||||||
"""Test the setter for the default values.
|
"""Test the setter for the default values.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theItem = NWItem(theProject, "0000000000000")
|
theItem = NWItem(theProject, "0000000000000")
|
||||||
|
|
||||||
# Root items should not have their class updated
|
# Root items should not have their class updated
|
||||||
@@ -532,7 +532,7 @@ def testCoreItem_ClassDefaults(mockGUI):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreItem_PackUnpack(mockGUI, caplog, mockRnd):
|
def testCoreItem_PackUnpack(mockGUI, caplog, mockRnd):
|
||||||
"""Test packing and unpacking entries for the NWItem class."""
|
"""Test packing and unpacking entries for the NWItem class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theProject.data.itemStatus.write(None, "New", (100, 100, 100))
|
theProject.data.itemStatus.write(None, "New", (100, 100, 100))
|
||||||
theProject.data.itemImport.write(None, "New", (100, 100, 100))
|
theProject.data.itemImport.write(None, "New", (100, 100, 100))
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ from novelwriter.gui.noveltree import NovelTreeColumn
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreOptions_LoadSave(monkeypatch, mockGUI, fncPath):
|
def testCoreOptions_LoadSave(monkeypatch, mockGUI, fncPath):
|
||||||
"""Test loading and saving from the OptionState class."""
|
"""Test loading and saving from the OptionState class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theOpts = OptionState(theProject)
|
theOpts = OptionState(theProject)
|
||||||
|
|
||||||
metaDir = fncPath / "meta"
|
metaDir = fncPath / "meta"
|
||||||
@@ -106,7 +106,7 @@ def testCoreOptions_LoadSave(monkeypatch, mockGUI, fncPath):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreOptions_SetGet(mockGUI):
|
def testCoreOptions_SetGet(mockGUI):
|
||||||
"""Test setting and getting values from the OptionState class."""
|
"""Test setting and getting values from the OptionState class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theOpts = OptionState(theProject)
|
theOpts = OptionState(theProject)
|
||||||
|
|
||||||
nwColHidden = NovelTreeColumn.HIDDEN
|
nwColHidden = NovelTreeColumn.HIDDEN
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import QMessageBox
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
@@ -27,7 +28,7 @@ from zipfile import ZipFile
|
|||||||
from mocked import causeOSError
|
from mocked import causeOSError
|
||||||
from tools import C, cmpFiles, buildTestProject, XML_IGNORE
|
from tools import C, cmpFiles, buildTestProject, XML_IGNORE
|
||||||
|
|
||||||
from novelwriter import CONFIG
|
from novelwriter import CONFIG, SHARED
|
||||||
from novelwriter.enum import nwItemClass
|
from novelwriter.enum import nwItemClass
|
||||||
from novelwriter.constants import nwFiles
|
from novelwriter.constants import nwFiles
|
||||||
from novelwriter.core.tree import NWTree
|
from novelwriter.core.tree import NWTree
|
||||||
@@ -44,7 +45,7 @@ def testCoreProject_NewRoot(fncPath, tstPaths, mockGUI, mockRnd):
|
|||||||
testFile = tstPaths.outDir / "coreProject_NewRoot_nwProject.nwx"
|
testFile = tstPaths.outDir / "coreProject_NewRoot_nwProject.nwx"
|
||||||
compFile = tstPaths.refDir / "coreProject_NewRoot_nwProject.nwx"
|
compFile = tstPaths.refDir / "coreProject_NewRoot_nwProject.nwx"
|
||||||
|
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
|
|
||||||
@@ -94,7 +95,7 @@ def testCoreProject_NewFileFolder(monkeypatch, fncPath, tstPaths, mockGUI, mockR
|
|||||||
testFile = tstPaths.outDir / "coreProject_NewFileFolder_nwProject.nwx"
|
testFile = tstPaths.outDir / "coreProject_NewFileFolder_nwProject.nwx"
|
||||||
compFile = tstPaths.refDir / "coreProject_NewFileFolder_nwProject.nwx"
|
compFile = tstPaths.refDir / "coreProject_NewFileFolder_nwProject.nwx"
|
||||||
|
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
|
|
||||||
@@ -163,7 +164,7 @@ def testCoreProject_NewFileFolder(monkeypatch, fncPath, tstPaths, mockGUI, mockR
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncPath, mockRnd):
|
def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncPath, mockRnd):
|
||||||
"""Test opening a project."""
|
"""Test opening a project."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
|
|
||||||
@@ -204,37 +205,40 @@ def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncPath, mockRnd):
|
|||||||
mp.setattr(ProjectXMLReader, "read", lambda *a: False)
|
mp.setattr(ProjectXMLReader, "read", lambda *a: False)
|
||||||
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.NOT_NWX_FILE))
|
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.NOT_NWX_FILE))
|
||||||
assert theProject.openProject(fncPath) is False
|
assert theProject.openProject(fncPath) is False
|
||||||
assert "Project file does not appear" in mockGUI.lastAlert
|
lastMsg = SHARED.alert.logMessage if SHARED.alert else ""
|
||||||
|
assert "Project file does not appear" in lastMsg
|
||||||
|
|
||||||
# Unknown project file version
|
# Unknown project file version
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr(ProjectXMLReader, "read", lambda *a: False)
|
mp.setattr(ProjectXMLReader, "read", lambda *a: False)
|
||||||
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.UNKNOWN_VERSION))
|
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.UNKNOWN_VERSION))
|
||||||
assert theProject.openProject(fncPath) is False
|
assert theProject.openProject(fncPath) is False
|
||||||
assert "Unknown or unsupported novelWriter project file" in mockGUI.lastAlert
|
lastMsg = SHARED.alert.logMessage if SHARED.alert else ""
|
||||||
|
assert "Unknown or unsupported novelWriter project file" in lastMsg
|
||||||
|
|
||||||
# Other parse error
|
# Other parse error
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr(ProjectXMLReader, "read", lambda *a: False)
|
mp.setattr(ProjectXMLReader, "read", lambda *a: False)
|
||||||
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.CANNOT_PARSE))
|
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.CANNOT_PARSE))
|
||||||
assert theProject.openProject(fncPath) is False
|
assert theProject.openProject(fncPath) is False
|
||||||
assert "Failed to parse project xml" in mockGUI.lastAlert
|
lastMsg = SHARED.alert.logMessage if SHARED.alert else ""
|
||||||
|
assert "Failed to parse project xml" in lastMsg
|
||||||
|
|
||||||
# Won't convert legacy file
|
# Won't convert legacy file
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.WAS_LEGACY))
|
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.WAS_LEGACY))
|
||||||
mockGUI.askResponse = False
|
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
|
||||||
assert theProject.openProject(fncPath) is False
|
assert theProject.openProject(fncPath) is False
|
||||||
assert "The file format of your project is about to be" in mockGUI.lastQuestion
|
lastMsg = SHARED.alert.logMessage if SHARED.alert else ""
|
||||||
mockGUI.askResponse = True
|
assert "The file format of your project is about to be" in lastMsg
|
||||||
|
|
||||||
# Won't open project from newer version
|
# Won't open project from newer version
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr(ProjectXMLReader, "hexVersion", property(lambda *a: 0x99999999))
|
mp.setattr(ProjectXMLReader, "hexVersion", property(lambda *a: 0x99999999))
|
||||||
mockGUI.askResponse = False
|
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
|
||||||
assert theProject.openProject(fncPath) is False
|
assert theProject.openProject(fncPath) is False
|
||||||
assert "This project was saved by a newer version" in mockGUI.lastQuestion
|
lastMsg = SHARED.alert.logMessage if SHARED.alert else ""
|
||||||
mockGUI.askResponse = True
|
assert "This project was saved by a newer version" in lastMsg
|
||||||
|
|
||||||
# Fail checking items should still pass
|
# Fail checking items should still pass
|
||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
@@ -247,10 +251,10 @@ def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncPath, mockRnd):
|
|||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.WAS_LEGACY))
|
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.WAS_LEGACY))
|
||||||
mp.setattr("novelwriter.core.index.NWIndex.loadIndex", lambda *a: True)
|
mp.setattr("novelwriter.core.index.NWIndex.loadIndex", lambda *a: True)
|
||||||
mockGUI.askResponse = True
|
|
||||||
theProject.index._indexBroken = True
|
theProject.index._indexBroken = True
|
||||||
assert theProject.openProject(fncPath) is True
|
assert theProject.openProject(fncPath) is True
|
||||||
assert "The file format of your project is about to be" in mockGUI.lastQuestion
|
lastMsg = SHARED.alert.logMessage if SHARED.alert else ""
|
||||||
|
assert "The file format of your project is about to be" in lastMsg
|
||||||
assert theProject.index._indexBroken is False
|
assert theProject.index._indexBroken is False
|
||||||
|
|
||||||
theProject.closeProject()
|
theProject.closeProject()
|
||||||
@@ -261,7 +265,7 @@ def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncPath, mockRnd):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreProject_Save(monkeypatch, mockGUI, mockRnd, fncPath):
|
def testCoreProject_Save(monkeypatch, mockGUI, mockRnd, fncPath):
|
||||||
"""Test saving a project."""
|
"""Test saving a project."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
|
|
||||||
# Nothing to save
|
# Nothing to save
|
||||||
assert theProject.saveProject() is False
|
assert theProject.saveProject() is False
|
||||||
@@ -290,7 +294,7 @@ def testCoreProject_Save(monkeypatch, mockGUI, mockRnd, fncPath):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreProject_AccessItems(mockGUI, fncPath, mockRnd):
|
def testCoreProject_AccessItems(mockGUI, fncPath, mockRnd):
|
||||||
"""Test helper functions for the project folder."""
|
"""Test helper functions for the project folder."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
|
|
||||||
# Storage Objects
|
# Storage Objects
|
||||||
@@ -354,7 +358,7 @@ def testCoreProject_AccessItems(mockGUI, fncPath, mockRnd):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreProject_StatusImport(mockGUI, fncPath, mockRnd):
|
def testCoreProject_StatusImport(mockGUI, fncPath, mockRnd):
|
||||||
"""Test the status and importance flag handling."""
|
"""Test the status and importance flag handling."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
|
|
||||||
@@ -463,7 +467,7 @@ def testCoreProject_StatusImport(mockGUI, fncPath, mockRnd):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreProject_Methods(monkeypatch, mockGUI, fncPath, mockRnd):
|
def testCoreProject_Methods(monkeypatch, mockGUI, fncPath, mockRnd):
|
||||||
"""Test other project class methods and functions."""
|
"""Test other project class methods and functions."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
|
|
||||||
# Project Name
|
# Project Name
|
||||||
@@ -581,7 +585,7 @@ def testCoreProject_Backup(monkeypatch, mockGUI, fncPath, tstPaths):
|
|||||||
backup file and checks that the project XML file is identical to
|
backup file and checks that the project XML file is identical to
|
||||||
the original file.
|
the original file.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
|
|
||||||
# No Project
|
# No Project
|
||||||
assert theProject.backupProject(doNotify=False) is False
|
assert theProject.backupProject(doNotify=False) is False
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ from novelwriter.core.sessions import NWSessionLog
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreSessions_Main(monkeypatch, mockGUI, fncPath):
|
def testCoreSessions_Main(monkeypatch, mockGUI, fncPath):
|
||||||
"""Test log file handling of the NWSessionLog class."""
|
"""Test log file handling of the NWSessionLog class."""
|
||||||
project = NWProject(mockGUI)
|
project = NWProject()
|
||||||
buildTestProject(project, fncPath)
|
buildTestProject(project, fncPath)
|
||||||
|
|
||||||
logFile = project.storage.getMetaFile(nwFiles.SESS_FILE)
|
logFile = project.storage.getMetaFile(nwFiles.SESS_FILE)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ from novelwriter.core.spellcheck import FakeEnchant, NWSpellEnchant, UserDiction
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreSpell_UserDictionary(monkeypatch, mockGUI, fncPath):
|
def testCoreSpell_UserDictionary(monkeypatch, mockGUI, fncPath):
|
||||||
"""Test the UserDictionary class."""
|
"""Test the UserDictionary class."""
|
||||||
project = NWProject(mockGUI)
|
project = NWProject()
|
||||||
buildTestProject(project, fncPath)
|
buildTestProject(project, fncPath)
|
||||||
|
|
||||||
# Check that there is no file before we start
|
# Check that there is no file before we start
|
||||||
@@ -114,7 +114,7 @@ def testCoreSpell_UserDictionary(monkeypatch, mockGUI, fncPath):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreSpell_FakeEnchant(monkeypatch, mockGUI, fncPath):
|
def testCoreSpell_FakeEnchant(monkeypatch, mockGUI, fncPath):
|
||||||
"""Test the FakeEnchant spell checker fallback."""
|
"""Test the FakeEnchant spell checker fallback."""
|
||||||
project = NWProject(mockGUI)
|
project = NWProject()
|
||||||
buildTestProject(project, fncPath)
|
buildTestProject(project, fncPath)
|
||||||
|
|
||||||
# Make package import fail
|
# Make package import fail
|
||||||
@@ -149,7 +149,7 @@ def testCoreSpell_FakeEnchant(monkeypatch, mockGUI, fncPath):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreSpell_Enchant(monkeypatch, mockGUI, fncPath):
|
def testCoreSpell_Enchant(monkeypatch, mockGUI, fncPath):
|
||||||
"""Test the pyenchant spell checker."""
|
"""Test the pyenchant spell checker."""
|
||||||
project = NWProject(mockGUI)
|
project = NWProject()
|
||||||
buildTestProject(project, fncPath)
|
buildTestProject(project, fncPath)
|
||||||
|
|
||||||
# Break the enchant package, and check error handling
|
# Break the enchant package, and check error handling
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class MockProject:
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreStorage_OpenProjectInPlace(mockGUI, fncPath, mockRnd):
|
def testCoreStorage_OpenProjectInPlace(mockGUI, fncPath, mockRnd):
|
||||||
"""Test opening a project in a folder."""
|
"""Test opening a project in a folder."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
theProject.closeProject()
|
theProject.closeProject()
|
||||||
@@ -180,7 +180,7 @@ def testCoreStorage_ZipIt(monkeypatch, mockGUI, fncPath, tstPaths, mockRnd):
|
|||||||
"""Test making a zip archive of a project."""
|
"""Test making a zip archive of a project."""
|
||||||
zipFile = tstPaths.tmpDir / "project.zip"
|
zipFile = tstPaths.tmpDir / "project.zip"
|
||||||
|
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
storage = theProject.storage
|
storage = theProject.storage
|
||||||
assert storage.zipIt(zipFile) is False
|
assert storage.zipIt(zipFile) is False
|
||||||
|
|
||||||
@@ -365,7 +365,7 @@ def testCoreStorage_DeprecatedFiles(monkeypatch, fncPath):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreStorage_OldFormatConvert(monkeypatch, mockGUI, fncPath):
|
def testCoreStorage_OldFormatConvert(monkeypatch, mockGUI, fncPath):
|
||||||
"""Test cleanup of deprecated files that needs to be converted."""
|
"""Test cleanup of deprecated files that needs to be converted."""
|
||||||
project = NWProject(mockGUI)
|
project = NWProject()
|
||||||
buildTestProject(project, fncPath)
|
buildTestProject(project, fncPath)
|
||||||
legacy = _LegacyStorage(project)
|
legacy = _LegacyStorage(project)
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ from novelwriter.core.project import NWProject
|
|||||||
def testCoreToHtml_ConvertFormat(mockGUI):
|
def testCoreToHtml_ConvertFormat(mockGUI):
|
||||||
"""Test the tokenizer and converter chain using the ToHtml class.
|
"""Test the tokenizer and converter chain using the ToHtml class.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theHtml = ToHtml(theProject)
|
theHtml = ToHtml(theProject)
|
||||||
|
|
||||||
# Novel Files Headers
|
# Novel Files Headers
|
||||||
@@ -233,7 +233,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
|||||||
def testCoreToHtml_ConvertDirect(mockGUI):
|
def testCoreToHtml_ConvertDirect(mockGUI):
|
||||||
"""Test the converter directly using the ToHtml class.
|
"""Test the converter directly using the ToHtml class.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theHtml = ToHtml(theProject)
|
theHtml = ToHtml(theProject)
|
||||||
|
|
||||||
theHtml._isNovel = True
|
theHtml._isNovel = True
|
||||||
@@ -380,7 +380,7 @@ def testCoreToHtml_ConvertDirect(mockGUI):
|
|||||||
def testCoreToHtml_SpecialCases(mockGUI):
|
def testCoreToHtml_SpecialCases(mockGUI):
|
||||||
"""Test some special cases that have caused errors in the past.
|
"""Test some special cases that have caused errors in the past.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theHtml = ToHtml(theProject)
|
theHtml = ToHtml(theProject)
|
||||||
theHtml._isNovel = True
|
theHtml._isNovel = True
|
||||||
|
|
||||||
@@ -454,7 +454,7 @@ def testCoreToHtml_SpecialCases(mockGUI):
|
|||||||
def testCoreToHtml_Complex(mockGUI, fncPath):
|
def testCoreToHtml_Complex(mockGUI, fncPath):
|
||||||
"""Test the save method of the ToHtml class.
|
"""Test the save method of the ToHtml class.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theHtml = ToHtml(theProject)
|
theHtml = ToHtml(theProject)
|
||||||
theHtml._isNovel = True
|
theHtml._isNovel = True
|
||||||
|
|
||||||
@@ -549,7 +549,7 @@ def testCoreToHtml_Complex(mockGUI, fncPath):
|
|||||||
def testCoreToHtml_Methods(mockGUI):
|
def testCoreToHtml_Methods(mockGUI):
|
||||||
"""Test all the other methods of the ToHtml class.
|
"""Test all the other methods of the ToHtml class.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theHtml = ToHtml(theProject)
|
theHtml = ToHtml(theProject)
|
||||||
theHtml.setKeepMarkdown(True)
|
theHtml.setKeepMarkdown(True)
|
||||||
|
|
||||||
@@ -609,7 +609,7 @@ def testCoreToHtml_Methods(mockGUI):
|
|||||||
def testCoreToHtml_Format(mockGUI):
|
def testCoreToHtml_Format(mockGUI):
|
||||||
"""Test all the formatters for the ToHtml class.
|
"""Test all the formatters for the ToHtml class.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theHtml = ToHtml(theProject)
|
theHtml = ToHtml(theProject)
|
||||||
|
|
||||||
# Export Mode
|
# Export Mode
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class BareTokenizer(Tokenizer):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToken_Setters(mockGUI):
|
def testCoreToken_Setters(mockGUI):
|
||||||
"""Test all the setters for the Tokenizer class."""
|
"""Test all the setters for the Tokenizer class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theToken = BareTokenizer(theProject)
|
theToken = BareTokenizer(theProject)
|
||||||
|
|
||||||
# Verify defaults
|
# Verify defaults
|
||||||
@@ -133,7 +133,7 @@ def testCoreToken_Setters(mockGUI):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToken_TextOps(monkeypatch, mockGUI, mockRnd, fncPath):
|
def testCoreToken_TextOps(monkeypatch, mockGUI, mockRnd, fncPath):
|
||||||
"""Test handling files and text in the Tokenizer class."""
|
"""Test handling files and text in the Tokenizer class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
mockRnd.reset()
|
mockRnd.reset()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
|
|
||||||
@@ -231,7 +231,7 @@ def testCoreToken_StripEscape():
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToken_HeaderFormat(mockGUI):
|
def testCoreToken_HeaderFormat(mockGUI):
|
||||||
"""Test the tokenization of header formats in the Tokenizer class."""
|
"""Test the tokenization of header formats in the Tokenizer class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theToken = BareTokenizer(theProject)
|
theToken = BareTokenizer(theProject)
|
||||||
theToken.setKeepMarkdown(True)
|
theToken.setKeepMarkdown(True)
|
||||||
|
|
||||||
@@ -434,7 +434,7 @@ def testCoreToken_HeaderFormat(mockGUI):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToken_MetaFormat(mockGUI):
|
def testCoreToken_MetaFormat(mockGUI):
|
||||||
"""Test the tokenization of meta formats in the Tokenizer class."""
|
"""Test the tokenization of meta formats in the Tokenizer class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theToken = BareTokenizer(theProject)
|
theToken = BareTokenizer(theProject)
|
||||||
theToken.setKeepMarkdown(True)
|
theToken.setKeepMarkdown(True)
|
||||||
|
|
||||||
@@ -502,7 +502,7 @@ def testCoreToken_MetaFormat(mockGUI):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToken_MarginFormat(mockGUI):
|
def testCoreToken_MarginFormat(mockGUI):
|
||||||
"""Test the tokenization of margin formats in the Tokenizer class."""
|
"""Test the tokenization of margin formats in the Tokenizer class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theToken = BareTokenizer(theProject)
|
theToken = BareTokenizer(theProject)
|
||||||
theToken.setKeepMarkdown(True)
|
theToken.setKeepMarkdown(True)
|
||||||
|
|
||||||
@@ -556,7 +556,7 @@ def testCoreToken_MarginFormat(mockGUI):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToken_TextFormat(mockGUI):
|
def testCoreToken_TextFormat(mockGUI):
|
||||||
"""Test the tokenization of text formats in the Tokenizer class."""
|
"""Test the tokenization of text formats in the Tokenizer class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theToken = BareTokenizer(theProject)
|
theToken = BareTokenizer(theProject)
|
||||||
theToken.setKeepMarkdown(True)
|
theToken.setKeepMarkdown(True)
|
||||||
|
|
||||||
@@ -677,7 +677,7 @@ def testCoreToken_TextFormat(mockGUI):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToken_SpecialFormat(mockGUI):
|
def testCoreToken_SpecialFormat(mockGUI):
|
||||||
"""Test the tokenization of special formats in the Tokenizer class."""
|
"""Test the tokenization of special formats in the Tokenizer class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theToken = BareTokenizer(theProject)
|
theToken = BareTokenizer(theProject)
|
||||||
|
|
||||||
theToken._isNovel = True
|
theToken._isNovel = True
|
||||||
@@ -879,7 +879,7 @@ def testCoreToken_SpecialFormat(mockGUI):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToken_ProcessHeaders(mockGUI):
|
def testCoreToken_ProcessHeaders(mockGUI):
|
||||||
"""Test the header and page parser of the Tokenizer class."""
|
"""Test the header and page parser of the Tokenizer class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theProject.data.setLanguage("en")
|
theProject.data.setLanguage("en")
|
||||||
theProject._loadProjectLocalisation()
|
theProject._loadProjectLocalisation()
|
||||||
theToken = BareTokenizer(theProject)
|
theToken = BareTokenizer(theProject)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ def testCoreToMarkdown_ConvertFormat(mockGUI):
|
|||||||
"""Test the tokenizer and converter chain using the ToMarkdown
|
"""Test the tokenizer and converter chain using the ToMarkdown
|
||||||
class.
|
class.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theMD = ToMarkdown(theProject)
|
theMD = ToMarkdown(theProject)
|
||||||
|
|
||||||
# Headers
|
# Headers
|
||||||
@@ -159,7 +159,7 @@ def testCoreToMarkdown_ConvertFormat(mockGUI):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToMarkdown_ConvertDirect(mockGUI):
|
def testCoreToMarkdown_ConvertDirect(mockGUI):
|
||||||
"""Test the converter directly using the ToMarkdown class."""
|
"""Test the converter directly using the ToMarkdown class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theMD = ToMarkdown(theProject)
|
theMD = ToMarkdown(theProject)
|
||||||
|
|
||||||
theMD._isNovel = True
|
theMD._isNovel = True
|
||||||
@@ -209,7 +209,7 @@ def testCoreToMarkdown_ConvertDirect(mockGUI):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToMarkdown_Complex(mockGUI, fncPath):
|
def testCoreToMarkdown_Complex(mockGUI, fncPath):
|
||||||
"""Test the save method of the ToMarkdown class."""
|
"""Test the save method of the ToMarkdown class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theMD = ToMarkdown(theProject)
|
theMD = ToMarkdown(theProject)
|
||||||
theMD._isNovel = True
|
theMD._isNovel = True
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@ def testCoreToMarkdown_Complex(mockGUI, fncPath):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToMarkdown_Format(mockGUI):
|
def testCoreToMarkdown_Format(mockGUI):
|
||||||
"""Test all the formatters for the ToMarkdown class."""
|
"""Test all the formatters for the ToMarkdown class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theMD = ToMarkdown(theProject)
|
theMD = ToMarkdown(theProject)
|
||||||
|
|
||||||
assert theMD._formatKeywords("", theMD.A_NONE) == ""
|
assert theMD._formatKeywords("", theMD.A_NONE) == ""
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ def xmlToText(xElem):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToOdt_Init(mockGUI):
|
def testCoreToOdt_Init(mockGUI):
|
||||||
"""Test initialisation of the ODT document."""
|
"""Test initialisation of the ODT document."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
|
|
||||||
# Flat Doc
|
# Flat Doc
|
||||||
# ========
|
# ========
|
||||||
@@ -108,7 +108,7 @@ def testCoreToOdt_Init(mockGUI):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToOdt_TextFormatting(mockGUI):
|
def testCoreToOdt_TextFormatting(mockGUI):
|
||||||
"""Test formatting of paragraphs."""
|
"""Test formatting of paragraphs."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theDoc = ToOdt(theProject, isFlat=True)
|
theDoc = ToOdt(theProject, isFlat=True)
|
||||||
|
|
||||||
theDoc.initDocument()
|
theDoc.initDocument()
|
||||||
@@ -242,7 +242,7 @@ def testCoreToOdt_TextFormatting(mockGUI):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToOdt_Convert(mockGUI):
|
def testCoreToOdt_Convert(mockGUI):
|
||||||
"""Test the converter of the ToOdt class."""
|
"""Test the converter of the ToOdt class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theDoc = ToOdt(theProject, isFlat=True)
|
theDoc = ToOdt(theProject, isFlat=True)
|
||||||
|
|
||||||
theDoc._isNovel = True
|
theDoc._isNovel = True
|
||||||
@@ -573,7 +573,7 @@ def testCoreToOdt_ConvertDirect(mockGUI):
|
|||||||
"""Test the converter directly using the ToOdt class to reach some
|
"""Test the converter directly using the ToOdt class to reach some
|
||||||
otherwise hard to reach conditions.
|
otherwise hard to reach conditions.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theDoc = ToOdt(theProject, isFlat=True)
|
theDoc = ToOdt(theProject, isFlat=True)
|
||||||
|
|
||||||
theDoc._isNovel = True
|
theDoc._isNovel = True
|
||||||
@@ -626,7 +626,7 @@ def testCoreToOdt_ConvertDirect(mockGUI):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToOdt_SaveFlat(mockGUI, fncPath, tstPaths):
|
def testCoreToOdt_SaveFlat(mockGUI, fncPath, tstPaths):
|
||||||
"""Test the document save functions."""
|
"""Test the document save functions."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theProject.data.setAuthor("Jane Smith")
|
theProject.data.setAuthor("Jane Smith")
|
||||||
theProject.data.setName("Test Project")
|
theProject.data.setName("Test Project")
|
||||||
theProject.data.setSaveCount(1234)
|
theProject.data.setSaveCount(1234)
|
||||||
@@ -668,7 +668,7 @@ def testCoreToOdt_SaveFlat(mockGUI, fncPath, tstPaths):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToOdt_SaveFull(mockGUI, fncPath, tstPaths):
|
def testCoreToOdt_SaveFull(mockGUI, fncPath, tstPaths):
|
||||||
"""Test the document save functions."""
|
"""Test the document save functions."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theProject.data.setAuthor("Jane Smith")
|
theProject.data.setAuthor("Jane Smith")
|
||||||
theProject.data.setName("Test Project")
|
theProject.data.setName("Test Project")
|
||||||
theProject.data.setSaveCount(1234)
|
theProject.data.setSaveCount(1234)
|
||||||
@@ -745,7 +745,7 @@ def testCoreToOdt_SaveFull(mockGUI, fncPath, tstPaths):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToOdt_Format(mockGUI):
|
def testCoreToOdt_Format(mockGUI):
|
||||||
"""Test the formatters for the ToOdt class."""
|
"""Test the formatters for the ToOdt class."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theDoc = ToOdt(theProject, isFlat=True)
|
theDoc = ToOdt(theProject, isFlat=True)
|
||||||
|
|
||||||
assert theDoc._formatSynopsis("synopsis text") == (
|
assert theDoc._formatSynopsis("synopsis text") == (
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ from novelwriter.core.project import NWProject
|
|||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
def mockItems(mockGUI, mockRnd):
|
def mockItems(mockGUI, mockRnd):
|
||||||
"""Create a list of mock items."""
|
"""Create a list of mock items."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
|
|
||||||
itemA = NWItem(theProject, "a000000000001")
|
itemA = NWItem(theProject, "a000000000001")
|
||||||
itemA._name = "Novel"
|
itemA._name = "Novel"
|
||||||
@@ -112,7 +112,7 @@ def mockItems(mockGUI, mockRnd):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTree_BuildTree(mockGUI, mockItems):
|
def testCoreTree_BuildTree(mockGUI, mockItems):
|
||||||
"""Test building a project tree from a list of items."""
|
"""Test building a project tree from a list of items."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theTree = NWTree(theProject)
|
theTree = NWTree(theProject)
|
||||||
|
|
||||||
# Check that tree is empty (calls NWTree.__bool__)
|
# Check that tree is empty (calls NWTree.__bool__)
|
||||||
@@ -269,7 +269,7 @@ def testCoreTree_BuildTree(mockGUI, mockItems):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTree_PackUnpack(mockGUI, mockItems):
|
def testCoreTree_PackUnpack(mockGUI, mockItems):
|
||||||
"""Test packing and unpacking data."""
|
"""Test packing and unpacking data."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theTree = NWTree(theProject)
|
theTree = NWTree(theProject)
|
||||||
|
|
||||||
aHandles = []
|
aHandles = []
|
||||||
@@ -298,7 +298,7 @@ def testCoreTree_PackUnpack(mockGUI, mockItems):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTree_CheckConsistency(caplog: pytest.LogCaptureFixture, mockGUI, fncPath, mockRnd):
|
def testCoreTree_CheckConsistency(caplog: pytest.LogCaptureFixture, mockGUI, fncPath, mockRnd):
|
||||||
"""Check the project consistency."""
|
"""Check the project consistency."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
buildTestProject(theProject, fncPath)
|
buildTestProject(theProject, fncPath)
|
||||||
|
|
||||||
# By default, all is well
|
# By default, all is well
|
||||||
@@ -365,7 +365,7 @@ def testCoreTree_CheckConsistency(caplog: pytest.LogCaptureFixture, mockGUI, fnc
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTree_Methods(mockGUI, mockItems):
|
def testCoreTree_Methods(mockGUI, mockItems):
|
||||||
"""Test various class methods."""
|
"""Test various class methods."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theTree = NWTree(theProject)
|
theTree = NWTree(theProject)
|
||||||
|
|
||||||
for nwItem in mockItems:
|
for nwItem in mockItems:
|
||||||
@@ -446,7 +446,7 @@ def testCoreTree_Methods(mockGUI, mockItems):
|
|||||||
def testCoreTree_MakeHandles(mockGUI):
|
def testCoreTree_MakeHandles(mockGUI):
|
||||||
"""Test generating item handles."""
|
"""Test generating item handles."""
|
||||||
random.seed(42)
|
random.seed(42)
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theTree = NWTree(theProject)
|
theTree = NWTree(theProject)
|
||||||
|
|
||||||
handles = ["1c803a3b1799d", "bdd6406671ad1", "3eb1346685257", "23b8c392456de"]
|
handles = ["1c803a3b1799d", "bdd6406671ad1", "3eb1346685257", "23b8c392456de"]
|
||||||
@@ -474,7 +474,7 @@ def testCoreTree_MakeHandles(mockGUI):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTree_Stats(mockGUI, mockItems):
|
def testCoreTree_Stats(mockGUI, mockItems):
|
||||||
"""Test project stats methods."""
|
"""Test project stats methods."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theTree = NWTree(theProject)
|
theTree = NWTree(theProject)
|
||||||
|
|
||||||
for nwItem in mockItems:
|
for nwItem in mockItems:
|
||||||
@@ -494,7 +494,7 @@ def testCoreTree_Stats(mockGUI, mockItems):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTree_Reorder(caplog, mockGUI, mockItems):
|
def testCoreTree_Reorder(caplog, mockGUI, mockItems):
|
||||||
"""Test changing tree order."""
|
"""Test changing tree order."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theTree = NWTree(theProject)
|
theTree = NWTree(theProject)
|
||||||
|
|
||||||
aHandle = []
|
aHandle = []
|
||||||
@@ -529,7 +529,7 @@ def testCoreTree_Reorder(caplog, mockGUI, mockItems):
|
|||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTree_ToCFile(monkeypatch, fncPath, mockGUI, mockItems):
|
def testCoreTree_ToCFile(monkeypatch, fncPath, mockGUI, mockItems):
|
||||||
"""Test writing the ToC.txt file."""
|
"""Test writing the ToC.txt file."""
|
||||||
theProject = NWProject(mockGUI)
|
theProject = NWProject()
|
||||||
theTree = NWTree(theProject)
|
theTree = NWTree(theProject)
|
||||||
|
|
||||||
for nwItem in mockItems:
|
for nwItem in mockItems:
|
||||||
|
|||||||
Reference in New Issue
Block a user