Switch to Path objects nearly everywhere
This commit is contained in:
+5
-28
@@ -23,12 +23,12 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
import uuid
|
||||
import hashlib
|
||||
import logging
|
||||
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from configparser import ConfigParser
|
||||
|
||||
@@ -36,7 +36,7 @@ from PyQt5.QtCore import QCoreApplication
|
||||
from PyQt5.QtWidgets import qApp
|
||||
|
||||
from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
|
||||
from novelwriter.error import formatException, logException
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.constants import nwConst, nwUnicode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -458,20 +458,16 @@ def jsonEncode(data, n=0, nmax=0):
|
||||
def readTextFile(path):
|
||||
"""Read the content of a text file in a robust manner.
|
||||
"""
|
||||
if not os.path.isfile(path):
|
||||
path = Path(path)
|
||||
if not path.is_file():
|
||||
return ""
|
||||
|
||||
text = ""
|
||||
try:
|
||||
with open(path, mode="r", encoding="utf-8") as inFile:
|
||||
text = inFile.read()
|
||||
return path.read_text(encoding="utf-8")
|
||||
except Exception:
|
||||
logger.error("Could not read file: %s", path)
|
||||
logException()
|
||||
return ""
|
||||
|
||||
return text
|
||||
|
||||
|
||||
def makeFileNameSafe(value):
|
||||
"""Returns a filename safe string of the value.
|
||||
@@ -483,25 +479,6 @@ def makeFileNameSafe(value):
|
||||
return clean
|
||||
|
||||
|
||||
def ensureFolder(path, parent=None, errLog=None):
|
||||
"""Make sure a folder exists, and if it doesn't, create it.
|
||||
"""
|
||||
try:
|
||||
if parent:
|
||||
path = os.path.join(parent, path)
|
||||
if not os.path.isdir(path):
|
||||
os.mkdir(path)
|
||||
except Exception as exc:
|
||||
logger.error("Could not create folder: %s", path)
|
||||
logException()
|
||||
if isinstance(errLog, list):
|
||||
errLog.append(f"Could not create folder: {path}")
|
||||
errLog.append(formatException(exc))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def sha256sum(path):
|
||||
"""Make a shasum of a file using a buffer.
|
||||
Based on: https://stackoverflow.com/a/44873382/5825851
|
||||
|
||||
+21
-5
@@ -23,7 +23,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import logging
|
||||
@@ -184,7 +183,7 @@ class Config:
|
||||
self.searchMatchCap = False
|
||||
|
||||
# Backup Settings
|
||||
self.backupPath = ""
|
||||
self._backupPath = None
|
||||
self.backupOnClose = False
|
||||
self.askBeforeBackup = True
|
||||
|
||||
@@ -296,6 +295,14 @@ class Config:
|
||||
return self._lastPath
|
||||
return Path.home().absolute()
|
||||
|
||||
def backupPath(self):
|
||||
"""Return the backup path.
|
||||
"""
|
||||
if isinstance(self._backupPath, Path):
|
||||
if self._backupPath.is_dir():
|
||||
return self._backupPath
|
||||
return None
|
||||
|
||||
def errorText(self):
|
||||
"""Compile and return error messages from the initialisation of
|
||||
the Config class, and clear the error buffer.
|
||||
@@ -369,7 +376,7 @@ class Config:
|
||||
lngFile = "%s_%s" % (lngBase, lngCode.replace("-", "_"))
|
||||
if lngFile not in self._qtTrans:
|
||||
if qTrans.load(lngFile, str(lngPath)):
|
||||
logger.debug("Loaded: %s", os.path.join(lngPath, lngFile))
|
||||
logger.debug("Loaded: %s/%s", lngPath, lngFile)
|
||||
nwApp.installTranslator(qTrans)
|
||||
self._qtTrans[lngFile] = qTrans
|
||||
|
||||
@@ -489,9 +496,10 @@ class Config:
|
||||
|
||||
# Backup
|
||||
cnfSec = "Backup"
|
||||
self.backupPath = theConf.rdStr(cnfSec, "backuppath", self.backupPath)
|
||||
backupPath = theConf.rdStr(cnfSec, "backuppath", None)
|
||||
self.backupOnClose = theConf.rdBool(cnfSec, "backuponclose", self.backupOnClose)
|
||||
self.askBeforeBackup = theConf.rdBool(cnfSec, "askbeforebackup", self.askBeforeBackup)
|
||||
self.setBackupPath(backupPath)
|
||||
|
||||
# State
|
||||
cnfSec = "State"
|
||||
@@ -599,7 +607,7 @@ class Config:
|
||||
}
|
||||
|
||||
theConf["Backup"] = {
|
||||
"backuppath": str(self.backupPath),
|
||||
"backuppath": str(self._backupPath or ""),
|
||||
"backuponclose": str(self.backupOnClose),
|
||||
"askbeforebackup": str(self.askBeforeBackup),
|
||||
}
|
||||
@@ -653,6 +661,14 @@ class Config:
|
||||
logger.debug("Last path updated: %s" % self._lastPath)
|
||||
return
|
||||
|
||||
def setBackupPath(self, backupPath):
|
||||
"""Set the current backup path.
|
||||
"""
|
||||
self._backupPath = None
|
||||
if isinstance(backupPath, (str, Path)):
|
||||
self._backupPath = Path(backupPath)
|
||||
return
|
||||
|
||||
def setWinSize(self, newWidth, newHeight):
|
||||
"""Set the size of the main window, but only if the change is
|
||||
larger than 5 pixels. The OS window manager will sometimes
|
||||
|
||||
@@ -456,7 +456,8 @@ class NWProject(QObject):
|
||||
logger.info("Backing up project")
|
||||
self.mainGui.setStatus(self.tr("Backing up project ..."))
|
||||
|
||||
if not self.mainConf.backupPath:
|
||||
backupPath = self.mainConf.backupPath()
|
||||
if not isinstance(backupPath, Path):
|
||||
self.mainGui.makeAlert(self.tr(
|
||||
"Cannot backup project because no valid backup path is set. "
|
||||
"Please set a valid backup location in Preferences."
|
||||
@@ -471,7 +472,7 @@ class NWProject(QObject):
|
||||
return False
|
||||
|
||||
cleanName = makeFileNameSafe(self._data.name)
|
||||
baseDir = Path(self.mainConf.backupPath) / cleanName
|
||||
baseDir = backupPath / cleanName
|
||||
try:
|
||||
baseDir.mkdir(exist_ok=True)
|
||||
except Exception as exc:
|
||||
|
||||
@@ -23,7 +23,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
import novelwriter
|
||||
|
||||
@@ -384,7 +383,7 @@ class GuiPreferencesProjects(QWidget):
|
||||
self.mainForm.addGroupLabel(self.tr("Project Backup"))
|
||||
|
||||
# Backup Path
|
||||
self.backupPath = self.mainConf.backupPath
|
||||
self.backupPath = self.mainConf.backupPath()
|
||||
self.backupGetPath = QPushButton(self.tr("Browse"))
|
||||
self.backupGetPath.clicked.connect(self._backupFolder)
|
||||
self.backupPathRow = self.mainForm.addRow(
|
||||
@@ -451,7 +450,7 @@ class GuiPreferencesProjects(QWidget):
|
||||
self.mainConf.autoSaveProj = self.autoSaveProj.value()
|
||||
|
||||
# Project Backup
|
||||
self.mainConf.backupPath = self.backupPath
|
||||
self.mainConf.setBackupPath(self.backupPath)
|
||||
self.mainConf.backupOnClose = self.backupOnClose.isChecked()
|
||||
self.mainConf.askBeforeBackup = self.askBeforeBackup.isChecked()
|
||||
|
||||
@@ -470,12 +469,9 @@ class GuiPreferencesProjects(QWidget):
|
||||
def _backupFolder(self):
|
||||
"""Open a dialog to select the backup folder.
|
||||
"""
|
||||
currDir = self.backupPath
|
||||
if not os.path.isdir(currDir):
|
||||
currDir = ""
|
||||
|
||||
currDir = self.backupPath or ""
|
||||
newDir = QFileDialog.getExistingDirectory(
|
||||
self, self.tr("Backup Directory"), currDir, options=QFileDialog.ShowDirsOnly
|
||||
self, self.tr("Backup Directory"), str(currDir), options=QFileDialog.ShowDirsOnly
|
||||
)
|
||||
if newDir:
|
||||
self.backupPath = newDir
|
||||
|
||||
@@ -23,10 +23,10 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
import novelwriter
|
||||
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
from PyQt5.QtGui import QKeySequence
|
||||
@@ -190,8 +190,8 @@ class GuiProjectLoad(QDialog):
|
||||
self, self.tr("Open Project"), "", filter=";;".join(extFilter)
|
||||
)
|
||||
if projFile:
|
||||
thePath = os.path.abspath(os.path.dirname(projFile))
|
||||
self.selPath.setText(thePath)
|
||||
thePath = Path(projFile).absolute()
|
||||
self.selPath.setText(str(thePath))
|
||||
self.openPath = thePath
|
||||
self.openState = self.OPEN_STATE
|
||||
self.accept()
|
||||
|
||||
@@ -826,7 +826,7 @@ class GuiMainMenu(QMenuBar):
|
||||
|
||||
# Tools > Backup
|
||||
self.aBackupProject = QAction(self.tr("Backup Project"), self)
|
||||
self.aBackupProject.triggered.connect(lambda: self.theProject.backupProject(doNoify=True))
|
||||
self.aBackupProject.triggered.connect(lambda: self.theProject.backupProject(True))
|
||||
self.toolsMenu.addAction(self.aBackupProject)
|
||||
|
||||
# Tools > Export Project
|
||||
|
||||
@@ -23,7 +23,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
import novelwriter
|
||||
|
||||
@@ -362,7 +361,7 @@ class GuiMain(QMainWindow):
|
||||
logger.error("No projData or projPath set")
|
||||
return False
|
||||
|
||||
if os.path.isfile(os.path.join(projPath, nwFiles.PROJ_FILE)):
|
||||
if (Path(projPath) / nwFiles.PROJ_FILE).is_file():
|
||||
self.makeAlert(self.tr(
|
||||
"A project already exists in that location. "
|
||||
"Please choose another folder."
|
||||
@@ -414,7 +413,7 @@ class GuiMain(QMainWindow):
|
||||
if not msgYes:
|
||||
doBackup = False
|
||||
if doBackup:
|
||||
self.theProject.backupProject(doNotify=False)
|
||||
self.theProject.backupProject(False)
|
||||
else:
|
||||
saveOK = True
|
||||
|
||||
|
||||
+38
-70
@@ -19,7 +19,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
import shutil
|
||||
@@ -50,25 +49,14 @@ def initQt(qtbot):
|
||||
##
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def tmpDir():
|
||||
"""A temporary folder for the test session. This folder is
|
||||
presistent after the test so that the status of generated files can
|
||||
be checked. The folder is instead cleared before a new test session.
|
||||
"""
|
||||
testDir = os.path.dirname(__file__)
|
||||
theDir = os.path.join(testDir, "temp")
|
||||
if os.path.isdir(theDir):
|
||||
shutil.rmtree(theDir)
|
||||
if not os.path.isdir(theDir):
|
||||
os.mkdir(theDir)
|
||||
return theDir
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def tmpPath(tmpDir):
|
||||
def tmpPath():
|
||||
"""A temporary folder for the test session. Path version.
|
||||
"""
|
||||
return Path(tmpDir)
|
||||
theTemp = Path(__file__).parent / "temp"
|
||||
if theTemp.exists():
|
||||
shutil.rmtree(theTemp)
|
||||
theTemp.mkdir(exist_ok=True)
|
||||
return theTemp
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
@@ -99,57 +87,15 @@ def fncPath(tmpPath):
|
||||
return fncPath
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def refDir():
|
||||
"""The folder where all the reference files are stored for verifying
|
||||
the results of tests.
|
||||
"""
|
||||
testDir = os.path.dirname(__file__)
|
||||
theDir = os.path.join(testDir, "reference")
|
||||
return theDir
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def filesDir():
|
||||
"""The folder where additional test files are stored.
|
||||
"""
|
||||
testDir = os.path.dirname(__file__)
|
||||
theDir = os.path.join(testDir, "files")
|
||||
return theDir
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def outDir(tmpDir):
|
||||
"""An output folder for test results
|
||||
"""
|
||||
theDir = os.path.join(tmpDir, "results")
|
||||
if not os.path.isdir(theDir):
|
||||
os.mkdir(theDir)
|
||||
return theDir
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def fncDir(tmpDir):
|
||||
"""A temporary folder for a single test function.
|
||||
"""
|
||||
fncDir = os.path.join(tmpDir, "function")
|
||||
if os.path.isdir(fncDir):
|
||||
shutil.rmtree(fncDir)
|
||||
if not os.path.isdir(fncDir):
|
||||
os.mkdir(fncDir)
|
||||
return fncDir
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def fncProj(fncDir):
|
||||
def projPath(fncPath):
|
||||
"""A temporary folder for a single test function,
|
||||
with a project folder.
|
||||
"""
|
||||
prjDir = os.path.join(fncDir, "project")
|
||||
if os.path.isdir(prjDir):
|
||||
prjDir = fncPath / "project"
|
||||
if prjDir.exists():
|
||||
shutil.rmtree(prjDir)
|
||||
if not os.path.isdir(prjDir):
|
||||
os.mkdir(prjDir)
|
||||
prjDir.mkdir(exist_ok=True)
|
||||
return prjDir
|
||||
|
||||
|
||||
@@ -252,14 +198,36 @@ def mockRnd(monkeypatch):
|
||||
##
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def nwLipsum(tmpDir):
|
||||
def nwLipsum(tmpPath):
|
||||
"""A medium sized novelWriter example project with a lot of Lorem
|
||||
Ipsum text.
|
||||
"""
|
||||
tstDir = os.path.dirname(__file__)
|
||||
srcDir = os.path.join(tstDir, "lipsum")
|
||||
dstDir = os.path.join(tmpDir, "lipsum")
|
||||
if os.path.isdir(dstDir):
|
||||
tstDir = Path(__file__).parent
|
||||
srcDir = tstDir / "lipsum"
|
||||
dstDir = tmpPath / "lipsum"
|
||||
if dstDir.exists():
|
||||
shutil.rmtree(dstDir)
|
||||
|
||||
shutil.copytree(srcDir, dstDir)
|
||||
cleanProject(dstDir)
|
||||
|
||||
yield str(dstDir)
|
||||
|
||||
if dstDir.exists():
|
||||
shutil.rmtree(dstDir)
|
||||
|
||||
return
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def prjLipsum(tmpPath):
|
||||
"""A medium sized novelWriter example project with a lot of Lorem
|
||||
Ipsum text.
|
||||
"""
|
||||
tstDir = Path(__file__).parent
|
||||
srcDir = tstDir / "lipsum"
|
||||
dstDir = tmpPath / "lipsum"
|
||||
if dstDir.exists():
|
||||
shutil.rmtree(dstDir)
|
||||
|
||||
shutil.copytree(srcDir, dstDir)
|
||||
@@ -267,7 +235,7 @@ def nwLipsum(tmpDir):
|
||||
|
||||
yield dstDir
|
||||
|
||||
if os.path.isdir(dstDir):
|
||||
if dstDir.exists():
|
||||
shutil.rmtree(dstDir)
|
||||
|
||||
return
|
||||
|
||||
@@ -19,10 +19,9 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import time
|
||||
import pytest
|
||||
import hashlib
|
||||
|
||||
from mock import causeOSError
|
||||
from tools import writeFile
|
||||
@@ -33,8 +32,8 @@ from novelwriter.common import (
|
||||
checkUuid, isHandle, isTitleTag, isItemClass, isItemType, isItemLayout,
|
||||
hexToInt, minmax, checkIntTuple, formatInt, formatTimeStamp, formatTime,
|
||||
simplified, yesNo, splitVersionNumber, transferCase, fuzzyTime,
|
||||
numberToRoman, jsonEncode, readTextFile, makeFileNameSafe, ensureFolder,
|
||||
sha256sum, getGuiItem, NWConfigParser
|
||||
numberToRoman, jsonEncode, readTextFile, makeFileNameSafe, sha256sum,
|
||||
getGuiItem, NWConfigParser
|
||||
)
|
||||
|
||||
|
||||
@@ -591,18 +590,18 @@ def testBaseCommon_JsonEncode():
|
||||
|
||||
|
||||
@pytest.mark.base
|
||||
def testBaseCommon_ReadTextFile(monkeypatch, fncDir, ipsumText):
|
||||
def testBaseCommon_ReadTextFile(monkeypatch, fncPath, ipsumText):
|
||||
"""Test the readTextFile function.
|
||||
"""
|
||||
testText = "\n\n".join(ipsumText) + "\n"
|
||||
testFile = os.path.join(fncDir, "ipsum.txt")
|
||||
testFile = fncPath / "ipsum.txt"
|
||||
writeFile(testFile, testText)
|
||||
|
||||
assert readTextFile(os.path.join(fncDir, "not_a_file.txt")) == ""
|
||||
assert readTextFile(fncPath / "not_a_file.txt") == ""
|
||||
assert readTextFile(testFile) == testText
|
||||
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr("builtins.open", causeOSError)
|
||||
mp.setattr("pathlib.Path.read_text", causeOSError)
|
||||
assert readTextFile(testFile) == ""
|
||||
|
||||
# END Test testBaseCommon_ReadTextFile
|
||||
@@ -621,33 +620,7 @@ def testBaseCommon_MakeFileNameSafe():
|
||||
|
||||
|
||||
@pytest.mark.base
|
||||
def testBaseCommon_EnsureFolder(monkeypatch, fncDir):
|
||||
"""Test the ensureFolder function.
|
||||
"""
|
||||
newDir1 = os.path.join(fncDir, "newDir1")
|
||||
newDir2 = os.path.join(fncDir, "newDir2")
|
||||
newDir3 = os.path.join(fncDir, "newDir3")
|
||||
|
||||
assert ensureFolder(None) is False
|
||||
|
||||
assert ensureFolder(newDir1) is True
|
||||
assert os.path.isdir(newDir1)
|
||||
|
||||
assert ensureFolder("newDir2", parent=fncDir) is True
|
||||
assert os.path.isdir(newDir2)
|
||||
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr("os.mkdir", causeOSError)
|
||||
errLog = []
|
||||
assert ensureFolder("newDir3", parent=fncDir, errLog=errLog) is False
|
||||
assert errLog[0] == f"Could not create folder: {newDir3}"
|
||||
assert not os.path.isdir(newDir3)
|
||||
|
||||
# END Test testBaseCommon_EnsureFolder
|
||||
|
||||
|
||||
@pytest.mark.base
|
||||
def testBaseCommon_Sha256Sum(monkeypatch, fncDir, ipsumText):
|
||||
def testBaseCommon_Sha256Sum(monkeypatch, fncPath, ipsumText):
|
||||
"""Test the sha256sum function.
|
||||
"""
|
||||
longText = 50*(" ".join(ipsumText) + " ")
|
||||
@@ -656,9 +629,9 @@ def testBaseCommon_Sha256Sum(monkeypatch, fncDir, ipsumText):
|
||||
|
||||
assert len(longText) == 175650
|
||||
|
||||
longFile = os.path.join(fncDir, "long_file.txt")
|
||||
shortFile = os.path.join(fncDir, "short_file.txt")
|
||||
noneFile = os.path.join(fncDir, "none_file.txt")
|
||||
longFile = fncPath / "long_file.txt"
|
||||
shortFile = fncPath / "short_file.txt"
|
||||
noneFile = fncPath / "none_file.txt"
|
||||
|
||||
writeFile(longFile, longText)
|
||||
writeFile(shortFile, shortText)
|
||||
@@ -697,10 +670,10 @@ def testBaseCommon_GetGuiItem(nwGUI):
|
||||
|
||||
|
||||
@pytest.mark.base
|
||||
def testBaseCommon_NWConfigParser(fncDir):
|
||||
def testBaseCommon_NWConfigParser(fncPath):
|
||||
"""Test the NWConfigParser subclass.
|
||||
"""
|
||||
tstConf = os.path.join(fncDir, "test.cfg")
|
||||
tstConf = fncPath / "test.cfg"
|
||||
writeFile(tstConf, (
|
||||
"[main]\n"
|
||||
"stropt = value\n"
|
||||
|
||||
@@ -20,9 +20,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import novelwriter
|
||||
|
||||
from PyQt5.QtWidgets import QMessageBox, qApp
|
||||
|
||||
from mock import causeException
|
||||
|
||||
@@ -30,18 +27,9 @@ from novelwriter.error import NWErrorMessage, exceptionHandler
|
||||
|
||||
|
||||
@pytest.mark.base
|
||||
def testBaseError_Dialog(qtbot, monkeypatch, fncDir, tmpDir):
|
||||
def testBaseError_Dialog(qtbot, monkeypatch, nwGUI):
|
||||
"""Test the error dialog.
|
||||
"""
|
||||
# Block message box
|
||||
monkeypatch.setattr(QMessageBox, "warning", lambda *a: QMessageBox.Yes)
|
||||
|
||||
qApp.closeAllWindows()
|
||||
nwGUI = novelwriter.main(["--testmode", "--config=%s" % fncDir, "--data=%s" % tmpDir])
|
||||
qtbot.addWidget(nwGUI)
|
||||
nwGUI.show()
|
||||
qtbot.wait(20)
|
||||
|
||||
nwErr = NWErrorMessage(nwGUI)
|
||||
qtbot.addWidget(nwErr)
|
||||
nwErr.show()
|
||||
@@ -76,19 +64,11 @@ def testBaseError_Dialog(qtbot, monkeypatch, fncDir, tmpDir):
|
||||
|
||||
|
||||
@pytest.mark.base
|
||||
def testBaseError_Handler(qtbot, monkeypatch, fncDir, tmpDir):
|
||||
def testBaseError_Handler(qtbot, monkeypatch, nwGUI):
|
||||
"""Test the error handler. This test doesn'thave any asserts, but it
|
||||
checks that the error handler handles potential exceptions. The test
|
||||
will fail if excpetions are not handled.
|
||||
"""
|
||||
monkeypatch.setattr(QMessageBox, "warning", lambda *a: QMessageBox.Yes)
|
||||
|
||||
qApp.closeAllWindows()
|
||||
nwGUI = novelwriter.main(["--testmode", "--config=%s" % fncDir, "--data=%s" % tmpDir])
|
||||
qtbot.addWidget(nwGUI)
|
||||
nwGUI.show()
|
||||
qtbot.wait(20)
|
||||
|
||||
# Normal shutdown
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(NWErrorMessage, "exec_", lambda *a: None)
|
||||
|
||||
@@ -28,13 +28,13 @@ from mock import MockGuiMain
|
||||
|
||||
|
||||
@pytest.mark.base
|
||||
def testBaseInit_Launch(caplog, monkeypatch, tmpDir):
|
||||
def testBaseInit_Launch(caplog, monkeypatch, tmpPath):
|
||||
"""Check launching the main GUI.
|
||||
"""
|
||||
monkeypatch.setattr("novelwriter.guimain.GuiMain", MockGuiMain)
|
||||
|
||||
# TestMode Launch
|
||||
nwGUI = novelwriter.main(["--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir])
|
||||
nwGUI = novelwriter.main(["--testmode", f"--config={tmpPath}", f"--data={tmpPath}"])
|
||||
assert isinstance(nwGUI, MockGuiMain)
|
||||
|
||||
# Darwin Launch
|
||||
@@ -43,7 +43,7 @@ def testBaseInit_Launch(caplog, monkeypatch, tmpDir):
|
||||
novelwriter.CONFIG.osDarwin = True
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setitem(sys.modules, "Foundation", None)
|
||||
nwGUI = novelwriter.main(["--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir])
|
||||
nwGUI = novelwriter.main(["--testmode", f"--config={tmpPath}", f"--data={tmpPath}"])
|
||||
assert isinstance(nwGUI, MockGuiMain)
|
||||
assert "Failed" in caplog.text
|
||||
|
||||
@@ -55,7 +55,7 @@ def testBaseInit_Launch(caplog, monkeypatch, tmpDir):
|
||||
novelwriter.CONFIG.osWindows = True
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setitem(sys.modules, "ctypes", None)
|
||||
nwGUI = novelwriter.main(["--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir])
|
||||
nwGUI = novelwriter.main(["--testmode", f"--config={tmpPath}", f"--data={tmpPath}"])
|
||||
assert isinstance(nwGUI, MockGuiMain)
|
||||
if not sys.platform.startswith("darwin"):
|
||||
# For some reason, the test doesn't work on macOS
|
||||
@@ -71,19 +71,19 @@ def testBaseInit_Launch(caplog, monkeypatch, tmpDir):
|
||||
monkeypatch.setattr("PyQt5.QtWidgets.QApplication.setOrganizationDomain", lambda *a: None)
|
||||
monkeypatch.setattr("PyQt5.QtWidgets.QApplication.exec_", lambda *a: 0)
|
||||
with pytest.raises(SystemExit) as ex:
|
||||
novelwriter.main(["--config=%s" % tmpDir, "--data=%s" % tmpDir])
|
||||
novelwriter.main([f"--config={tmpPath}", f"--data={tmpPath}"])
|
||||
assert ex.value.code == 0
|
||||
|
||||
# END Test testBaseInit_Launch
|
||||
|
||||
|
||||
@pytest.mark.base
|
||||
def testBaseInit_Options(monkeypatch, tmpDir):
|
||||
def testBaseInit_Options(monkeypatch, tmpPath):
|
||||
"""Test command line options for logging level.
|
||||
"""
|
||||
monkeypatch.setattr("novelwriter.guimain.GuiMain", MockGuiMain)
|
||||
monkeypatch.setattr(sys, "argv", [
|
||||
"novelWriter.py", "--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir
|
||||
"novelWriter.py", "--testmode", f"--config={tmpPath}", f"--data={tmpPath}"
|
||||
])
|
||||
|
||||
# Defaults w/None Args
|
||||
@@ -93,20 +93,20 @@ def testBaseInit_Options(monkeypatch, tmpDir):
|
||||
|
||||
# Defaults
|
||||
nwGUI = novelwriter.main(
|
||||
["--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir, "--style=Fusion"]
|
||||
["--testmode", f"--config={tmpPath}", f"--data={tmpPath}", "--style=Fusion"]
|
||||
)
|
||||
assert novelwriter.logger.getEffectiveLevel() == logging.WARNING
|
||||
assert nwGUI.closeMain() == "closeMain"
|
||||
|
||||
# Log Levels
|
||||
nwGUI = novelwriter.main(
|
||||
["--testmode", "--info", "--config=%s" % tmpDir, "--data=%s" % tmpDir]
|
||||
["--testmode", "--info", f"--config={tmpPath}", f"--data={tmpPath}"]
|
||||
)
|
||||
assert novelwriter.logger.getEffectiveLevel() == logging.INFO
|
||||
assert nwGUI.closeMain() == "closeMain"
|
||||
|
||||
nwGUI = novelwriter.main(
|
||||
["--testmode", "--debug", "--config=%s" % tmpDir, "--data=%s" % tmpDir]
|
||||
["--testmode", "--debug", f"--config={tmpPath}", f"--data={tmpPath}"]
|
||||
)
|
||||
assert novelwriter.logger.getEffectiveLevel() == logging.DEBUG
|
||||
assert nwGUI.closeMain() == "closeMain"
|
||||
@@ -114,14 +114,14 @@ def testBaseInit_Options(monkeypatch, tmpDir):
|
||||
# Help and Version
|
||||
with pytest.raises(SystemExit) as ex:
|
||||
nwGUI = novelwriter.main(
|
||||
["--testmode", "--help", "--config=%s" % tmpDir, "--data=%s" % tmpDir]
|
||||
["--testmode", "--help", f"--config={tmpPath}", f"--data={tmpPath}"]
|
||||
)
|
||||
assert nwGUI.closeMain() == "closeMain"
|
||||
assert ex.value.code == 0
|
||||
|
||||
with pytest.raises(SystemExit) as ex:
|
||||
nwGUI = novelwriter.main(
|
||||
["--testmode", "--version", "--config=%s" % tmpDir, "--data=%s" % tmpDir]
|
||||
["--testmode", "--version", f"--config={tmpPath}", f"--data={tmpPath}"]
|
||||
)
|
||||
assert nwGUI.closeMain() == "closeMain"
|
||||
assert ex.value.code == 0
|
||||
@@ -129,14 +129,14 @@ def testBaseInit_Options(monkeypatch, tmpDir):
|
||||
# Invalid options
|
||||
with pytest.raises(SystemExit) as ex:
|
||||
nwGUI = novelwriter.main(
|
||||
["--testmode", "--invalid", "--config=%s" % tmpDir, "--data=%s" % tmpDir]
|
||||
["--testmode", "--invalid", f"--config={tmpPath}", f"--data={tmpPath}"]
|
||||
)
|
||||
assert nwGUI.closeMain() == "closeMain"
|
||||
assert ex.value.code == 2
|
||||
|
||||
# Project Path
|
||||
nwGUI = novelwriter.main(
|
||||
["--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir, "sample/"]
|
||||
["--testmode", f"--config={tmpPath}", f"--data={tmpPath}", "sample/"]
|
||||
)
|
||||
assert novelwriter.CONFIG.cmdOpen == "sample/"
|
||||
assert nwGUI.closeMain() == "closeMain"
|
||||
@@ -145,7 +145,7 @@ def testBaseInit_Options(monkeypatch, tmpDir):
|
||||
|
||||
|
||||
@pytest.mark.base
|
||||
def testBaseInit_Imports(caplog, monkeypatch, tmpDir):
|
||||
def testBaseInit_Imports(caplog, monkeypatch, tmpPath):
|
||||
"""Check import error handling.
|
||||
"""
|
||||
monkeypatch.setattr("novelwriter.guimain.GuiMain", MockGuiMain)
|
||||
@@ -161,7 +161,7 @@ def testBaseInit_Imports(caplog, monkeypatch, tmpDir):
|
||||
|
||||
with pytest.raises(SystemExit) as ex:
|
||||
_ = novelwriter.main(
|
||||
["--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir]
|
||||
["--testmode", f"--config={tmpPath}", f"--data={tmpPath}"]
|
||||
)
|
||||
|
||||
assert ex.value.code & 4 == 4 # Python version not satisfied
|
||||
|
||||
@@ -19,7 +19,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import uuid
|
||||
import pytest
|
||||
|
||||
@@ -35,12 +34,12 @@ from novelwriter.core.coretools import DocMerger, DocSplitter, ProjectBuilder
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreTools_DocMerger(monkeypatch, mockGUI, fncDir, outDir, refDir, mockRnd, ipsumText):
|
||||
def testCoreTools_DocMerger(monkeypatch, mockGUI, fncPath, tstPaths, mockRnd, ipsumText):
|
||||
"""Test the DocMerger utility.
|
||||
"""
|
||||
theProject = NWProject(mockGUI)
|
||||
mockRnd.reset()
|
||||
buildTestProject(theProject, fncDir)
|
||||
buildTestProject(theProject, fncPath)
|
||||
|
||||
# Create Files to Merge
|
||||
# =====================
|
||||
@@ -77,9 +76,9 @@ def testCoreTools_DocMerger(monkeypatch, mockGUI, fncDir, outDir, refDir, mockRn
|
||||
# Merge to New
|
||||
# ============
|
||||
|
||||
saveFile = os.path.join(fncDir, "content", "0000000000014.nwd")
|
||||
testFile = os.path.join(outDir, "coreDocTools_DocMerger_0000000000014.nwd")
|
||||
compFile = os.path.join(refDir, "coreDocTools_DocMerger_0000000000014.nwd")
|
||||
saveFile = fncPath / "content" / "0000000000014.nwd"
|
||||
testFile = tstPaths.outDir / "coreDocTools_DocMerger_0000000000014.nwd"
|
||||
compFile = tstPaths.refDir / "coreDocTools_DocMerger_0000000000014.nwd"
|
||||
|
||||
assert docMerger.newTargetDoc(hChapter1, "All of Chapter 1") == "0000000000014"
|
||||
|
||||
@@ -92,7 +91,7 @@ def testCoreTools_DocMerger(monkeypatch, mockGUI, fncDir, outDir, refDir, mockRn
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr("builtins.open", causeOSError)
|
||||
assert docMerger.writeTargetDoc() is False
|
||||
assert not os.path.isfile(saveFile)
|
||||
assert not saveFile.exists()
|
||||
assert docMerger.getError() != ""
|
||||
|
||||
# Write properly, and compare
|
||||
@@ -103,9 +102,9 @@ def testCoreTools_DocMerger(monkeypatch, mockGUI, fncDir, outDir, refDir, mockRn
|
||||
# Merge into Existing
|
||||
# ===================
|
||||
|
||||
saveFile = os.path.join(fncDir, "content", "0000000000010.nwd")
|
||||
testFile = os.path.join(outDir, "coreDocTools_DocMerger_0000000000010.nwd")
|
||||
compFile = os.path.join(refDir, "coreDocTools_DocMerger_0000000000010.nwd")
|
||||
saveFile = fncPath / "content" / "0000000000010.nwd"
|
||||
testFile = tstPaths.outDir / "coreDocTools_DocMerger_0000000000010.nwd"
|
||||
compFile = tstPaths.refDir / "coreDocTools_DocMerger_0000000000010.nwd"
|
||||
|
||||
docMerger.setTargetDoc(hChapter1)
|
||||
|
||||
@@ -124,12 +123,12 @@ def testCoreTools_DocMerger(monkeypatch, mockGUI, fncDir, outDir, refDir, mockRn
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreTools_DocSplitter(monkeypatch, mockGUI, fncDir, outDir, refDir, mockRnd, ipsumText):
|
||||
def testCoreTools_DocSplitter(monkeypatch, mockGUI, fncPath, mockRnd, ipsumText):
|
||||
"""Test the DocSplitter utility.
|
||||
"""
|
||||
theProject = NWProject(mockGUI)
|
||||
mockRnd.reset()
|
||||
buildTestProject(theProject, fncDir)
|
||||
buildTestProject(theProject, fncPath)
|
||||
|
||||
# Create File to Split
|
||||
# ====================
|
||||
@@ -264,15 +263,15 @@ def testCoreTools_DocSplitter(monkeypatch, mockGUI, fncDir, outDir, refDir, mock
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreTools_NewMinimal(monkeypatch, fncDir, outDir, refDir, mockGUI, mockRnd):
|
||||
def testCoreTools_NewMinimal(monkeypatch, fncPath, tstPaths, mockGUI, mockRnd):
|
||||
"""Create a new project from a project wizard dictionary. With
|
||||
default setting, creating a Minimal project.
|
||||
"""
|
||||
monkeypatch.setattr("uuid.uuid4", lambda *a: uuid.UUID("d0f3fe10-c6e6-4310-8bfd-181eb4224eed"))
|
||||
|
||||
projFile = os.path.join(fncDir, "nwProject.nwx")
|
||||
testFile = os.path.join(outDir, "coreTools_NewMinimal_nwProject.nwx")
|
||||
compFile = os.path.join(refDir, "coreTools_NewMinimal_nwProject.nwx")
|
||||
projFile = fncPath / "nwProject.nwx"
|
||||
testFile = tstPaths.outDir / "coreTools_NewMinimal_nwProject.nwx"
|
||||
compFile = tstPaths.refDir / "coreTools_NewMinimal_nwProject.nwx"
|
||||
|
||||
projBuild = ProjectBuilder(mockGUI)
|
||||
|
||||
@@ -283,10 +282,10 @@ def testCoreTools_NewMinimal(monkeypatch, fncDir, outDir, refDir, mockGUI, mockR
|
||||
assert projBuild.buildProject("stuff") is False
|
||||
|
||||
# Try again with a proper path
|
||||
assert projBuild.buildProject({"projPath": fncDir}) is True
|
||||
assert projBuild.buildProject({"projPath": fncPath}) is True
|
||||
|
||||
# Creating the project once more should fail
|
||||
assert projBuild.buildProject({"projPath": fncDir}) is False
|
||||
assert projBuild.buildProject({"projPath": fncPath}) is False
|
||||
|
||||
# Save and close
|
||||
copyfile(projFile, testFile)
|
||||
@@ -296,21 +295,21 @@ def testCoreTools_NewMinimal(monkeypatch, fncDir, outDir, refDir, mockGUI, mockR
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreTools_NewCustomA(monkeypatch, fncDir, outDir, refDir, mockGUI, mockRnd):
|
||||
def testCoreTools_NewCustomA(monkeypatch, fncPath, tstPaths, mockGUI, mockRnd):
|
||||
"""Create a new project from a project wizard dictionary.
|
||||
Custom type with chapters and scenes.
|
||||
"""
|
||||
monkeypatch.setattr("uuid.uuid4", lambda *a: uuid.UUID("d0f3fe10-c6e6-4310-8bfd-181eb4224eed"))
|
||||
|
||||
projFile = os.path.join(fncDir, "nwProject.nwx")
|
||||
testFile = os.path.join(outDir, "coreTools_NewCustomA_nwProject.nwx")
|
||||
compFile = os.path.join(refDir, "coreTools_NewCustomA_nwProject.nwx")
|
||||
projFile = fncPath / "nwProject.nwx"
|
||||
testFile = tstPaths.outDir / "coreTools_NewCustomA_nwProject.nwx"
|
||||
compFile = tstPaths.refDir / "coreTools_NewCustomA_nwProject.nwx"
|
||||
|
||||
projData = {
|
||||
"projName": "Test Custom",
|
||||
"projTitle": "Test Novel",
|
||||
"projAuthors": "Jane Doe\nJohn Doh\n",
|
||||
"projPath": fncDir,
|
||||
"projPath": fncPath,
|
||||
"popSample": False,
|
||||
"popMinimal": False,
|
||||
"popCustom": True,
|
||||
@@ -334,21 +333,21 @@ def testCoreTools_NewCustomA(monkeypatch, fncDir, outDir, refDir, mockGUI, mockR
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreTools_NewCustomB(monkeypatch, fncDir, outDir, refDir, mockGUI, mockRnd):
|
||||
def testCoreTools_NewCustomB(monkeypatch, fncPath, tstPaths, mockGUI, mockRnd):
|
||||
"""Create a new project from a project wizard dictionary.
|
||||
Custom type without chapters, but with scenes.
|
||||
"""
|
||||
monkeypatch.setattr("uuid.uuid4", lambda *a: uuid.UUID("d0f3fe10-c6e6-4310-8bfd-181eb4224eed"))
|
||||
|
||||
projFile = os.path.join(fncDir, "nwProject.nwx")
|
||||
testFile = os.path.join(outDir, "coreTools_NewCustomB_nwProject.nwx")
|
||||
compFile = os.path.join(refDir, "coreTools_NewCustomB_nwProject.nwx")
|
||||
projFile = fncPath / "nwProject.nwx"
|
||||
testFile = tstPaths.outDir / "coreTools_NewCustomB_nwProject.nwx"
|
||||
compFile = tstPaths.refDir / "coreTools_NewCustomB_nwProject.nwx"
|
||||
|
||||
projData = {
|
||||
"projName": "Test Custom",
|
||||
"projTitle": "Test Novel",
|
||||
"projAuthors": "Jane Doe\nJohn Doh\n",
|
||||
"projPath": fncDir,
|
||||
"projPath": fncPath,
|
||||
"popSample": False,
|
||||
"popMinimal": False,
|
||||
"popCustom": True,
|
||||
@@ -406,16 +405,15 @@ def testCoreTools_NewSample(monkeypatch, fncPath, tmpConf, tmpPath, mockGUI):
|
||||
outFile.write("foo")
|
||||
|
||||
assert projBuild.buildProject(projData) is False
|
||||
os.unlink(dstSample)
|
||||
dstSample.unlink()
|
||||
|
||||
# Create a real zip file, and unpack it
|
||||
with ZipFile(dstSample, "w") as zipObj:
|
||||
zipObj.write(os.path.join(srcSample, "nwProject.nwx"), "nwProject.nwx")
|
||||
for docFile in os.listdir(os.path.join(srcSample, "content")):
|
||||
srcDoc = os.path.join(srcSample, "content", docFile)
|
||||
zipObj.write(srcDoc, "content/"+docFile)
|
||||
zipObj.write(srcSample / "nwProject.nwx", "nwProject.nwx")
|
||||
for docFile in (srcSample / "content").iterdir():
|
||||
zipObj.write(docFile, f"content/{docFile.name}")
|
||||
|
||||
assert projBuild.buildProject(projData) is True
|
||||
os.unlink(dstSample)
|
||||
dstSample.unlink()
|
||||
|
||||
# END Test testCoreTools_NewSample
|
||||
|
||||
@@ -23,7 +23,6 @@ import json
|
||||
import pytest
|
||||
|
||||
from shutil import copyfile
|
||||
from pathlib import Path
|
||||
|
||||
from mock import causeException
|
||||
from tools import C, buildTestProject, cmpFiles, writeFile
|
||||
@@ -35,16 +34,16 @@ from novelwriter.core.project import NWProject
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreIndex_LoadSave(monkeypatch, nwLipsum, mockGUI, tstPaths):
|
||||
def testCoreIndex_LoadSave(monkeypatch, prjLipsum, mockGUI, tstPaths):
|
||||
"""Test core functionality of scaning, saving, loading and checking
|
||||
the index cache file.
|
||||
"""
|
||||
projFile = Path(nwLipsum) / "meta" / nwFiles.INDEX_FILE
|
||||
projFile = prjLipsum / "meta" / nwFiles.INDEX_FILE
|
||||
testFile = tstPaths.outDir / "coreIndex_LoadSave_tagsIndex.json"
|
||||
compFile = tstPaths.refDir / "coreIndex_LoadSave_tagsIndex.json"
|
||||
|
||||
theProject = NWProject(mockGUI)
|
||||
assert theProject.openProject(nwLipsum)
|
||||
assert theProject.openProject(prjLipsum)
|
||||
|
||||
theIndex = NWIndex(theProject)
|
||||
assert repr(theIndex) == "<NWIndex project='Lorem Ipsum'>"
|
||||
@@ -196,12 +195,12 @@ def testCoreIndex_ScanThis(mockGUI):
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreIndex_CheckThese(mockGUI, fncDir, mockRnd):
|
||||
def testCoreIndex_CheckThese(mockGUI, fncPath, mockRnd):
|
||||
"""Test the tag checker function checkThese.
|
||||
"""
|
||||
theProject = NWProject(mockGUI)
|
||||
mockRnd.reset()
|
||||
buildTestProject(theProject, fncDir)
|
||||
buildTestProject(theProject, fncPath)
|
||||
theIndex = theProject.index
|
||||
theIndex.clearIndex()
|
||||
|
||||
@@ -274,12 +273,12 @@ def testCoreIndex_CheckThese(mockGUI, fncDir, mockRnd):
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreIndex_ScanText(mockGUI, fncDir, mockRnd):
|
||||
def testCoreIndex_ScanText(mockGUI, fncPath, mockRnd):
|
||||
"""Check the index text scanner.
|
||||
"""
|
||||
theProject = NWProject(mockGUI)
|
||||
mockRnd.reset()
|
||||
buildTestProject(theProject, fncDir)
|
||||
buildTestProject(theProject, fncPath)
|
||||
theIndex = theProject.index
|
||||
|
||||
# Some items for fail to scan tests
|
||||
@@ -486,12 +485,12 @@ def testCoreIndex_ScanText(mockGUI, fncDir, mockRnd):
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreIndex_ExtractData(mockGUI, fncDir, mockRnd):
|
||||
def testCoreIndex_ExtractData(mockGUI, fncPath, mockRnd):
|
||||
"""Check the index data extraction functions.
|
||||
"""
|
||||
theProject = NWProject(mockGUI)
|
||||
mockRnd.reset()
|
||||
buildTestProject(theProject, fncDir)
|
||||
buildTestProject(theProject, fncPath)
|
||||
|
||||
theIndex = theProject.index
|
||||
theIndex.reIndexHandle(C.hNovelRoot)
|
||||
@@ -940,12 +939,12 @@ def testCoreIndex_TagsIndex():
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreIndex_ItemIndex(mockGUI, fncDir, mockRnd):
|
||||
def testCoreIndex_ItemIndex(mockGUI, fncPath, mockRnd):
|
||||
"""Check the ItemIndex class.
|
||||
"""
|
||||
theProject = NWProject(mockGUI)
|
||||
mockRnd.reset()
|
||||
buildTestProject(theProject, fncDir)
|
||||
buildTestProject(theProject, fncPath)
|
||||
theProject.index.clearIndex()
|
||||
|
||||
nHandle = C.hTitlePage
|
||||
|
||||
@@ -31,12 +31,12 @@ from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreItem_Setters(mockGUI, mockRnd, fncDir):
|
||||
def testCoreItem_Setters(mockGUI, mockRnd, fncPath):
|
||||
"""Test all the simple setters for the NWItem class.
|
||||
"""
|
||||
theProject = NWProject(mockGUI)
|
||||
mockRnd.reset()
|
||||
buildTestProject(theProject, fncDir)
|
||||
buildTestProject(theProject, fncPath)
|
||||
theItem = NWItem(theProject)
|
||||
|
||||
statusKeys = ["s000000", "s000001", "s000002", "s000003"]
|
||||
@@ -192,12 +192,12 @@ def testCoreItem_Setters(mockGUI, mockRnd, fncDir):
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreItem_Methods(mockGUI, mockRnd, fncDir):
|
||||
def testCoreItem_Methods(mockGUI, mockRnd, fncPath):
|
||||
"""Test the simple methods of the NWItem class.
|
||||
"""
|
||||
theProject = NWProject(mockGUI)
|
||||
mockRnd.reset()
|
||||
buildTestProject(theProject, fncDir)
|
||||
buildTestProject(theProject, fncPath)
|
||||
theItem = NWItem(theProject)
|
||||
|
||||
# Describe Me
|
||||
|
||||
@@ -180,6 +180,7 @@ def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncPath, mockRnd):
|
||||
# Fail on lock file
|
||||
assert theProject._storage.writeLockFile()
|
||||
assert theProject.openProject(fncPath) is False
|
||||
assert isinstance(theProject.getLockStatus(), list)
|
||||
|
||||
# Fail to read lockfile (which still opens the project)
|
||||
with monkeypatch.context() as mp:
|
||||
@@ -193,6 +194,7 @@ def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncPath, mockRnd):
|
||||
assert theProject._storage.writeLockFile()
|
||||
assert theProject.openProject(fncPath, overrideLock=True) is True
|
||||
assert theProject.closeProject()
|
||||
assert theProject.getLockStatus() is None
|
||||
|
||||
# Fail getting xml reader
|
||||
with monkeypatch.context() as mp:
|
||||
@@ -625,7 +627,7 @@ def testCoreProject_Methods(monkeypatch, mockGUI, fncPath, mockRnd):
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreProject_OrphanedFiles(mockGUI, nwLipsum):
|
||||
def testCoreProject_OrphanedFiles(mockGUI, prjLipsum):
|
||||
"""Check that files in the content folder that are not tracked in
|
||||
the project XML file are handled correctly by the orphaned files
|
||||
function. It should also restore as much meta data as possible from
|
||||
@@ -633,7 +635,7 @@ def testCoreProject_OrphanedFiles(mockGUI, nwLipsum):
|
||||
"""
|
||||
theProject = NWProject(mockGUI)
|
||||
|
||||
assert theProject.openProject(nwLipsum) is True
|
||||
assert theProject.openProject(prjLipsum) is True
|
||||
assert theProject.tree["636b6aa9b697b"] is None
|
||||
|
||||
# Add a file with non-existent parent
|
||||
@@ -646,7 +648,7 @@ def testCoreProject_OrphanedFiles(mockGUI, nwLipsum):
|
||||
assert theProject.closeProject() is True
|
||||
|
||||
# First Item with Meta Data
|
||||
orphPath = Path(nwLipsum) / "content" / "636b6aa9b697b.nwd"
|
||||
orphPath = prjLipsum / "content" / "636b6aa9b697b.nwd"
|
||||
writeFile(orphPath, (
|
||||
"%%~name:[Recovered] Mars\n"
|
||||
"%%~path:5eaea4e8cdee8/636b6aa9b697b\n"
|
||||
@@ -656,22 +658,22 @@ def testCoreProject_OrphanedFiles(mockGUI, nwLipsum):
|
||||
))
|
||||
|
||||
# Second Item without Meta Data
|
||||
orphPath = Path(nwLipsum) / "content" / "736b6aa9b697b.nwd"
|
||||
orphPath = prjLipsum / "content" / "736b6aa9b697b.nwd"
|
||||
writeFile(orphPath, "\n")
|
||||
|
||||
# Invalid File Name
|
||||
tstPath = Path(nwLipsum) / "content" / "636b6aa9b697b.txt"
|
||||
tstPath = prjLipsum / "content" / "636b6aa9b697b.txt"
|
||||
writeFile(tstPath, "\n")
|
||||
|
||||
# Invalid File Name
|
||||
tstPath = Path(nwLipsum) / "content" / "636b6aa9b697bb.nwd"
|
||||
tstPath = prjLipsum / "content" / "636b6aa9b697bb.nwd"
|
||||
writeFile(tstPath, "\n")
|
||||
|
||||
# Invalid File Name
|
||||
tstPath = Path(nwLipsum) / "content" / "abcdefghijklm.nwd"
|
||||
tstPath = prjLipsum / "content" / "abcdefghijklm.nwd"
|
||||
writeFile(tstPath, "\n")
|
||||
|
||||
assert theProject.openProject(nwLipsum)
|
||||
assert theProject.openProject(prjLipsum)
|
||||
assert theProject.storage.storagePath is not None
|
||||
assert theProject.storage.runtimePath is not None
|
||||
assert theProject.tree["636b6aa9b697bb"] is None
|
||||
@@ -697,7 +699,7 @@ def testCoreProject_OrphanedFiles(mockGUI, nwLipsum):
|
||||
assert oItem.itemType == nwItemType.FILE
|
||||
assert oItem.itemLayout == nwItemLayout.NOTE
|
||||
|
||||
assert theProject.saveProject(nwLipsum)
|
||||
assert theProject.saveProject(prjLipsum)
|
||||
assert theProject.closeProject()
|
||||
|
||||
# Finally, check that the orphaned files function returns
|
||||
@@ -730,17 +732,17 @@ def testCoreProject_Backup(monkeypatch, mockGUI, fncPath, tmpPath):
|
||||
mockGUI.hasProject = True
|
||||
|
||||
# Invalid path
|
||||
theProject.mainConf.backupPath = None
|
||||
theProject.mainConf._backupPath = None
|
||||
assert theProject.backupProject(doNotify=False) is False
|
||||
|
||||
# Missing project name
|
||||
theProject.mainConf.backupPath = str(tmpPath)
|
||||
theProject.mainConf._backupPath = tmpPath
|
||||
theProject.data.setName("")
|
||||
assert theProject.backupProject(doNotify=False) is False
|
||||
|
||||
# Valid Settings
|
||||
# ==============
|
||||
theProject.mainConf.backupPath = str(tmpPath)
|
||||
theProject.mainConf._backupPath = tmpPath
|
||||
theProject.data.setName("Test Minimal")
|
||||
|
||||
# Can't make folder
|
||||
|
||||
@@ -19,7 +19,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from tools import readFile
|
||||
@@ -441,7 +440,7 @@ def testCoreToHtml_SpecialCases(mockGUI):
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToHtml_Complex(mockGUI, fncDir):
|
||||
def testCoreToHtml_Complex(mockGUI, fncPath):
|
||||
"""Test the save method of the ToHtml class.
|
||||
"""
|
||||
theProject = NWProject(mockGUI)
|
||||
@@ -529,7 +528,7 @@ def testCoreToHtml_Complex(mockGUI, fncDir):
|
||||
bodyText="".join(resText).rstrip()
|
||||
)
|
||||
|
||||
saveFile = os.path.join(fncDir, "outFile.htm")
|
||||
saveFile = fncPath / "outFile.htm"
|
||||
theHtml.saveHTML5(saveFile)
|
||||
assert readFile(saveFile) == htmlDoc
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from tools import C, buildTestProject, readFile
|
||||
@@ -132,12 +131,12 @@ def testCoreToken_Setters(mockGUI):
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToken_TextOps(monkeypatch, mockGUI, mockRnd, fncDir):
|
||||
def testCoreToken_TextOps(monkeypatch, mockGUI, mockRnd, fncPath):
|
||||
"""Test handling files and text in the Tokenizer class.
|
||||
"""
|
||||
theProject = NWProject(mockGUI)
|
||||
mockRnd.reset()
|
||||
buildTestProject(theProject, fncDir)
|
||||
buildTestProject(theProject, fncPath)
|
||||
|
||||
theProject.data.setLanguage("en")
|
||||
theProject._loadProjectLocalisation()
|
||||
@@ -210,7 +209,7 @@ def testCoreToken_TextOps(monkeypatch, mockGUI, mockRnd, fncDir):
|
||||
assert theToken.theResult == "This is text with escapes: ** ~~ __"
|
||||
|
||||
# Save File
|
||||
savePath = os.path.join(fncDir, "dump.nwd")
|
||||
savePath = fncPath / "dump.nwd"
|
||||
theToken.saveRawMarkdown(savePath)
|
||||
assert readFile(savePath) == (
|
||||
"# Notes: Plot\n\n"
|
||||
|
||||
@@ -19,7 +19,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from tools import readFile
|
||||
@@ -208,7 +207,7 @@ def testCoreToMarkdown_ConvertDirect(mockGUI):
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToMarkdown_Complex(mockGUI, fncDir):
|
||||
def testCoreToMarkdown_Complex(mockGUI, fncPath):
|
||||
"""Test the save method of the ToMarkdown class.
|
||||
"""
|
||||
theProject = NWProject(mockGUI)
|
||||
@@ -253,7 +252,7 @@ def testCoreToMarkdown_Complex(mockGUI, fncDir):
|
||||
# Check File
|
||||
# ==========
|
||||
|
||||
saveFile = os.path.join(fncDir, "outFile.md")
|
||||
saveFile = fncPath / "outFile.md"
|
||||
theMD.saveMarkdown(saveFile)
|
||||
assert readFile(saveFile) == "".join(resText)
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pytest
|
||||
import zipfile
|
||||
|
||||
@@ -612,7 +611,7 @@ def testCoreToOdt_ConvertDirect(mockGUI):
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToOdt_SaveFlat(mockGUI, fncDir, outDir, refDir):
|
||||
def testCoreToOdt_SaveFlat(mockGUI, fncPath, tstPaths):
|
||||
"""Test the document save functions.
|
||||
"""
|
||||
theProject = NWProject(mockGUI)
|
||||
@@ -634,12 +633,12 @@ def testCoreToOdt_SaveFlat(mockGUI, fncDir, outDir, refDir):
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
|
||||
flatFile = os.path.join(fncDir, "document.fodt")
|
||||
testFile = os.path.join(outDir, "coreToOdt_SaveFlat_document.fodt")
|
||||
compFile = os.path.join(refDir, "coreToOdt_SaveFlat_document.fodt")
|
||||
flatFile = fncPath / "document.fodt"
|
||||
testFile = tstPaths.outDir / "coreToOdt_SaveFlat_document.fodt"
|
||||
compFile = tstPaths.refDir / "coreToOdt_SaveFlat_document.fodt"
|
||||
|
||||
theDoc.saveFlatXML(flatFile)
|
||||
assert os.path.isfile(flatFile)
|
||||
assert flatFile.exists()
|
||||
|
||||
copyfile(flatFile, testFile)
|
||||
assert cmpFiles(testFile, compFile, [4, 5])
|
||||
@@ -648,7 +647,7 @@ def testCoreToOdt_SaveFlat(mockGUI, fncDir, outDir, refDir):
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToOdt_SaveFull(mockGUI, fncDir, outDir, refDir):
|
||||
def testCoreToOdt_SaveFull(mockGUI, fncPath, tstPaths):
|
||||
"""Test the document save functions.
|
||||
"""
|
||||
theProject = NWProject(mockGUI)
|
||||
@@ -667,25 +666,25 @@ def testCoreToOdt_SaveFull(mockGUI, fncDir, outDir, refDir):
|
||||
theDoc.doConvert()
|
||||
theDoc.closeDocument()
|
||||
|
||||
fullFile = os.path.join(fncDir, "document.odt")
|
||||
fullFile = fncPath / "document.odt"
|
||||
|
||||
theDoc.saveOpenDocText(fullFile)
|
||||
assert os.path.isfile(fullFile)
|
||||
assert fullFile.exists()
|
||||
assert zipfile.is_zipfile(fullFile)
|
||||
|
||||
maniFile = os.path.join(outDir, "coreToOdt_SaveFull_manifest.xml")
|
||||
settFile = os.path.join(outDir, "coreToOdt_SaveFull_settings.xml")
|
||||
contFile = os.path.join(outDir, "coreToOdt_SaveFull_content.xml")
|
||||
metaFile = os.path.join(outDir, "coreToOdt_SaveFull_meta.xml")
|
||||
stylFile = os.path.join(outDir, "coreToOdt_SaveFull_styles.xml")
|
||||
maniFile = tstPaths.outDir / "coreToOdt_SaveFull_manifest.xml"
|
||||
settFile = tstPaths.outDir / "coreToOdt_SaveFull_settings.xml"
|
||||
contFile = tstPaths.outDir / "coreToOdt_SaveFull_content.xml"
|
||||
metaFile = tstPaths.outDir / "coreToOdt_SaveFull_meta.xml"
|
||||
stylFile = tstPaths.outDir / "coreToOdt_SaveFull_styles.xml"
|
||||
|
||||
maniComp = os.path.join(refDir, "coreToOdt_SaveFull_manifest.xml")
|
||||
settComp = os.path.join(refDir, "coreToOdt_SaveFull_settings.xml")
|
||||
contComp = os.path.join(refDir, "coreToOdt_SaveFull_content.xml")
|
||||
metaComp = os.path.join(refDir, "coreToOdt_SaveFull_meta.xml")
|
||||
stylComp = os.path.join(refDir, "coreToOdt_SaveFull_styles.xml")
|
||||
maniComp = tstPaths.refDir / "coreToOdt_SaveFull_manifest.xml"
|
||||
settComp = tstPaths.refDir / "coreToOdt_SaveFull_settings.xml"
|
||||
contComp = tstPaths.refDir / "coreToOdt_SaveFull_content.xml"
|
||||
metaComp = tstPaths.refDir / "coreToOdt_SaveFull_meta.xml"
|
||||
stylComp = tstPaths.refDir / "coreToOdt_SaveFull_styles.xml"
|
||||
|
||||
extaxtTo = os.path.join(outDir, "coreToOdt_SaveFull")
|
||||
extaxtTo = tstPaths.outDir / "coreToOdt_SaveFull"
|
||||
|
||||
with zipfile.ZipFile(fullFile, mode="r") as theZip:
|
||||
theZip.extract("META-INF/manifest.xml", extaxtTo)
|
||||
@@ -694,17 +693,17 @@ def testCoreToOdt_SaveFull(mockGUI, fncDir, outDir, refDir):
|
||||
theZip.extract("meta.xml", extaxtTo)
|
||||
theZip.extract("styles.xml", extaxtTo)
|
||||
|
||||
maniOut = os.path.join(outDir, "coreToOdt_SaveFull", "META-INF", "manifest.xml")
|
||||
settOut = os.path.join(outDir, "coreToOdt_SaveFull", "settings.xml")
|
||||
contOut = os.path.join(outDir, "coreToOdt_SaveFull", "content.xml")
|
||||
metaOut = os.path.join(outDir, "coreToOdt_SaveFull", "meta.xml")
|
||||
stylOut = os.path.join(outDir, "coreToOdt_SaveFull", "styles.xml")
|
||||
maniOut = tstPaths.outDir / "coreToOdt_SaveFull" / "META-INF" / "manifest.xml"
|
||||
settOut = tstPaths.outDir / "coreToOdt_SaveFull" / "settings.xml"
|
||||
contOut = tstPaths.outDir / "coreToOdt_SaveFull" / "content.xml"
|
||||
metaOut = tstPaths.outDir / "coreToOdt_SaveFull" / "meta.xml"
|
||||
stylOut = tstPaths.outDir / "coreToOdt_SaveFull" / "styles.xml"
|
||||
|
||||
def prettifyXml(inFile, outFile):
|
||||
with open(outFile, mode="wb") as fileStream:
|
||||
fileStream.write(
|
||||
etree.tostring(
|
||||
etree.parse(inFile),
|
||||
etree.parse(str(inFile)),
|
||||
pretty_print=True,
|
||||
encoding="utf-8",
|
||||
xml_declaration=True
|
||||
|
||||
@@ -29,11 +29,11 @@ from novelwriter.dialogs.docmerge import GuiDocMerge
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testDlgMerge_Main(qtbot, nwGUI, fncProj, mockRnd):
|
||||
def testDlgMerge_Main(qtbot, nwGUI, projPath, mockRnd):
|
||||
"""Test the merge documents tool.
|
||||
"""
|
||||
# Create a new project
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
# Check that the dialog kan handle invalid items
|
||||
nwMerge = GuiDocMerge(nwGUI, C.hInvalid, [C.hInvalid])
|
||||
|
||||
@@ -28,13 +28,13 @@ from novelwriter.dialogs.editlabel import GuiEditLabel
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
|
||||
def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
"""Test the split document tool.
|
||||
"""
|
||||
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
||||
|
||||
# Create a new project
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
theProject = nwGUI.theProject
|
||||
projTree = nwGUI.projView.projTree
|
||||
|
||||
@@ -20,7 +20,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import os
|
||||
|
||||
from tools import buildTestProject, getGuiItem
|
||||
|
||||
@@ -33,10 +32,10 @@ from novelwriter.dialogs.projload import GuiProjectLoad
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testDlgLoadProject_Main(qtbot, monkeypatch, nwGUI, fncProj):
|
||||
def testDlgLoadProject_Main(qtbot, monkeypatch, nwGUI, projPath):
|
||||
"""Test the load project wizard.
|
||||
"""
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
assert nwGUI.closeProject()
|
||||
|
||||
monkeypatch.setattr(GuiProjectLoad, "exec_", lambda *a: None)
|
||||
@@ -87,10 +86,10 @@ def testDlgLoadProject_Main(qtbot, monkeypatch, nwGUI, fncProj):
|
||||
nwLoad._doDeleteRecent()
|
||||
assert nwLoad.listBox.topLevelItemCount() == recentCount - 1
|
||||
|
||||
getFile = os.path.join(fncProj, "nwProject.nwx")
|
||||
getFile = str(projPath / "nwProject.nwx")
|
||||
monkeypatch.setattr(QFileDialog, "getOpenFileName", lambda *a, **k: (getFile, None))
|
||||
qtbot.mouseClick(nwLoad.browseButton, Qt.LeftButton)
|
||||
assert nwLoad.openPath == fncProj
|
||||
assert nwLoad.openPath == projPath / "nwProject.nwx"
|
||||
assert nwLoad.openState == nwLoad.OPEN_STATE
|
||||
|
||||
nwLoad.close()
|
||||
|
||||
@@ -82,16 +82,16 @@ def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI):
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testDlgProjSettings_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj, mockRnd):
|
||||
def testDlgProjSettings_Main(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd):
|
||||
"""Test the main tab of the project settings dialog.
|
||||
"""
|
||||
# Mock components
|
||||
monkeypatch.setattr(nwGUI.docEditor.spEnchant, "listDictionaries", lambda: [("en", "none")])
|
||||
|
||||
# Create new project
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
mockRnd.reset()
|
||||
nwGUI.mainConf.backupPath = fncDir
|
||||
nwGUI.mainConf.backupPath = fncPath
|
||||
|
||||
# Set some values
|
||||
theProject = nwGUI.theProject
|
||||
@@ -148,7 +148,7 @@ def testDlgProjSettings_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj, mockRnd
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncDir, fncProj, mockRnd):
|
||||
def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd):
|
||||
"""Test the status and importance tabs of the project settings
|
||||
dialog.
|
||||
"""
|
||||
@@ -159,8 +159,8 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncDir, fncProj,
|
||||
|
||||
# Create new project
|
||||
mockRnd.reset()
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
nwGUI.mainConf.backupPath = fncDir
|
||||
buildTestProject(nwGUI, projPath)
|
||||
nwGUI.mainConf.backupPath = fncPath
|
||||
|
||||
# Set some values
|
||||
theProject = nwGUI.theProject
|
||||
@@ -350,7 +350,7 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncDir, fncProj,
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testDlgProjSettings_Replace(qtbot, monkeypatch, nwGUI, fncDir, fncProj, mockRnd):
|
||||
def testDlgProjSettings_Replace(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd):
|
||||
"""Test the auto-replace tab of the project settings dialog.
|
||||
"""
|
||||
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
||||
@@ -360,8 +360,8 @@ def testDlgProjSettings_Replace(qtbot, monkeypatch, nwGUI, fncDir, fncProj, mock
|
||||
|
||||
# Create new project
|
||||
mockRnd.reset()
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
nwGUI.mainConf.backupPath = fncDir
|
||||
buildTestProject(nwGUI, projPath)
|
||||
nwGUI.mainConf.backupPath = fncPath
|
||||
|
||||
# Set some values
|
||||
theProject = nwGUI.theProject
|
||||
|
||||
@@ -19,7 +19,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
@@ -33,18 +32,18 @@ from novelwriter.dialogs.wordlist import GuiWordList
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testDlgWordList_Dialog(qtbot, monkeypatch, nwGUI, fncProj):
|
||||
def testDlgWordList_Dialog(qtbot, monkeypatch, nwGUI, projPath):
|
||||
"""test the word list editor.
|
||||
"""
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
monkeypatch.setattr(GuiWordList, "exec_", lambda *a: None)
|
||||
monkeypatch.setattr(GuiWordList, "result", lambda *a: QDialog.Accepted)
|
||||
monkeypatch.setattr(GuiWordList, "accept", lambda *a: None)
|
||||
|
||||
# Open project
|
||||
nwGUI.openProject(fncProj)
|
||||
dictFile = os.path.join(fncProj, "meta", nwFiles.PROJ_DICT)
|
||||
nwGUI.openProject(projPath)
|
||||
dictFile = projPath / "meta" / nwFiles.PROJ_DICT
|
||||
|
||||
# Load the dialog
|
||||
nwGUI.mainMenu.aEditWordList.activate(QAction.Trigger)
|
||||
|
||||
@@ -37,11 +37,11 @@ KEY_DELAY = 1
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiEditor_Init(qtbot, nwGUI, fncProj, ipsumText, mockRnd):
|
||||
def testGuiEditor_Init(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
"""Test initialising the editor.
|
||||
"""
|
||||
# Open project
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
assert nwGUI.openDocument(C.hSceneDoc)
|
||||
|
||||
nwGUI.docEditor.setText("### Lorem Ipsum\n\n%s" % ipsumText[0])
|
||||
@@ -80,10 +80,10 @@ def testGuiEditor_Init(qtbot, nwGUI, fncProj, ipsumText, mockRnd):
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiEditor_LoadText(qtbot, monkeypatch, caplog, nwGUI, fncProj, ipsumText, mockRnd):
|
||||
def testGuiEditor_LoadText(qtbot, monkeypatch, caplog, nwGUI, projPath, ipsumText, mockRnd):
|
||||
"""Test loading text into the editor.
|
||||
"""
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
|
||||
longText = "### Lorem Ipsum\n\n%s" % "\n\n".join(ipsumText*20)
|
||||
@@ -135,10 +135,10 @@ def testGuiEditor_LoadText(qtbot, monkeypatch, caplog, nwGUI, fncProj, ipsumText
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiEditor_SaveText(qtbot, monkeypatch, caplog, nwGUI, fncProj, ipsumText, mockRnd):
|
||||
def testGuiEditor_SaveText(qtbot, monkeypatch, caplog, nwGUI, projPath, ipsumText, mockRnd):
|
||||
"""Test saving text from the editor.
|
||||
"""
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
|
||||
# Save Text
|
||||
@@ -179,10 +179,10 @@ def testGuiEditor_SaveText(qtbot, monkeypatch, caplog, nwGUI, fncProj, ipsumText
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiEditor_MetaData(qtbot, nwGUI, fncProj, mockRnd):
|
||||
def testGuiEditor_MetaData(qtbot, nwGUI, projPath, mockRnd):
|
||||
"""Test extracting various meta data and other values.
|
||||
"""
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
|
||||
# Get Text
|
||||
@@ -226,13 +226,13 @@ def testGuiEditor_MetaData(qtbot, nwGUI, fncProj, mockRnd):
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiEditor_Actions(qtbot, nwGUI, fncProj, ipsumText, mockRnd):
|
||||
def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
"""Test the document actions. This is not an extensive test of the
|
||||
action features, just that the actions are actually called. The
|
||||
various action features are tested when their respective functions
|
||||
are tested.
|
||||
"""
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
|
||||
theText = "### A Scene\n\n%s" % "\n\n".join(ipsumText)
|
||||
@@ -459,10 +459,10 @@ def testGuiEditor_Actions(qtbot, nwGUI, fncProj, ipsumText, mockRnd):
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiEditor_Insert(qtbot, monkeypatch, nwGUI, fncProj, ipsumText, mockRnd):
|
||||
def testGuiEditor_Insert(qtbot, monkeypatch, nwGUI, projPath, ipsumText, mockRnd):
|
||||
"""Test the document insert functions.
|
||||
"""
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
|
||||
theText = "### A Scene\n\n%s" % "\n\n".join(ipsumText)
|
||||
@@ -542,10 +542,10 @@ def testGuiEditor_Insert(qtbot, monkeypatch, nwGUI, fncProj, ipsumText, mockRnd)
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiEditor_TextManipulation(qtbot, monkeypatch, nwGUI, fncProj, ipsumText, mockRnd):
|
||||
def testGuiEditor_TextManipulation(qtbot, monkeypatch, nwGUI, projPath, ipsumText, mockRnd):
|
||||
"""Test the text manipulation functions.
|
||||
"""
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
|
||||
theText = "### A Scene\n\n%s" % "\n\n".join(ipsumText)
|
||||
@@ -749,10 +749,10 @@ def testGuiEditor_TextManipulation(qtbot, monkeypatch, nwGUI, fncProj, ipsumText
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiEditor_BlockFormatting(qtbot, monkeypatch, nwGUI, fncProj, ipsumText, mockRnd):
|
||||
def testGuiEditor_BlockFormatting(qtbot, monkeypatch, nwGUI, projPath, ipsumText, mockRnd):
|
||||
"""Test the block formatting function.
|
||||
"""
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
|
||||
theText = "### A Scene\n\n%s" % "\n\n".join(ipsumText)
|
||||
@@ -1062,10 +1062,10 @@ def testGuiEditor_BlockFormatting(qtbot, monkeypatch, nwGUI, fncProj, ipsumText,
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiEditor_Tags(qtbot, nwGUI, fncProj, ipsumText, mockRnd):
|
||||
def testGuiEditor_Tags(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
"""Test the document editor tags functionality.
|
||||
"""
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
|
||||
# Create Scene
|
||||
@@ -1121,7 +1121,7 @@ def testGuiEditor_Tags(qtbot, nwGUI, fncProj, ipsumText, mockRnd):
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiEditor_WordCounters(qtbot, monkeypatch, nwGUI, fncProj, ipsumText, mockRnd):
|
||||
def testGuiEditor_WordCounters(qtbot, monkeypatch, nwGUI, projPath, ipsumText, mockRnd):
|
||||
"""Test saving text from the editor.
|
||||
"""
|
||||
class MockThreadPool:
|
||||
@@ -1139,7 +1139,7 @@ def testGuiEditor_WordCounters(qtbot, monkeypatch, nwGUI, fncProj, ipsumText, mo
|
||||
nwGUI.docEditor.wcTimerDoc.blockSignals(True)
|
||||
nwGUI.docEditor.wcTimerSel.blockSignals(True)
|
||||
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
# Run on an empty document
|
||||
nwGUI.docEditor._runDocCounter()
|
||||
|
||||
@@ -19,7 +19,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from tools import C, cmpFiles, buildTestProject, XML_IGNORE, writeFile
|
||||
@@ -67,7 +66,7 @@ def testGuiMain_ProjectBlocker(nwGUI):
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiMain_NewProject(monkeypatch, nwGUI, fncProj):
|
||||
def testGuiMain_NewProject(monkeypatch, nwGUI, projPath):
|
||||
"""Test creating a new project.
|
||||
"""
|
||||
# No data
|
||||
@@ -79,34 +78,34 @@ def testGuiMain_NewProject(monkeypatch, nwGUI, fncProj):
|
||||
with monkeypatch.context() as mp:
|
||||
nwGUI.hasProject = True
|
||||
mp.setattr(QMessageBox, "question", lambda *a: QMessageBox.No)
|
||||
assert nwGUI.newProject(projData={"projPath": fncProj}) is False
|
||||
assert nwGUI.newProject(projData={"projPath": projPath}) is False
|
||||
|
||||
# No project path
|
||||
assert nwGUI.newProject(projData={}) is False
|
||||
|
||||
# Project file already exists
|
||||
projFile = os.path.join(fncProj, nwFiles.PROJ_FILE)
|
||||
projFile = projPath / nwFiles.PROJ_FILE
|
||||
writeFile(projFile, "Stuff")
|
||||
assert nwGUI.newProject(projData={"projPath": fncProj}) is False
|
||||
os.unlink(projFile)
|
||||
assert nwGUI.newProject(projData={"projPath": projPath}) is False
|
||||
projFile.unlink()
|
||||
|
||||
# An unreachable path should also fail
|
||||
projPath = os.path.join(fncProj, "stuff", "stuff", "stuff")
|
||||
assert nwGUI.newProject(projData={"projPath": projPath}) is False
|
||||
stuffPath = projPath / "stuff" / "stuff" / "stuff"
|
||||
assert nwGUI.newProject(projData={"projPath": stuffPath}) is False
|
||||
|
||||
# This one should work just fine
|
||||
assert nwGUI.newProject(projData={"projPath": fncProj}) is True
|
||||
assert os.path.isfile(os.path.join(fncProj, nwFiles.PROJ_FILE))
|
||||
assert os.path.isdir(os.path.join(fncProj, "content"))
|
||||
assert nwGUI.newProject(projData={"projPath": projPath}) is True
|
||||
assert (projPath / nwFiles.PROJ_FILE).is_file()
|
||||
assert (projPath / "content").is_dir()
|
||||
|
||||
# END Test testGuiMain_NewProject
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
|
||||
def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
"""Test handling of project tree items based on GUI focus states.
|
||||
"""
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
sHandle = "000000000000f"
|
||||
assert nwGUI.openSelectedItem() is False
|
||||
@@ -153,7 +152,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mockRnd):
|
||||
def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd):
|
||||
"""Test the document editor.
|
||||
"""
|
||||
monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
|
||||
@@ -162,7 +161,7 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
|
||||
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
||||
|
||||
# Create new, save, close project
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
assert nwGUI.saveProject()
|
||||
assert nwGUI.closeProject()
|
||||
|
||||
@@ -176,14 +175,14 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
|
||||
assert nwGUI.theProject.data.spellCheck is False
|
||||
|
||||
# Check the files
|
||||
projFile = os.path.join(fncProj, "nwProject.nwx")
|
||||
testFile = os.path.join(outDir, "guiEditor_Main_Initial_nwProject.nwx")
|
||||
compFile = os.path.join(refDir, "guiEditor_Main_Initial_nwProject.nwx")
|
||||
projFile = projPath / "nwProject.nwx"
|
||||
testFile = tstPaths.outDir / "guiEditor_Main_Initial_nwProject.nwx"
|
||||
compFile = tstPaths.refDir / "guiEditor_Main_Initial_nwProject.nwx"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE)
|
||||
|
||||
# Re-open project
|
||||
assert nwGUI.openProject(fncProj)
|
||||
assert nwGUI.openProject(projPath)
|
||||
|
||||
# Check that we loaded the data
|
||||
assert len(nwGUI.theProject.tree) == 8
|
||||
@@ -494,33 +493,33 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
|
||||
assert nwGUI.saveProject()
|
||||
|
||||
# Check the files
|
||||
projFile = os.path.join(fncProj, "nwProject.nwx")
|
||||
testFile = os.path.join(outDir, "guiEditor_Main_Final_nwProject.nwx")
|
||||
compFile = os.path.join(refDir, "guiEditor_Main_Final_nwProject.nwx")
|
||||
projFile = projPath / "nwProject.nwx"
|
||||
testFile = tstPaths.outDir / "guiEditor_Main_Final_nwProject.nwx"
|
||||
compFile = tstPaths.refDir / "guiEditor_Main_Final_nwProject.nwx"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile, ignoreStart=(*XML_IGNORE, "<spellCheck"))
|
||||
|
||||
projFile = os.path.join(fncProj, "content", "000000000000f.nwd")
|
||||
testFile = os.path.join(outDir, "guiEditor_Main_Final_000000000000f.nwd")
|
||||
compFile = os.path.join(refDir, "guiEditor_Main_Final_000000000000f.nwd")
|
||||
projFile = projPath / "content" / "000000000000f.nwd"
|
||||
testFile = tstPaths.outDir / "guiEditor_Main_Final_000000000000f.nwd"
|
||||
compFile = tstPaths.refDir / "guiEditor_Main_Final_000000000000f.nwd"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
|
||||
projFile = os.path.join(fncProj, "content", "0000000000010.nwd")
|
||||
testFile = os.path.join(outDir, "guiEditor_Main_Final_0000000000010.nwd")
|
||||
compFile = os.path.join(refDir, "guiEditor_Main_Final_0000000000010.nwd")
|
||||
projFile = projPath / "content" / "0000000000010.nwd"
|
||||
testFile = tstPaths.outDir / "guiEditor_Main_Final_0000000000010.nwd"
|
||||
compFile = tstPaths.refDir / "guiEditor_Main_Final_0000000000010.nwd"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
|
||||
projFile = os.path.join(fncProj, "content", "0000000000011.nwd")
|
||||
testFile = os.path.join(outDir, "guiEditor_Main_Final_0000000000011.nwd")
|
||||
compFile = os.path.join(refDir, "guiEditor_Main_Final_0000000000011.nwd")
|
||||
projFile = projPath / "content" / "0000000000011.nwd"
|
||||
testFile = tstPaths.outDir / "guiEditor_Main_Final_0000000000011.nwd"
|
||||
compFile = tstPaths.refDir / "guiEditor_Main_Final_0000000000011.nwd"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
|
||||
projFile = os.path.join(fncProj, "content", "0000000000012.nwd")
|
||||
testFile = os.path.join(outDir, "guiEditor_Main_Final_0000000000012.nwd")
|
||||
compFile = os.path.join(refDir, "guiEditor_Main_Final_0000000000012.nwd")
|
||||
projFile = projPath / "content" / "0000000000012.nwd"
|
||||
testFile = tstPaths.outDir / "guiEditor_Main_Final_0000000000012.nwd"
|
||||
compFile = tstPaths.refDir / "guiEditor_Main_Final_0000000000012.nwd"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
|
||||
@@ -530,10 +529,10 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiMain_FocusFullMode(qtbot, nwGUI, fncProj, mockRnd):
|
||||
def testGuiMain_FocusFullMode(qtbot, nwGUI, projPath, mockRnd):
|
||||
"""Test toggling focus mode in main window.
|
||||
"""
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
assert nwGUI.isFocusMode is False
|
||||
|
||||
# Focus Mode
|
||||
|
||||
@@ -20,10 +20,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import os
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QTextCursor, QTextBlock
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import QAction, QFileDialog, QMessageBox
|
||||
|
||||
from tools import C, writeFile, buildTestProject
|
||||
@@ -422,10 +421,10 @@ def testGuiMenu_ContextMenus(qtbot, nwGUI, nwLipsum):
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiMenu_Insert(qtbot, monkeypatch, nwGUI, fncDir, fncProj, mockRnd):
|
||||
def testGuiMenu_Insert(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd):
|
||||
"""Test the Insert menu.
|
||||
"""
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
assert nwGUI.projView.projTree._getTreeItem(C.hSceneDoc) is not None
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
@@ -626,8 +625,8 @@ def testGuiMenu_Insert(qtbot, monkeypatch, nwGUI, fncDir, fncProj, mockRnd):
|
||||
assert not nwGUI.importDocument()
|
||||
|
||||
# Then a valid path, but bot a file that exists
|
||||
theFile = os.path.join(fncDir, "import.txt")
|
||||
monkeypatch.setattr(QFileDialog, "getOpenFileName", lambda *a, **k: (theFile, ""))
|
||||
theFile = fncPath / "import.txt"
|
||||
monkeypatch.setattr(QFileDialog, "getOpenFileName", lambda *a, **k: (str(theFile), ""))
|
||||
assert not nwGUI.importDocument()
|
||||
|
||||
# Create the file and try again, but with no target document open
|
||||
@@ -666,7 +665,7 @@ def testGuiMenu_Insert(qtbot, monkeypatch, nwGUI, fncDir, fncProj, mockRnd):
|
||||
theBits = theMessage.split("<br>")
|
||||
assert len(theBits) == 2
|
||||
assert theBits[0] == "The currently open file is saved in:"
|
||||
assert theBits[1] == os.path.join(fncProj, "content", "000000000000f.nwd")
|
||||
assert theBits[1] == str(projPath / "content" / "000000000000f.nwd")
|
||||
|
||||
# qtbot.stop()
|
||||
|
||||
|
||||
@@ -35,12 +35,12 @@ from novelwriter.dialogs.editlabel import GuiEditLabel
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
|
||||
def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
"""Test navigating the novel tree.
|
||||
"""
|
||||
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
||||
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
nwGUI.switchFocus(nwWidget.TREE)
|
||||
nwGUI.projView.projTree.clearSelection()
|
||||
|
||||
@@ -32,12 +32,11 @@ from novelwriter.enum import nwItemClass, nwOutline, nwView
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, fncDir):
|
||||
def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, projPath):
|
||||
"""Test the outline view.
|
||||
"""
|
||||
# Create a project
|
||||
prjDir = os.path.join(fncDir, "project")
|
||||
buildTestProject(nwGUI, prjDir)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
nwGUI.rebuildIndex()
|
||||
nwGUI._changeView(nwView.OUTLINE)
|
||||
|
||||
@@ -19,7 +19,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from mock import causeOSError
|
||||
@@ -36,7 +35,7 @@ from novelwriter.dialogs.editlabel import GuiEditLabel
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd):
|
||||
def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
"""Test adding and removing items from the project tree.
|
||||
"""
|
||||
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
||||
@@ -49,8 +48,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
|
||||
assert projView.projTree.newTreeItem(nwItemType.FILE) is False
|
||||
|
||||
# Create a project
|
||||
prjDir = os.path.join(fncDir, "project")
|
||||
buildTestProject(nwGUI, prjDir)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
# No itemType set
|
||||
projView.projTree.clearSelection()
|
||||
@@ -168,7 +166,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
|
||||
def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
"""Test adding and removing items from the project tree.
|
||||
"""
|
||||
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
||||
@@ -180,8 +178,7 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
|
||||
assert projView.projTree.moveTreeItem(1) is False
|
||||
|
||||
# Create a project
|
||||
prjDir = os.path.join(fncDir, "project")
|
||||
buildTestProject(nwGUI, prjDir)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
# Move Documents
|
||||
# ==============
|
||||
@@ -279,7 +276,7 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiProjTree_RequestDeleteItem(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd):
|
||||
def testGuiProjTree_RequestDeleteItem(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
"""Test external requests for removing items from project tree.
|
||||
"""
|
||||
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
||||
@@ -291,8 +288,7 @@ def testGuiProjTree_RequestDeleteItem(qtbot, caplog, monkeypatch, nwGUI, fncDir,
|
||||
assert projView.requestDeleteItem() is False
|
||||
|
||||
# Create a project
|
||||
prjDir = os.path.join(fncDir, "project")
|
||||
buildTestProject(nwGUI, prjDir)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
# Try emptying the trash already now, when there is no trash folder
|
||||
assert projView.emptyTrash() is False
|
||||
@@ -363,7 +359,7 @@ def testGuiProjTree_RequestDeleteItem(qtbot, caplog, monkeypatch, nwGUI, fncDir,
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiProjTree_MoveItemToTrash(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd):
|
||||
def testGuiProjTree_MoveItemToTrash(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
"""Test moving items to Trash.
|
||||
"""
|
||||
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
||||
@@ -372,8 +368,7 @@ def testGuiProjTree_MoveItemToTrash(qtbot, caplog, monkeypatch, nwGUI, fncDir, m
|
||||
projTree = nwGUI.projView.projTree
|
||||
|
||||
# Create a project
|
||||
prjDir = os.path.join(fncDir, "project")
|
||||
buildTestProject(nwGUI, prjDir)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
# Invalid item
|
||||
caplog.clear()
|
||||
@@ -417,7 +412,7 @@ def testGuiProjTree_MoveItemToTrash(qtbot, caplog, monkeypatch, nwGUI, fncDir, m
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiProjTree_PermanentlyDeleteItem(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd):
|
||||
def testGuiProjTree_PermanentlyDeleteItem(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
"""Test permanently deleting items.
|
||||
"""
|
||||
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
||||
@@ -426,8 +421,7 @@ def testGuiProjTree_PermanentlyDeleteItem(qtbot, caplog, monkeypatch, nwGUI, fnc
|
||||
projTree = nwGUI.projView.projTree
|
||||
|
||||
# Create a project
|
||||
prjDir = os.path.join(fncDir, "project")
|
||||
buildTestProject(nwGUI, prjDir)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
# Invalid item
|
||||
caplog.clear()
|
||||
@@ -470,7 +464,7 @@ def testGuiProjTree_PermanentlyDeleteItem(qtbot, caplog, monkeypatch, nwGUI, fnc
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiProjTree_EmptyTrash(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd):
|
||||
def testGuiProjTree_EmptyTrash(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
"""Test emptying Trash.
|
||||
"""
|
||||
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
||||
@@ -484,8 +478,7 @@ def testGuiProjTree_EmptyTrash(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRn
|
||||
assert "No project open" in caplog.text
|
||||
|
||||
# Create a project
|
||||
prjDir = os.path.join(fncDir, "project")
|
||||
buildTestProject(nwGUI, prjDir)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
# No Trash folder
|
||||
assert projTree.emptyTrash() is False
|
||||
@@ -524,7 +517,7 @@ def testGuiProjTree_EmptyTrash(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRn
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
|
||||
def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
"""Test the building of the project tree context menu. All this does
|
||||
is test that the menu builds. It doesn't open the actual menu,
|
||||
"""
|
||||
@@ -532,8 +525,7 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
|
||||
monkeypatch.setattr(QMenu, "exec_", lambda *a: None)
|
||||
|
||||
# Create a project
|
||||
prjDir = os.path.join(fncDir, "project")
|
||||
buildTestProject(nwGUI, prjDir)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
# Handles for new objects
|
||||
hCharNote = "0000000000011"
|
||||
@@ -643,7 +635,7 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, fncDir, mockRnd, ipsumText):
|
||||
def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, projPath, mockRnd, ipsumText):
|
||||
"""Test the merge document function.
|
||||
"""
|
||||
mergeData = {}
|
||||
@@ -654,8 +646,7 @@ def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, fncDir, mockRnd, i
|
||||
monkeypatch.setattr(GuiDocMerge, "getData", lambda *a: mergeData)
|
||||
|
||||
# Create a project
|
||||
prjDir = os.path.join(fncDir, "project")
|
||||
buildTestProject(nwGUI, prjDir)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
theProject = nwGUI.theProject
|
||||
projTree = nwGUI.projView.projTree
|
||||
@@ -746,7 +737,7 @@ def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, fncDir, mockRnd, i
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, fncDir, mockRnd, ipsumText):
|
||||
def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, projPath, mockRnd, ipsumText):
|
||||
"""Test the split document function.
|
||||
"""
|
||||
splitData = {}
|
||||
@@ -758,8 +749,7 @@ def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, fncDir, mockRnd, ip
|
||||
monkeypatch.setattr(GuiDocSplit, "getData", lambda *a: (splitData, splitText))
|
||||
|
||||
# Create a project
|
||||
prjDir = os.path.join(fncDir, "project")
|
||||
buildTestProject(nwGUI, prjDir)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
theProject = nwGUI.theProject
|
||||
projTree = nwGUI.projView.projTree
|
||||
@@ -828,13 +818,13 @@ def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, fncDir, mockRnd, ip
|
||||
assert projTree._splitDocument(hSplitDoc) is True
|
||||
for tHandle in fstSet:
|
||||
assert tHandle in theProject.tree
|
||||
assert not os.path.isfile(os.path.join(prjDir, "content", f"{tHandle}.nwd"))
|
||||
assert not (projPath / "content" / f"{tHandle}.nwd").is_file()
|
||||
|
||||
# Writing succeeds
|
||||
assert projTree._splitDocument(hSplitDoc) is True
|
||||
for tHandle in sndSet:
|
||||
assert tHandle in theProject.tree
|
||||
assert os.path.isfile(os.path.join(prjDir, "content", f"{tHandle}.nwd"))
|
||||
assert (projPath / "content" / f"{tHandle}.nwd").is_file()
|
||||
|
||||
# Add to a folder and move source to trash
|
||||
splitData["intoFolder"] = True
|
||||
@@ -843,7 +833,7 @@ def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, fncDir, mockRnd, ip
|
||||
assert "0000000000029" in theProject.tree # The folder
|
||||
for tHandle in trdSet:
|
||||
assert tHandle in theProject.tree
|
||||
assert os.path.isfile(os.path.join(prjDir, "content", f"{tHandle}.nwd"))
|
||||
assert (projPath / "content" / f"{tHandle}.nwd").is_file()
|
||||
|
||||
assert theProject.tree.isTrash(hSplitDoc) is True
|
||||
|
||||
@@ -858,13 +848,12 @@ def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, fncDir, mockRnd, ip
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiProjTree_Other(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
|
||||
def testGuiProjTree_Other(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
"""Test various parts of the project tree class not covered by
|
||||
other tests.
|
||||
"""
|
||||
# Create a project
|
||||
prjDir = os.path.join(fncDir, "project")
|
||||
buildTestProject(nwGUI, prjDir)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
|
||||
projView = nwGUI.projView
|
||||
projTree = nwGUI.projView.projTree
|
||||
|
||||
@@ -28,10 +28,10 @@ from novelwriter.enum import nwState
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testGuiStatusBar_Main(qtbot, nwGUI, fncProj, mockRnd):
|
||||
def testGuiStatusBar_Main(qtbot, nwGUI, projPath, mockRnd):
|
||||
"""Test the the various features of the status bar.
|
||||
"""
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
cHandle = nwGUI.theProject.newFile("A Note", C.hCharRoot)
|
||||
newDoc = nwGUI.theProject.storage.getDocument(cHandle)
|
||||
newDoc.writeDocument("# A Note\n\n")
|
||||
|
||||
@@ -20,10 +20,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import os
|
||||
|
||||
from shutil import copyfile
|
||||
from pathlib import Path
|
||||
|
||||
from tools import cmpFiles, getGuiItem
|
||||
|
||||
@@ -34,7 +32,7 @@ from novelwriter.tools import GuiBuildNovel
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testToolBuild_Main(qtbot, monkeypatch, nwGUI, nwLipsum, refDir, outDir):
|
||||
def testToolBuild_Main(qtbot, monkeypatch, nwGUI, prjLipsum, tstPaths):
|
||||
"""Test the build tool.
|
||||
"""
|
||||
# Block message box
|
||||
@@ -45,7 +43,7 @@ def testToolBuild_Main(qtbot, monkeypatch, nwGUI, nwLipsum, refDir, outDir):
|
||||
assert getGuiItem("GuiBuildNovel") is None
|
||||
|
||||
# Open a project
|
||||
assert nwGUI.openProject(nwLipsum)
|
||||
assert nwGUI.openProject(prjLipsum)
|
||||
|
||||
# Open the tool
|
||||
nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger)
|
||||
@@ -69,41 +67,41 @@ def testToolBuild_Main(qtbot, monkeypatch, nwGUI, nwLipsum, refDir, outDir):
|
||||
assert not nwBuild._saveDocument(nwBuild.FMT_NWD)
|
||||
|
||||
# Default Settings
|
||||
nwGUI.mainConf._lastPath = Path(nwLipsum)
|
||||
nwGUI.mainConf._lastPath = prjLipsum
|
||||
qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)
|
||||
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_NWD)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step1_Lorem_Ipsum.nwd")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step1_Lorem_Ipsum.nwd")
|
||||
projFile = prjLipsum / "Lorem Ipsum.nwd"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step1_Lorem_Ipsum.nwd"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step1_Lorem_Ipsum.nwd"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_HTM)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step1_Lorem_Ipsum.htm")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step1_Lorem_Ipsum.htm")
|
||||
projFile = prjLipsum / "Lorem Ipsum.htm"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step1_Lorem_Ipsum.htm"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step1_Lorem_Ipsum.htm"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_MD)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.md")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step1_Lorem_Ipsum.md")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step1_Lorem_Ipsum.md")
|
||||
projFile = prjLipsum / "Lorem Ipsum.md"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step1_Lorem_Ipsum.md"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step1_Lorem_Ipsum.md"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_GH)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.md")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step1G_Lorem_Ipsum.md")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step1G_Lorem_Ipsum.md")
|
||||
projFile = prjLipsum / "Lorem Ipsum.md"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step1G_Lorem_Ipsum.md"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step1G_Lorem_Ipsum.md"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_FODT)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.fodt")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step1_Lorem_Ipsum.fodt")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step1_Lorem_Ipsum.fodt")
|
||||
projFile = prjLipsum / "Lorem Ipsum.fodt"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step1_Lorem_Ipsum.fodt"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step1_Lorem_Ipsum.fodt"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile, [4, 5])
|
||||
|
||||
@@ -124,30 +122,30 @@ def testToolBuild_Main(qtbot, monkeypatch, nwGUI, nwLipsum, refDir, outDir):
|
||||
qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)
|
||||
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_NWD)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step2_Lorem_Ipsum.nwd")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step2_Lorem_Ipsum.nwd")
|
||||
projFile = prjLipsum / "Lorem Ipsum.nwd"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step2_Lorem_Ipsum.nwd"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step2_Lorem_Ipsum.nwd"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_HTM)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step2_Lorem_Ipsum.htm")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step2_Lorem_Ipsum.htm")
|
||||
projFile = prjLipsum / "Lorem Ipsum.htm"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step2_Lorem_Ipsum.htm"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step2_Lorem_Ipsum.htm"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_MD)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.md")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step2_Lorem_Ipsum.md")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step2_Lorem_Ipsum.md")
|
||||
projFile = prjLipsum / "Lorem Ipsum.md"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step2_Lorem_Ipsum.md"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step2_Lorem_Ipsum.md"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_FODT)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.fodt")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step2_Lorem_Ipsum.fodt")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step2_Lorem_Ipsum.fodt")
|
||||
projFile = prjLipsum / "Lorem Ipsum.fodt"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step2_Lorem_Ipsum.fodt"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step2_Lorem_Ipsum.fodt"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile, [4, 5])
|
||||
|
||||
@@ -158,30 +156,30 @@ def testToolBuild_Main(qtbot, monkeypatch, nwGUI, nwLipsum, refDir, outDir):
|
||||
|
||||
# Save files that can be compared
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_NWD)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step3_Lorem_Ipsum.nwd")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step3_Lorem_Ipsum.nwd")
|
||||
projFile = prjLipsum / "Lorem Ipsum.nwd"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step3_Lorem_Ipsum.nwd"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step3_Lorem_Ipsum.nwd"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_HTM)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step3_Lorem_Ipsum.htm")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step3_Lorem_Ipsum.htm")
|
||||
projFile = prjLipsum / "Lorem Ipsum.htm"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step3_Lorem_Ipsum.htm"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step3_Lorem_Ipsum.htm"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_MD)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.md")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step3_Lorem_Ipsum.md")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step3_Lorem_Ipsum.md")
|
||||
projFile = prjLipsum / "Lorem Ipsum.md"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step3_Lorem_Ipsum.md"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step3_Lorem_Ipsum.md"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_FODT)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.fodt")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step3_Lorem_Ipsum.fodt")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step3_Lorem_Ipsum.fodt")
|
||||
projFile = prjLipsum / "Lorem Ipsum.fodt"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step3_Lorem_Ipsum.fodt"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step3_Lorem_Ipsum.fodt"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile, [4, 5])
|
||||
|
||||
@@ -199,43 +197,43 @@ def testToolBuild_Main(qtbot, monkeypatch, nwGUI, nwLipsum, refDir, outDir):
|
||||
|
||||
# Save files that can be compared
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_NWD)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step4_Lorem_Ipsum.nwd")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step4_Lorem_Ipsum.nwd")
|
||||
projFile = prjLipsum / "Lorem Ipsum.nwd"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step4_Lorem_Ipsum.nwd"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step4_Lorem_Ipsum.nwd"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_HTM)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step4_Lorem_Ipsum.htm")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step4_Lorem_Ipsum.htm")
|
||||
projFile = prjLipsum / "Lorem Ipsum.htm"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step4_Lorem_Ipsum.htm"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step4_Lorem_Ipsum.htm"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile)
|
||||
|
||||
# Check the JSON files too at this stage
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_JSON_H)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.json")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step4H_Lorem_Ipsum.json")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step4H_Lorem_Ipsum.json")
|
||||
projFile = prjLipsum / "Lorem Ipsum.json"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step4H_Lorem_Ipsum.json"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step4H_Lorem_Ipsum.json"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile, [8])
|
||||
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_JSON_M)
|
||||
projFile = os.path.join(nwLipsum, "Lorem Ipsum.json")
|
||||
testFile = os.path.join(outDir, "guiBuild_Tool_Step4M_Lorem_Ipsum.json")
|
||||
compFile = os.path.join(refDir, "guiBuild_Tool_Step4M_Lorem_Ipsum.json")
|
||||
projFile = prjLipsum / "Lorem Ipsum.json"
|
||||
testFile = tstPaths.outDir / "guiBuild_Tool_Step4M_Lorem_Ipsum.json"
|
||||
compFile = tstPaths.refDir / "guiBuild_Tool_Step4M_Lorem_Ipsum.json"
|
||||
copyfile(projFile, testFile)
|
||||
assert cmpFiles(testFile, compFile, [8])
|
||||
|
||||
# Since odt and fodt is built by the same code, we don't check the
|
||||
# output. but just that the different format can be written as well
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_ODT)
|
||||
assert os.path.isfile(os.path.join(nwLipsum, "Lorem Ipsum.odt"))
|
||||
assert (prjLipsum / "Lorem Ipsum.odt").is_file()
|
||||
|
||||
# Print to PDF
|
||||
if not nwGUI.mainConf.osDarwin:
|
||||
assert nwBuild._saveDocument(nwBuild.FMT_PDF)
|
||||
assert os.path.isfile(os.path.join(nwLipsum, "Lorem Ipsum.pdf"))
|
||||
assert (prjLipsum / "Lorem Ipsum.pdf").is_file()
|
||||
|
||||
# Close the build tool
|
||||
htmlText = nwBuild.htmlText
|
||||
|
||||
@@ -29,7 +29,7 @@ from novelwriter.tools import GuiLipsum
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testToolLipsum_Main(qtbot, nwGUI, fncProj, mockRnd):
|
||||
def testToolLipsum_Main(qtbot, nwGUI, projPath, mockRnd):
|
||||
"""Test the Lorem Ipsum tool.
|
||||
"""
|
||||
# Check that we cannot open when there is no project
|
||||
@@ -37,7 +37,7 @@ def testToolLipsum_Main(qtbot, nwGUI, fncProj, mockRnd):
|
||||
assert getGuiItem("GuiLipsum") is None
|
||||
|
||||
# Create a new project
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
assert nwGUI.openDocument(C.hSceneDoc) is True
|
||||
assert len(nwGUI.docEditor.getText()) == 15
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
@@ -37,7 +36,7 @@ from novelwriter.tools.projwizard import (
|
||||
|
||||
@pytest.mark.gui
|
||||
@pytest.mark.skipif(sys.platform.startswith("darwin"), reason="Not running on Darwin")
|
||||
def testToolProjectWizard_Handling(qtbot, monkeypatch, nwGUI, fncProj):
|
||||
def testToolProjectWizard_Handling(qtbot, monkeypatch, nwGUI, projPath):
|
||||
"""Test the launch of the project wizard.
|
||||
Disabled for macOS because the test segfaults on QWizard.show()
|
||||
"""
|
||||
@@ -45,7 +44,7 @@ def testToolProjectWizard_Handling(qtbot, monkeypatch, nwGUI, fncProj):
|
||||
# ========================
|
||||
|
||||
# New with a project open should cause an error
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(nwGUI, "closeProject", lambda *a: False)
|
||||
assert nwGUI.newProject() is False
|
||||
@@ -61,7 +60,7 @@ def testToolProjectWizard_Handling(qtbot, monkeypatch, nwGUI, fncProj):
|
||||
assert nwGUI.newProject() is False
|
||||
|
||||
# Now, with a non-empty folder
|
||||
mp.setattr(nwGUI, "showNewProjectDialog", lambda *a: {"projPath": fncProj})
|
||||
mp.setattr(nwGUI, "showNewProjectDialog", lambda *a: {"projPath": projPath})
|
||||
assert nwGUI.newProject() is False
|
||||
|
||||
# Test the Wizard Launching
|
||||
@@ -96,7 +95,7 @@ def testToolProjectWizard_Handling(qtbot, monkeypatch, nwGUI, fncProj):
|
||||
@pytest.mark.gui
|
||||
@pytest.mark.parametrize("prjType", ["minimal", "custom1", "custom2", "sample"])
|
||||
@pytest.mark.skipif(sys.platform.startswith("darwin"), reason="Not running on Darwin")
|
||||
def testToolProjectWizard_Run(qtbot, monkeypatch, nwGUI, fncDir, prjType):
|
||||
def testToolProjectWizard_Run(qtbot, monkeypatch, nwGUI, fncPath, prjType):
|
||||
"""Test the new project wizard with a set of selection scenarios.
|
||||
"""
|
||||
monkeypatch.setattr(GuiProjectWizard, "exec_", lambda *a: None)
|
||||
@@ -130,12 +129,12 @@ def testToolProjectWizard_Run(qtbot, monkeypatch, nwGUI, fncDir, prjType):
|
||||
assert storagePage.errLabel.text() == ""
|
||||
|
||||
# Set an invalid path
|
||||
storagePage.projPath.setText(os.path.join(fncDir, "not", "a", "path"))
|
||||
storagePage.projPath.setText(str(fncPath / "not" / "a" / "path"))
|
||||
assert not nwWiz.button(QWizard.NextButton).isEnabled()
|
||||
assert storagePage.errLabel.text().startswith("Error")
|
||||
|
||||
# Set an existing path
|
||||
storagePage.projPath.setText(fncDir)
|
||||
storagePage.projPath.setText(str(fncPath))
|
||||
assert not nwWiz.button(QWizard.NextButton).isEnabled()
|
||||
assert storagePage.errLabel.text().startswith("Error")
|
||||
|
||||
@@ -146,12 +145,12 @@ def testToolProjectWizard_Run(qtbot, monkeypatch, nwGUI, fncDir, prjType):
|
||||
assert storagePage.errLabel.text() == ""
|
||||
|
||||
# Let the browse feature handle it
|
||||
projPath = os.path.join(fncDir, "Test Wizard")
|
||||
projPath = fncPath / "Test Wizard"
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(QFileDialog, "getExistingDirectory", lambda *a, **k: fncDir)
|
||||
mp.setattr(QFileDialog, "getExistingDirectory", lambda *a, **k: str(fncPath))
|
||||
qtbot.mouseClick(storagePage.browseButton, Qt.LeftButton, delay=100)
|
||||
|
||||
assert storagePage.projPath.text() == projPath
|
||||
assert storagePage.projPath.text() == str(projPath)
|
||||
assert storagePage.errLabel.text() == ""
|
||||
|
||||
# Setting projPath should activate the button
|
||||
@@ -216,7 +215,7 @@ def testToolProjectWizard_Run(qtbot, monkeypatch, nwGUI, fncDir, prjType):
|
||||
assert projData["projName"] == "Test Wizard"
|
||||
assert projData["projTitle"] == "My Novel"
|
||||
assert projData["projAuthors"] == "Jane Doe"
|
||||
assert projData["projPath"] == projPath
|
||||
assert projData["projPath"] == str(projPath)
|
||||
assert projData["popMinimal"] == prjType.startswith("minimal")
|
||||
assert projData["popCustom"] == prjType.startswith("custom")
|
||||
assert projData["popSample"] == prjType.startswith("sample")
|
||||
|
||||
@@ -19,9 +19,8 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import json
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from mock import causeOSError
|
||||
from tools import getGuiItem, writeFile, buildTestProject
|
||||
@@ -34,14 +33,14 @@ from novelwriter.constants import nwFiles
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj):
|
||||
def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncPath, projPath):
|
||||
"""Test the full writing stats tool.
|
||||
"""
|
||||
# Create a project to work on
|
||||
buildTestProject(nwGUI, fncProj)
|
||||
buildTestProject(nwGUI, projPath)
|
||||
qtbot.wait(100)
|
||||
assert nwGUI.saveProject()
|
||||
sessFile = os.path.join(fncProj, "meta", nwFiles.SESS_STATS)
|
||||
sessFile = projPath / "meta" / nwFiles.SESS_STATS
|
||||
|
||||
# Open the Writing Stats dialog
|
||||
nwGUI.mainMenu.aWritingStats.activate(QAction.Trigger)
|
||||
@@ -54,7 +53,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj):
|
||||
# ============
|
||||
|
||||
# No initial logfile
|
||||
assert not os.path.isfile(sessFile)
|
||||
assert not sessFile.is_file()
|
||||
assert not sessLog._loadLogFile()
|
||||
|
||||
# Make a test log file
|
||||
@@ -66,7 +65,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj):
|
||||
"2020-01-03 21:30:00 2020-01-03 21:30:15 125 5\n"
|
||||
"2020-01-06 21:00:00 2020-01-06 21:00:10 125 5\n"
|
||||
))
|
||||
assert os.path.isfile(sessFile)
|
||||
assert sessFile.is_file()
|
||||
assert sessLog._loadLogFile()
|
||||
assert sessLog.wordOffset == 123
|
||||
assert len(sessLog.logData) == 4
|
||||
@@ -110,9 +109,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj):
|
||||
assert not sessLog._saveData(None)
|
||||
|
||||
# Make the save succeed
|
||||
monkeypatch.setattr("os.path.expanduser", lambda *a: fncDir)
|
||||
monkeypatch.setattr(QFileDialog, "getSaveFileName", lambda ss, tt, pp, options: (pp, ""))
|
||||
|
||||
sessLog.listBox.sortByColumn(sessLog.C_TIME, 0)
|
||||
|
||||
assert sessLog.novelWords.text() == "{:n}".format(600)
|
||||
@@ -135,7 +132,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj):
|
||||
qtbot.wait(100)
|
||||
|
||||
# Check the exported files
|
||||
jsonStats = os.path.join(fncDir, "sessionStats.json")
|
||||
jsonStats = fncPath / "sessionStats.json"
|
||||
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
|
||||
jsonData = json.load(inFile)
|
||||
|
||||
@@ -174,7 +171,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj):
|
||||
qtbot.mouseClick(sessLog.incNovel, Qt.LeftButton)
|
||||
assert sessLog._saveData(sessLog.FMT_JSON)
|
||||
|
||||
jsonStats = os.path.join(fncDir, "sessionStats.json")
|
||||
jsonStats = fncPath / "sessionStats.json"
|
||||
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
|
||||
jsonData = json.loads(inFile.read())
|
||||
|
||||
@@ -220,7 +217,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj):
|
||||
qtbot.mouseClick(sessLog.incNotes, Qt.LeftButton)
|
||||
assert sessLog._saveData(sessLog.FMT_JSON)
|
||||
|
||||
jsonStats = os.path.join(fncDir, "sessionStats.json")
|
||||
jsonStats = fncPath / "sessionStats.json"
|
||||
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
|
||||
jsonData = json.load(inFile)
|
||||
|
||||
@@ -268,7 +265,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj):
|
||||
|
||||
# qtbot.stop()
|
||||
|
||||
jsonStats = os.path.join(fncDir, "sessionStats.json")
|
||||
jsonStats = fncPath / "sessionStats.json"
|
||||
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
|
||||
jsonData = json.load(inFile)
|
||||
|
||||
@@ -298,7 +295,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj):
|
||||
qtbot.mouseClick(sessLog.hideZeros, Qt.LeftButton)
|
||||
assert sessLog._saveData(sessLog.FMT_JSON)
|
||||
|
||||
jsonStats = os.path.join(fncDir, "sessionStats.json")
|
||||
jsonStats = fncPath / "sessionStats.json"
|
||||
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
|
||||
jsonData = json.load(inFile)
|
||||
|
||||
@@ -351,7 +348,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj):
|
||||
qtbot.mouseClick(sessLog.groupByDay, Qt.LeftButton)
|
||||
assert sessLog._saveData(sessLog.FMT_JSON)
|
||||
|
||||
jsonStats = os.path.join(fncDir, "sessionStats.json")
|
||||
jsonStats = fncPath / "sessionStats.json"
|
||||
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
|
||||
jsonData = json.load(inFile)
|
||||
|
||||
|
||||
+14
-12
@@ -19,10 +19,11 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import os
|
||||
import time
|
||||
import shutil
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from PyQt5.QtWidgets import qApp
|
||||
|
||||
XML_IGNORE = ("<novelWriterXML", "<project")
|
||||
@@ -129,24 +130,25 @@ def writeFile(fileName, fileData):
|
||||
outFile.write(fileData)
|
||||
|
||||
|
||||
def cleanProject(projPath):
|
||||
def cleanProject(path):
|
||||
"""Delete all generated files in a project.
|
||||
"""
|
||||
cacheDir = os.path.join(projPath, "cache")
|
||||
if os.path.isdir(cacheDir):
|
||||
path = Path(path)
|
||||
cacheDir = path / "cache"
|
||||
if cacheDir.is_dir():
|
||||
shutil.rmtree(cacheDir)
|
||||
|
||||
metaDir = os.path.join(projPath, "meta")
|
||||
if os.path.isdir(metaDir):
|
||||
metaDir = path / "meta"
|
||||
if metaDir.is_dir():
|
||||
shutil.rmtree(metaDir)
|
||||
|
||||
bakFile = os.path.join(projPath, "nwProject.bak")
|
||||
if os.path.isfile(bakFile):
|
||||
os.unlink(bakFile)
|
||||
bakFile = path / "nwProject.bak"
|
||||
if bakFile.is_file():
|
||||
bakFile.unlink()
|
||||
|
||||
tocFile = os.path.join(projPath, "ToC.txt")
|
||||
if os.path.isfile(tocFile):
|
||||
os.unlink(tocFile)
|
||||
tocFile = path / "ToC.txt"
|
||||
if tocFile.is_file():
|
||||
tocFile.unlink()
|
||||
|
||||
return
|
||||
|
||||
|
||||
Reference in New Issue
Block a user