diff --git a/novelwriter/core/document.py b/novelwriter/core/document.py
index 7fe7f8e5..ab9b8ac9 100644
--- a/novelwriter/core/document.py
+++ b/novelwriter/core/document.py
@@ -138,7 +138,7 @@ class NWDocument:
contentPath = self.theProject.storage.contentPath
if not isinstance(contentPath, Path):
logger.error("No content path set")
- return None
+ return False
docFile = self._docHandle+".nwd"
logger.debug("Saving document: %s", docFile)
@@ -195,7 +195,7 @@ class NWDocument:
contentPath = self.theProject.storage.contentPath
if not isinstance(contentPath, Path):
logger.error("No content path set")
- return None
+ return False
docPath = contentPath / f"{self._docHandle}.nwd"
docTemp = docPath.with_suffix(".tmp")
diff --git a/novelwriter/core/index.py b/novelwriter/core/index.py
index f07c0ee0..249fd19d 100644
--- a/novelwriter/core/index.py
+++ b/novelwriter/core/index.py
@@ -820,8 +820,6 @@ class ItemIndex:
elif tItem.itemRoot == rootHandle:
for sTitle in self._items[tHandle].headings():
yield tHandle, sTitle, self._items[tHandle][sTitle]
- else:
- continue
return
diff --git a/novelwriter/core/project.py b/novelwriter/core/project.py
index d117f109..65d292c8 100644
--- a/novelwriter/core/project.py
+++ b/novelwriter/core/project.py
@@ -25,7 +25,6 @@ along with this program. If not, see .
from __future__ import annotations
-import os
import json
import logging
import novelwriter
@@ -82,8 +81,7 @@ class NWProject(QObject):
self.lockedBy = None # Data on which computer has the project open
# Class Settings
- self.projDict = None # The spell check dictionary
- self.projFiles = [] # A list of all files in the content folder on load
+ self.projFiles = [] # A list of all files in the content folder on load
# Internal Mapping
self.tr = partial(QCoreApplication.translate, "NWProject")
@@ -248,7 +246,6 @@ class NWProject(QObject):
self._data = NWProjectData(self)
# Project Settings
- self.projDict = None
self.projFiles = []
return
@@ -265,8 +262,6 @@ class NWProject(QObject):
logger.info("Opening project: %s", projPath)
- self.projDict = str(self._storage.getMetaFile(nwFiles.PROJ_DICT))
-
# Project Lock
# ============
@@ -367,11 +362,12 @@ class NWProject(QObject):
# Check the project tree consistency
for tItem in self._tree:
- tHandle = tItem.itemHandle
- logger.debug("Checking item '%s'", tHandle)
- if not self._tree.updateItemData(tHandle):
- logger.error("There was a problem item '%s', and it has been removed", tHandle)
- del self._tree[tHandle] # The file will be re-added as orphaned
+ if tItem:
+ tHandle = tItem.itemHandle
+ logger.debug("Checking item '%s'", tHandle)
+ if not self._tree.updateItemData(tHandle):
+ logger.error("There was a problem the item, and it has been removed")
+ del self._tree[tHandle] # The file will be re-added as orphaned
self._scanProjectFolder()
self._index.loadIndex()
@@ -694,20 +690,18 @@ class NWProject(QObject):
def _loadProjectLocalisation(self):
"""Load the language data for the current project language.
"""
- if self._data.language is None:
+ if self._data.language is None or self.mainConf.nwLangPath is None:
self._langData = {}
return False
- langFile = os.path.join(
- self.mainConf.nwLangPath, "project_%s.json" % self._data.language
- )
- if not os.path.isfile(langFile):
- langFile = os.path.join(self.mainConf.nwLangPath, "project_en_GB.json")
+ langFile = Path(self.mainConf.nwLangPath) / f"project_{self._data.language}.json"
+ if not langFile.is_file():
+ langFile = Path(self.mainConf.nwLangPath) / "project_en_GB.json"
try:
with open(langFile, mode="r", encoding="utf-8") as inFile:
self._langData = json.load(inFile)
- logger.debug("Loaded project language file: %s", os.path.basename(langFile))
+ logger.debug("Loaded project language file: %s", langFile.name)
except Exception:
logger.error("Failed to project language file")
diff --git a/novelwriter/core/spellcheck.py b/novelwriter/core/spellcheck.py
index 4a63bf39..30396d0d 100644
--- a/novelwriter/core/spellcheck.py
+++ b/novelwriter/core/spellcheck.py
@@ -23,10 +23,10 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
-import os
import logging
from collections import namedtuple
+from pathlib import Path
from novelwriter.error import logException
@@ -173,10 +173,10 @@ class NWSpellEnchant:
self._projDict = set()
self._projectDict = projectDict
- if projectDict is None:
+ if not isinstance(projectDict, Path):
return False
- if not os.path.isfile(projectDict):
+ if not projectDict.exists():
return False
try:
diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py
index 3e53b897..39c5edb3 100644
--- a/novelwriter/gui/doceditor.py
+++ b/novelwriter/gui/doceditor.py
@@ -53,7 +53,7 @@ from PyQt5.QtWidgets import (
from novelwriter.core import NWSpellEnchant, countWords
from novelwriter.enum import nwAlert, nwDocAction, nwDocInsert, nwDocMode
from novelwriter.common import transferCase
-from novelwriter.constants import nwConst, nwKeyWords, nwUnicode
+from novelwriter.constants import nwConst, nwFiles, nwKeyWords, nwUnicode
from novelwriter.gui.dochighlight import GuiDocHighlighter
logger = logging.getLogger(__name__)
@@ -689,7 +689,8 @@ class GuiDocEditor(QTextEdit):
else:
theLang = self.theProject.data.spellLang
- self.spEnchant.setLanguage(theLang, self.theProject.projDict)
+ projDict = self.theProject.storage.getMetaFile(nwFiles.PROJ_DICT)
+ self.spEnchant.setLanguage(theLang, projDict)
_, theProvider = self.spEnchant.describeDict()
self.spellDictionaryChanged.emit(str(theLang), str(theProvider))
diff --git a/tests/test_core/test_core_document.py b/tests/test_core/test_core_document.py
index ba74afbd..50dd28bf 100644
--- a/tests/test_core/test_core_document.py
+++ b/tests/test_core/test_core_document.py
@@ -19,7 +19,6 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
-import os
import pytest
from mock import causeOSError
@@ -31,12 +30,12 @@ from novelwriter.core.document import NWDocument
@pytest.mark.core
-def testCoreDocument_LoadSave(monkeypatch, mockGUI, fncDir, mockRnd):
+def testCoreDocument_LoadSave(monkeypatch, mockGUI, fncPath, mockRnd):
"""Test loading and saving a document with the NWDocument class.
"""
theProject = NWProject(mockGUI)
mockRnd.reset()
- buildTestProject(theProject, fncDir)
+ buildTestProject(theProject, fncPath)
# Read Document
# =============
@@ -51,6 +50,12 @@ def testCoreDocument_LoadSave(monkeypatch, mockGUI, fncDir, mockRnd):
assert theDoc.readDocument() is None
assert theDoc._currHash is None
+ # No content path
+ with monkeypatch.context() as mp:
+ mp.setattr("novelwriter.core.storage.NWStorage.contentPath", property(lambda *a: None))
+ theDoc = NWDocument(theProject, C.hSceneDoc)
+ assert theDoc.readDocument() is None
+
# Cause open() to fail while loading
with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError)
@@ -72,17 +77,23 @@ def testCoreDocument_LoadSave(monkeypatch, mockGUI, fncDir, mockRnd):
# Write Document
# ==============
- # Set handle and save again
+ # No content path
+ with monkeypatch.context() as mp:
+ mp.setattr("novelwriter.core.storage.NWStorage.contentPath", property(lambda *a: None))
+ theDoc = NWDocument(theProject, xHandle)
+ assert theDoc.writeDocument("") is False
+
+ # Set handle and save
theText = "### Test File\n\nText ...\n\n"
theDoc = NWDocument(theProject, xHandle)
assert theDoc.readDocument(xHandle) == ""
assert theDoc.writeDocument(theText) is True
# Save again to ensure temp file and previous file is handled
- assert theDoc.writeDocument(theText)
+ assert theDoc.writeDocument(theText) is True
# Check file content
- docPath = os.path.join(fncDir, "content", xHandle+".nwd")
+ docPath = fncPath / "content" / f"{xHandle}.nwd"
assert readFile(docPath) == (
"%%~name: New File\n"
f"%%~path: {C.hNovelRoot}/{xHandle}\n"
@@ -128,10 +139,16 @@ def testCoreDocument_LoadSave(monkeypatch, mockGUI, fncDir, mockRnd):
# Delete Document
# ===============
- # Delete the last document
+ # Delete a non-existing document
theDoc = NWDocument(theProject, "stuff")
assert theDoc.deleteDocument() is False
- assert os.path.isfile(docPath)
+ assert docPath.exists()
+
+ # No content path
+ with monkeypatch.context() as mp:
+ mp.setattr("novelwriter.core.storage.NWStorage.contentPath", property(lambda *a: None))
+ theDoc = NWDocument(theProject, xHandle)
+ assert theDoc.deleteDocument() is False
# Cause the delete to fail
with monkeypatch.context() as mp:
@@ -143,26 +160,26 @@ def testCoreDocument_LoadSave(monkeypatch, mockGUI, fncDir, mockRnd):
# Make the delete pass
theDoc = NWDocument(theProject, xHandle)
assert theDoc.deleteDocument() is True
- assert not os.path.isfile(docPath)
+ assert not docPath.exists()
# END Test testCoreDocument_Load
@pytest.mark.core
-def testCoreDocument_Methods(mockGUI, fncDir, mockRnd):
+def testCoreDocument_Methods(mockGUI, fncPath, mockRnd):
"""Test other methods of the NWDocument class.
"""
theProject = NWProject(mockGUI)
mockRnd.reset()
- buildTestProject(theProject, fncDir)
+ buildTestProject(theProject, fncPath)
theDoc = NWDocument(theProject, C.hSceneDoc)
- docPath = os.path.join(fncDir, "content", C.hSceneDoc+".nwd")
+ docPath = fncPath / "content" / f"{C.hSceneDoc}.nwd"
assert theDoc.readDocument() == "### New Scene\n\n"
# Check location
- assert theDoc.getFileLocation() == docPath
+ assert theDoc.getFileLocation() == str(docPath)
# Check the item
assert theDoc.getCurrentItem() is not None
diff --git a/tests/test_core/test_core_index.py b/tests/test_core/test_core_index.py
index 678f00e5..d08577d7 100644
--- a/tests/test_core/test_core_index.py
+++ b/tests/test_core/test_core_index.py
@@ -19,11 +19,11 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
-import os
import json
import pytest
from shutil import copyfile
+from pathlib import Path
from mock import causeException
from tools import C, buildTestProject, cmpFiles, writeFile
@@ -35,13 +35,13 @@ from novelwriter.core.project import NWProject
@pytest.mark.core
-def testCoreIndex_LoadSave(monkeypatch, nwLipsum, mockGUI, outDir, refDir):
+def testCoreIndex_LoadSave(monkeypatch, nwLipsum, mockGUI, tstPaths):
"""Test core functionality of scaning, saving, loading and checking
the index cache file.
"""
- projFile = os.path.join(nwLipsum, "meta", nwFiles.INDEX_FILE)
- testFile = os.path.join(outDir, "coreIndex_LoadSave_tagsIndex.json")
- compFile = os.path.join(refDir, "coreIndex_LoadSave_tagsIndex.json")
+ projFile = Path(nwLipsum) / "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)
@@ -62,6 +62,11 @@ def testCoreIndex_LoadSave(monkeypatch, nwLipsum, mockGUI, outDir, refDir):
assert theIndex.reIndexHandle(None) is False
+ # No folder for saving
+ with monkeypatch.context() as mp:
+ mp.setattr("novelwriter.core.storage.NWStorage.getMetaFile", lambda *a: None)
+ assert theIndex.saveIndex() is False
+
# Make the save fail
with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeException)
@@ -86,6 +91,11 @@ def testCoreIndex_LoadSave(monkeypatch, nwLipsum, mockGUI, outDir, refDir):
assert theIndex._tagsIndex._tags == {}
assert theIndex._itemIndex._items == {}
+ # No folder for sloading
+ with monkeypatch.context() as mp:
+ mp.setattr("novelwriter.core.storage.NWStorage.getMetaFile", lambda *a: None)
+ assert theIndex.loadIndex() is False
+
# Make the load fail
with monkeypatch.context() as mp:
mp.setattr(json, "load", causeException)
diff --git a/tests/test_core/test_core_project.py b/tests/test_core/test_core_project.py
index e2e6aad2..377273da 100644
--- a/tests/test_core/test_core_project.py
+++ b/tests/test_core/test_core_project.py
@@ -19,8 +19,6 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
-import os
-import shutil
import pytest
from time import time
@@ -42,16 +40,16 @@ from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter, XMLR
@pytest.mark.core
-def testCoreProject_NewRoot(fncDir, outDir, refDir, mockGUI, mockRnd):
+def testCoreProject_NewRoot(fncPath, tstPaths, mockGUI, mockRnd):
"""Check that new root folders can be added to the project.
"""
- projFile = os.path.join(fncDir, "nwProject.nwx")
- testFile = os.path.join(outDir, "coreProject_NewRoot_nwProject.nwx")
- compFile = os.path.join(refDir, "coreProject_NewRoot_nwProject.nwx")
+ projFile = fncPath / "nwProject.nwx"
+ testFile = tstPaths.outDir / "coreProject_NewRoot_nwProject.nwx"
+ compFile = tstPaths.refDir / "coreProject_NewRoot_nwProject.nwx"
theProject = NWProject(mockGUI)
mockRnd.reset()
- buildTestProject(theProject, fncDir)
+ buildTestProject(theProject, fncPath)
assert theProject.newRoot(nwItemClass.NOVEL) == "0000000000010"
assert theProject.newRoot(nwItemClass.PLOT) == "0000000000011"
@@ -93,16 +91,16 @@ def testCoreProject_NewRoot(fncDir, outDir, refDir, mockGUI, mockRnd):
@pytest.mark.core
-def testCoreProject_NewFileFolder(monkeypatch, fncDir, outDir, refDir, mockGUI, mockRnd):
+def testCoreProject_NewFileFolder(monkeypatch, fncPath, tstPaths, mockGUI, mockRnd):
"""Check that new files can be added to the project.
"""
- projFile = os.path.join(fncDir, "nwProject.nwx")
- testFile = os.path.join(outDir, "coreProject_NewFileFolder_nwProject.nwx")
- compFile = os.path.join(refDir, "coreProject_NewFileFolder_nwProject.nwx")
+ projFile = fncPath / "nwProject.nwx"
+ testFile = tstPaths.outDir / "coreProject_NewFileFolder_nwProject.nwx"
+ compFile = tstPaths.refDir / "coreProject_NewFileFolder_nwProject.nwx"
theProject = NWProject(mockGUI)
mockRnd.reset()
- buildTestProject(theProject, fncDir)
+ buildTestProject(theProject, fncPath)
# Invalid call
assert theProject.newFolder("New Folder", "1234567890abc") is None
@@ -147,15 +145,15 @@ def testCoreProject_NewFileFolder(monkeypatch, fncDir, outDir, refDir, mockGUI,
assert "0000000000011" in theProject.tree
# Delete new files and folders
- assert os.path.isfile(os.path.join(fncDir, "content", "0000000000012.nwd"))
- assert os.path.isfile(os.path.join(fncDir, "content", "0000000000011.nwd"))
+ assert (fncPath / "content" / "0000000000012.nwd").exists()
+ assert (fncPath / "content" / "0000000000011.nwd").exists()
assert theProject.removeItem("0000000000012") is True
assert theProject.removeItem("0000000000011") is True
assert theProject.removeItem("0000000000010") is True
- assert not os.path.isfile(os.path.join(fncDir, "content", "0000000000012.nwd"))
- assert not os.path.isfile(os.path.join(fncDir, "content", "0000000000011.nwd"))
+ assert not (fncPath / "content" / "0000000000012.nwd").exists()
+ assert not (fncPath / "content" / "0000000000011.nwd").exists()
assert "0000000000010" not in theProject.tree
assert "0000000000011" not in theProject.tree
@@ -167,69 +165,66 @@ def testCoreProject_NewFileFolder(monkeypatch, fncDir, outDir, refDir, mockGUI,
@pytest.mark.core
-def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncDir, mockRnd):
+def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncPath, mockRnd):
"""Test opening a project.
"""
theProject = NWProject(mockGUI)
mockRnd.reset()
- buildTestProject(theProject, fncDir)
+ buildTestProject(theProject, fncPath)
- # Rename the project file to check handling
- rName = os.path.join(fncDir, nwFiles.PROJ_FILE)
- wName = os.path.join(fncDir, nwFiles.PROJ_FILE+"_sdfghj")
- os.rename(rName, wName)
- assert theProject.openProject(fncDir) is False
- os.rename(wName, rName)
-
- # Fail on folder structure check
+ # Initialising the storage class fails
with monkeypatch.context() as mp:
- mp.setattr("os.mkdir", causeOSError)
- shutil.rmtree(os.path.join(fncDir, "meta"))
- assert theProject.openProject(fncDir) is False
+ mp.setattr("novelwriter.core.storage.NWStorage.openProjectInPlace", lambda *a, **k: False)
+ assert theProject.openProject(fncPath) is False
# Fail on lock file
assert theProject._storage.writeLockFile()
- assert theProject.openProject(fncDir) is False
+ assert theProject.openProject(fncPath) is False
# Fail to read lockfile (which still opens the project)
with monkeypatch.context() as mp:
mp.setattr("novelwriter.core.storage.NWStorage.readLockFile", lambda *a: ["ERROR"])
caplog.clear()
- assert theProject.openProject(fncDir) is True
+ assert theProject.openProject(fncPath) is True
assert "Failed to check lock file" in caplog.text
- assert theProject.closeProject()
+ assert theProject.closeProject()
# Force open with lockfile
assert theProject._storage.writeLockFile()
- assert theProject.openProject(fncDir, overrideLock=True) is True
+ assert theProject.openProject(fncPath, overrideLock=True) is True
assert theProject.closeProject()
+ # Fail getting xml reader
+ with monkeypatch.context() as mp:
+ mp.setattr("novelwriter.core.storage.NWStorage.getXmlReader", lambda *a: None)
+ assert theProject.openProject(fncPath) is False
+
# Not a novelwriter XML file
with monkeypatch.context() as mp:
mp.setattr(ProjectXMLReader, "read", lambda *a: False)
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.NOT_NWX_FILE))
- assert theProject.openProject(fncDir) is False
+ assert theProject.openProject(fncPath) is False
assert "Project file does not appear" in mockGUI.lastAlert
# Unknown project file version
with monkeypatch.context() as mp:
mp.setattr(ProjectXMLReader, "read", lambda *a: False)
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.UNKNOWN_VERSION))
- assert theProject.openProject(fncDir) is False
+ assert theProject.openProject(fncPath) is False
assert "Unknown or unsupported novelWriter project file" in mockGUI.lastAlert
# Other parse error
with monkeypatch.context() as mp:
mp.setattr(ProjectXMLReader, "read", lambda *a: False)
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.CANNOT_PARSE))
- assert theProject.openProject(fncDir) is False
+ assert theProject.openProject(fncPath) is False
assert "Failed to parse project xml" in mockGUI.lastAlert
# Won't convert legacy file
with monkeypatch.context() as mp:
mp.setattr(ProjectXMLReader, "state", property(lambda *a: XMLReadState.WAS_LEGACY))
mockGUI.askResponse = False
- assert theProject.openProject(fncDir) is False
+ assert theProject.openProject(fncPath) is False
assert "The file format of your project is about to be" in mockGUI.lastQuestion[1]
mockGUI.askResponse = True
@@ -237,17 +232,22 @@ def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncDir, mockRnd):
with monkeypatch.context() as mp:
mp.setattr(ProjectXMLReader, "hexVersion", property(lambda *a: 0x99999999))
mockGUI.askResponse = False
- assert theProject.openProject(fncDir) is False
+ assert theProject.openProject(fncPath) is False
assert "This project was saved by a newer version" in mockGUI.lastQuestion[1]
mockGUI.askResponse = True
+ # Fail checking items should still pass
+ with monkeypatch.context() as mp:
+ mp.setattr("novelwriter.core.tree.NWTree.updateItemData", lambda *a: False)
+ assert theProject.openProject(fncPath) is True
+
assert theProject.closeProject()
# END Test testCoreProject_Open
@pytest.mark.core
-def testCoreProject_Save(monkeypatch, mockGUI, mockRnd, fncDir, refDir):
+def testCoreProject_Save(monkeypatch, mockGUI, mockRnd, fncPath):
"""Test saving a project.
"""
theProject = NWProject(mockGUI)
@@ -256,7 +256,12 @@ def testCoreProject_Save(monkeypatch, mockGUI, mockRnd, fncDir, refDir):
assert theProject.saveProject() is False
mockRnd.reset()
- buildTestProject(theProject, fncDir)
+ buildTestProject(theProject, fncPath)
+
+ # Fail getting xml writer
+ with monkeypatch.context() as mp:
+ mp.setattr("novelwriter.core.storage.NWStorage.getXmlWriter", lambda *a: None)
+ assert theProject.saveProject() is False
# Fail writing
with monkeypatch.context() as mp:
@@ -272,11 +277,11 @@ def testCoreProject_Save(monkeypatch, mockGUI, mockRnd, fncDir, refDir):
@pytest.mark.core
-def testCoreProject_AccessItems(mockGUI, fncDir, mockRnd):
+def testCoreProject_AccessItems(mockGUI, fncPath, mockRnd):
"""Test helper functions for the project folder.
"""
theProject = NWProject(mockGUI)
- buildTestProject(theProject, fncDir)
+ buildTestProject(theProject, fncPath)
# Storage Objects
assert isinstance(theProject.index, NWIndex)
@@ -337,12 +342,12 @@ def testCoreProject_AccessItems(mockGUI, fncDir, mockRnd):
@pytest.mark.core
-def testCoreProject_StatusImport(mockGUI, fncDir, mockRnd):
+def testCoreProject_StatusImport(mockGUI, fncPath, mockRnd):
"""Test the status and importance flag handling.
"""
theProject = NWProject(mockGUI)
mockRnd.reset()
- buildTestProject(theProject, fncDir)
+ buildTestProject(theProject, fncPath)
statusKeys = [C.sNew, C.sNote, C.sDraft, C.sFinished]
importKeys = [C.iNew, C.iMinor, C.iMajor, C.iMain]
@@ -447,11 +452,11 @@ def testCoreProject_StatusImport(mockGUI, fncDir, mockRnd):
@pytest.mark.core
-def testCoreProject_Methods(monkeypatch, mockGUI, fncDir, mockRnd):
+def testCoreProject_Methods(monkeypatch, mockGUI, fncPath, mockRnd):
"""Test other project class methods and functions.
"""
theProject = NWProject(mockGUI)
- buildTestProject(theProject, fncDir)
+ buildTestProject(theProject, fncPath)
# Project Name
theProject.data.setName(" A Name ")
@@ -497,9 +502,12 @@ def testCoreProject_Methods(monkeypatch, mockGUI, fncDir, mockRnd):
# Spell check
theProject.setProjectChanged(False)
+ theProject._projAltered = False
theProject.data.setSpellCheck(True)
theProject.data.setSpellCheck(False)
- assert theProject.projChanged
+ assert theProject.projChanged is True
+ assert theProject.projAltered is True
+ assert theProject.projOpened > 0
# Spell language
theProject.setProjectChanged(False)
@@ -510,7 +518,7 @@ def testCoreProject_Methods(monkeypatch, mockGUI, fncDir, mockRnd):
assert theProject.data.spellLang is None
theProject.data.setSpellLang("en_GB")
assert theProject.data.spellLang == "en_GB"
- assert theProject.projChanged
+ assert theProject.projChanged is True
# Project Language
theProject.setProjectChanged(False)
@@ -524,6 +532,20 @@ def testCoreProject_Methods(monkeypatch, mockGUI, fncDir, mockRnd):
assert theProject.localLookup(1) == "One"
assert theProject.localLookup(10) == "Ten"
+ # Set invalid language
+ theProject.data.setLanguage("foo")
+ theProject._loadProjectLocalisation()
+ assert theProject.localLookup(1) == "One"
+ assert theProject.localLookup(10) == "Ten"
+
+ # Block reading language data
+ theProject.data.setLanguage("en")
+ with monkeypatch.context() as mp:
+ mp.setattr("builtins.open", causeOSError)
+ theProject._loadProjectLocalisation()
+ assert theProject.localLookup(1) == "One"
+ assert theProject.localLookup(10) == "Ten"
+
# Last edited
theProject.setProjectChanged(False)
theProject._data.setLastHandle("0123456789abc", "editor")
@@ -624,7 +646,7 @@ def testCoreProject_OrphanedFiles(mockGUI, nwLipsum):
assert theProject.closeProject() is True
# First Item with Meta Data
- orphPath = os.path.join(nwLipsum, "content", "636b6aa9b697b.nwd")
+ orphPath = Path(nwLipsum) / "content" / "636b6aa9b697b.nwd"
writeFile(orphPath, (
"%%~name:[Recovered] Mars\n"
"%%~path:5eaea4e8cdee8/636b6aa9b697b\n"
@@ -634,19 +656,19 @@ def testCoreProject_OrphanedFiles(mockGUI, nwLipsum):
))
# Second Item without Meta Data
- orphPath = os.path.join(nwLipsum, "content", "736b6aa9b697b.nwd")
+ orphPath = Path(nwLipsum) / "content" / "736b6aa9b697b.nwd"
writeFile(orphPath, "\n")
# Invalid File Name
- tstPath = os.path.join(nwLipsum, "content", "636b6aa9b697b.txt")
+ tstPath = Path(nwLipsum) / "content" / "636b6aa9b697b.txt"
writeFile(tstPath, "\n")
# Invalid File Name
- tstPath = os.path.join(nwLipsum, "content", "636b6aa9b697bb.nwd")
+ tstPath = Path(nwLipsum) / "content" / "636b6aa9b697bb.nwd"
writeFile(tstPath, "\n")
# Invalid File Name
- tstPath = os.path.join(nwLipsum, "content", "abcdefghijklm.nwd")
+ tstPath = Path(nwLipsum) / "content" / "abcdefghijklm.nwd"
writeFile(tstPath, "\n")
assert theProject.openProject(nwLipsum)
@@ -686,16 +708,21 @@ def testCoreProject_OrphanedFiles(mockGUI, nwLipsum):
@pytest.mark.core
-def testCoreProject_Backup(monkeypatch, mockGUI, fncDir, tmpDir):
+def testCoreProject_Backup(monkeypatch, mockGUI, fncPath, tmpPath):
"""Test the automated backup feature of the project class. The test
creates a backup of the Minimal test project, and then unzips the
backupd file and checks that the project XML file is identical to
the original file.
"""
theProject = NWProject(mockGUI)
- buildTestProject(theProject, fncDir)
- # Test faulty settings
+ # No Project
+ assert theProject.backupProject(doNotify=False) is False
+
+ buildTestProject(theProject, fncPath)
+
+ # Invalid Settings
+ # ================
# No project
mockGUI.hasProject = False
@@ -707,21 +734,14 @@ def testCoreProject_Backup(monkeypatch, mockGUI, fncDir, tmpDir):
assert theProject.backupProject(doNotify=False) is False
# Missing project name
- theProject.mainConf.backupPath = tmpDir
+ theProject.mainConf.backupPath = str(tmpPath)
theProject.data.setName("")
assert theProject.backupProject(doNotify=False) is False
- # Non-existent folder
- theProject.mainConf.backupPath = os.path.join(tmpDir, "nonexistent")
+ # Valid Settings
+ # ==============
+ theProject.mainConf.backupPath = str(tmpPath)
theProject.data.setName("Test Minimal")
- assert theProject.backupProject(doNotify=False) is False
-
- # Subfolder of project (causes infinite loop in zipping)
- theProject.mainConf.backupPath = os.path.join(fncDir, "subdir")
- assert theProject.backupProject(doNotify=False) is False
-
- # Set a valid folder
- theProject.mainConf.backupPath = tmpDir
# Can't make folder
with monkeypatch.context() as mp:
@@ -736,21 +756,21 @@ def testCoreProject_Backup(monkeypatch, mockGUI, fncDir, tmpDir):
# Test correct settings
assert theProject.backupProject(doNotify=True) is True
- theFiles = os.listdir(os.path.join(tmpDir, "Test Minimal"))
+ theFiles = list((tmpPath / "Test Minimal").iterdir())
assert len(theFiles) == 1
- theZip = theFiles[0]
+ theZip = theFiles[0].name
assert theZip[:12] == "Backup from "
assert theZip[-4:] == ".zip"
# Extract the archive
- with ZipFile(os.path.join(tmpDir, "Test Minimal", theZip), "r") as inZip:
- inZip.extractall(os.path.join(tmpDir, "extract"))
+ with ZipFile(tmpPath / "Test Minimal" / theZip, mode="r") as inZip:
+ inZip.extractall(tmpPath / "extract")
# Check that the main project file was restored
assert cmpFiles(
- os.path.join(fncDir, "nwProject.nwx"),
- os.path.join(tmpDir, "extract", "nwProject.nwx")
+ fncPath / "nwProject.nwx",
+ tmpPath / "extract" / "nwProject.nwx"
)
# END Test testCoreProject_Backup
diff --git a/tests/test_core/test_core_spellcheck.py b/tests/test_core/test_core_spellcheck.py
index 66dd33b2..b3b00bf4 100644
--- a/tests/test_core/test_core_spellcheck.py
+++ b/tests/test_core/test_core_spellcheck.py
@@ -19,7 +19,6 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
-import os
import sys
import pytest
@@ -63,10 +62,10 @@ def testCoreSpell_FakeEnchant(monkeypatch):
@pytest.mark.core
-def testCoreSpell_Enchant(monkeypatch, fncDir):
+def testCoreSpell_Enchant(monkeypatch, fncPath):
"""Test the pyenchant spell checker.
"""
- wList = os.path.join(fncDir, "wordlist.txt")
+ wList = fncPath / "wordlist.txt"
writeFile(wList, "a_word\nb_word\nc_word\n")
# Break the enchant package, and check error handling
@@ -134,13 +133,13 @@ def testCoreSpell_Enchant(monkeypatch, fncDir):
@pytest.mark.core
-def testCoreSpell_SessionWords(fncDir):
+def testCoreSpell_SessionWords(fncPath):
"""Test the handling of the custom word list in the spell checker.
New project sessions should not inherit the project word list from
other sessions, so this test checks that they don't bleed through.
"""
- wList1 = os.path.join(fncDir, "wordlist1.txt")
- wList2 = os.path.join(fncDir, "wordlist2.txt")
+ wList1 = fncPath / "wordlist1.txt"
+ wList2 = fncPath / "wordlist2.txt"
writeFile(wList1, "a_word\nb_word\nc_word\n")
writeFile(wList2, "d_word\ne_word\nf_word\n")