From c353e9ffb121196fdfffaee270454296a799073b Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sat, 5 Dec 2020 21:06:57 +0100 Subject: [PATCH] Updated and new tests for NWProject class --- nw/core/project.py | 51 +- tests/README.md | 1 + tests/conftest.py | 9 +- tests/dummy.py | 20 + tests/reference/coreProject_2_nwProject.nwx | 189 ++++- tests/reference/coreProject_3_nwProject.nwx | 108 ++- tests/reference/coreProject_4_nwProject.nwx | 189 +---- tests/reference/coreProject_5_nwProject.nwx | 108 +-- tests/test_core_project.py | 832 ++++++++++++++++++-- tests/test_core_tree.py | 6 +- 10 files changed, 1101 insertions(+), 412 deletions(-) diff --git a/nw/core/project.py b/nw/core/project.py index b646934a..1a834d73 100644 --- a/nw/core/project.py +++ b/nw/core/project.py @@ -1125,13 +1125,11 @@ class NWProject(): sentItems = [] iterItems = self.projTree.handles() n = 0 - nMax = len(iterItems) + nMax = min(len(iterItems), 10000) while n < nMax: tHandle = iterItems[n] tItem = self.projTree[tHandle] n += 1 - if n > 10000: - return # Just in case if tItem is None: # Technically a bug since treeOrder is built from the # same data as projTree @@ -1147,10 +1145,11 @@ class NWProject(): yield tItem elif tItem.itemParent in iterItems: # Item's parent exists, but hasn't been sent yet, so add - # it again to the end + # it again to the end, but make sure this doesn't get + # out hand, so we cap at 10000 items logger.warning("Item %s found before its parent" % tHandle) iterItems.append(tHandle) - nMax = len(iterItems) + nMax = min(len(iterItems), 10000) else: # Item is orphaned logger.error("Item %s has no parent in current tree" % tHandle) @@ -1189,13 +1188,12 @@ class NWProject(): if not os.path.isfile(lockFile): return [] + theLines = [] try: with open(lockFile, mode="r", encoding="utf8") as inFile: theData = inFile.read() theLines = theData.splitlines() - if len(theLines) == 4: - return theLines - else: + if len(theLines) != 4: return ["ERROR"] except Exception as e: @@ -1203,7 +1201,7 @@ class NWProject(): logger.error(str(e)) return ["ERROR"] - return ["ERROR"] + return theLines def _writeLockFile(self): """Writes a lock file to the project folder. @@ -1236,13 +1234,12 @@ class NWProject(): if os.path.isfile(lockFile): try: os.unlink(lockFile) - return True except Exception as e: logger.error("Failed to remove project lockfile") logger.error(str(e)) return False - return None + return True def _checkFolder(self, thePath): """Check if a folder exists, and if it doesn't, create it. @@ -1356,21 +1353,27 @@ class NWProject(): sessionFile = os.path.join(self.projMeta, nwFiles.SESS_STATS) isFile = os.path.isfile(sessionFile) - with open(sessionFile, mode="a+", encoding="utf8") as outFile: - if not isFile: - # It's a new file, so add a header - if self.lastWCount > 0: - outFile.write("# Offset %d\n" % self.lastWCount) - outFile.write("# %-17s %-19s %8s %8s\n" % ( - "Start Time", "End Time", "Novel", "Notes" + try: + with open(sessionFile, mode="a+", encoding="utf8") as outFile: + if not isFile: + # It's a new file, so add a header + if self.lastWCount > 0: + outFile.write("# Offset %d\n" % self.lastWCount) + outFile.write("# %-17s %-19s %8s %8s\n" % ( + "Start Time", "End Time", "Novel", "Notes" + )) + + outFile.write("%-19s %-19s %8d %8d\n" % ( + formatTimeStamp(self.projOpened), + formatTimeStamp(time()), + self.novelWCount, + self.notesWCount, )) - outFile.write("%-19s %-19s %8d %8d\n" % ( - formatTimeStamp(self.projOpened), - formatTimeStamp(time()), - self.novelWCount, - self.notesWCount, - )) + except Exception as e: + logger.error("Failed to write session stats file") + logger.error(str(e)) + return False return True diff --git a/tests/README.md b/tests/README.md index 82a34712..cd1be55b 100644 --- a/tests/README.md +++ b/tests/README.md @@ -65,6 +65,7 @@ The commands for the respective test categories are listed below. | Unit | NWDoc class | nw/core/document.py | `-m core` | `-k testCoreDocument` | | Unit | NWIndex class | nw/core/index.py | `-m core` | `-k testCoreIndex` | | Unit | NWItem class | nw/core/item.py | `-m core` | `-k testCoreItem` | +| Unit | NWProject class | nw/core/project.py | `-m core` | `-k testCoreProject` | | Unit | NWSpell* classes | nw/core/spellcheck.py | `-m core` | `-k testCoreSpell` | | Unit | NWStatus class | nw/core/status.py | `-m core` | `-k testCoreStatus` | | Unit | NWTree class | nw/core/tree.py | `-m core` | `-k testCoreTree` | diff --git a/tests/conftest.py b/tests/conftest.py index e6b90511..1f7b88ae 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,12 +6,15 @@ import sys import pytest import shutil import os +import time from dummy import DummyMain from PyQt5.QtWidgets import QMessageBox sys.path.insert(1, os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))) +os.environ["TZ"] = "UTC" +time.tzset() from nw.config import Config # noqa: E402 @@ -69,7 +72,7 @@ def fncDir(tmpDir): # novelWriter Objects ## -@pytest.fixture(scope="session") +@pytest.fixture(scope="function") def tmpConf(tmpDir): """Create a temporary novelWriter configuration object. """ @@ -78,7 +81,7 @@ def tmpConf(tmpDir): theConf.setLastPath("") return theConf -@pytest.fixture(scope="session") +@pytest.fixture(scope="function") def dummyGUI(tmpConf): """Create a dummy instance of novelWriter's main GUI class. """ @@ -168,6 +171,8 @@ def yesToAll(monkeypatch): monkeypatch.setattr( QMessageBox, "critical", lambda *args, **kwargs: QMessageBox.Yes ) + yield + monkeypatch.undo() return # =============================================================================================== # diff --git a/tests/dummy.py b/tests/dummy.py index 803e4e12..0f26e0ff 100644 --- a/tests/dummy.py +++ b/tests/dummy.py @@ -14,12 +14,22 @@ class DummyMain(): self.theIndex = None self.theProject = None self.statusBar = StatusBar() + + # Test Variables + self.askResponse = True + self.lastAlert = "" + return def makeAlert(self, theMessage, theLevel): print("%s: %s" % (str(theLevel), theMessage)) + self.lastAlert = str(theMessage) return + def askQuestion(self, theTitle, theQustion): + print("Question: %s" % theQustion) + return self.askResponse + def setStatus(self, theMessage): return @@ -32,6 +42,16 @@ class DummyMain(): def rebuildIndex(self): return + # Test Functions + + def undo(self): + self.askResponse = True + return + + def clear(self): + self.lastAlert = "" + return + # END Class GuiMain class StatusBar(): diff --git a/tests/reference/coreProject_2_nwProject.nwx b/tests/reference/coreProject_2_nwProject.nwx index 9ea0617f..fc7e7ab2 100644 --- a/tests/reference/coreProject_2_nwProject.nwx +++ b/tests/reference/coreProject_2_nwProject.nwx @@ -1,9 +1,11 @@ - New Project - - 2 + Test Custom + Test Novel + Jane Doe + John Doh + 1 1 0 @@ -38,7 +40,7 @@ Main - + Novel ROOT @@ -61,13 +63,34 @@ False - World + Locations ROOT WORLD New False - + + Timeline + ROOT + TIMELINE + New + False + + + Objects + ROOT + OBJECT + New + False + + + Entity + ROOT + ENTITY + New + False + + Title Page FILE NOVEL @@ -79,15 +102,15 @@ 0 0 - - New Chapter + + Chapter 1 FOLDER NOVEL New False - - New Chapter + + Chapter 1 FILE NOVEL New @@ -98,8 +121,8 @@ 0 0 - - New Scene + + Scene 1.1 FILE NOVEL New @@ -110,33 +133,139 @@ 0 0 - - Timeline - ROOT - TIMELINE + + Scene 1.2 + FILE + NOVEL + New + True + SCENE + 0 + 0 + 0 + 0 + + + Scene 1.3 + FILE + NOVEL + New + True + SCENE + 0 + 0 + 0 + 0 + + + Chapter 2 + FOLDER + NOVEL New False - - Object - ROOT - OBJECT + + Chapter 2 + FILE + NOVEL + New + True + CHAPTER + 0 + 0 + 0 + 0 + + + Scene 2.1 + FILE + NOVEL + New + True + SCENE + 0 + 0 + 0 + 0 + + + Scene 2.2 + FILE + NOVEL + New + True + SCENE + 0 + 0 + 0 + 0 + + + Scene 2.3 + FILE + NOVEL + New + True + SCENE + 0 + 0 + 0 + 0 + + + Chapter 3 + FOLDER + NOVEL New False - - Custom1 - ROOT - CUSTOM + + Chapter 3 + FILE + NOVEL New - False + True + CHAPTER + 0 + 0 + 0 + 0 - - Custom2 - ROOT - CUSTOM + + Scene 3.1 + FILE + NOVEL New - False + True + SCENE + 0 + 0 + 0 + 0 + + + Scene 3.2 + FILE + NOVEL + New + True + SCENE + 0 + 0 + 0 + 0 + + + Scene 3.3 + FILE + NOVEL + New + True + SCENE + 0 + 0 + 0 + 0 diff --git a/tests/reference/coreProject_3_nwProject.nwx b/tests/reference/coreProject_3_nwProject.nwx index 66488434..11d007aa 100644 --- a/tests/reference/coreProject_3_nwProject.nwx +++ b/tests/reference/coreProject_3_nwProject.nwx @@ -1,9 +1,11 @@ - + - New Project - - 2 + Test Custom + Test Novel + Jane Doe + John Doh + 1 1 0 @@ -38,7 +40,7 @@ Main - + Novel ROOT @@ -61,13 +63,34 @@ False - World + Locations ROOT WORLD New False - + + Timeline + ROOT + TIMELINE + New + False + + + Objects + ROOT + OBJECT + New + False + + + Entity + ROOT + ENTITY + New + False + + Title Page FILE NOVEL @@ -79,27 +102,8 @@ 0 0 - - New Chapter - FOLDER - NOVEL - New - False - - - New Chapter - FILE - NOVEL - New - True - CHAPTER - 0 - 0 - 0 - 0 - - - New Scene + + Scene 1 FILE NOVEL New @@ -110,8 +114,8 @@ 0 0 - - Hello + + Scene 2 FILE NOVEL New @@ -122,13 +126,49 @@ 0 0 - - Jane + + Scene 3 FILE - CHARACTER + NOVEL New True - NOTE + SCENE + 0 + 0 + 0 + 0 + + + Scene 4 + FILE + NOVEL + New + True + SCENE + 0 + 0 + 0 + 0 + + + Scene 5 + FILE + NOVEL + New + True + SCENE + 0 + 0 + 0 + 0 + + + Scene 6 + FILE + NOVEL + New + True + SCENE 0 0 0 diff --git a/tests/reference/coreProject_4_nwProject.nwx b/tests/reference/coreProject_4_nwProject.nwx index fc7e7ab2..9ea0617f 100644 --- a/tests/reference/coreProject_4_nwProject.nwx +++ b/tests/reference/coreProject_4_nwProject.nwx @@ -1,11 +1,9 @@ - Test Custom - Test Novel - Jane Doe - John Doh - 1 + New Project + + 2 1 0 @@ -40,7 +38,7 @@ Main - + Novel ROOT @@ -63,34 +61,13 @@ False - Locations + World ROOT WORLD New False - - Timeline - ROOT - TIMELINE - New - False - - - Objects - ROOT - OBJECT - New - False - - - Entity - ROOT - ENTITY - New - False - - + Title Page FILE NOVEL @@ -102,15 +79,15 @@ 0 0 - - Chapter 1 + + New Chapter FOLDER NOVEL New False - - Chapter 1 + + New Chapter FILE NOVEL New @@ -121,8 +98,8 @@ 0 0 - - Scene 1.1 + + New Scene FILE NOVEL New @@ -133,139 +110,33 @@ 0 0 - - Scene 1.2 - FILE - NOVEL - New - True - SCENE - 0 - 0 - 0 - 0 - - - Scene 1.3 - FILE - NOVEL - New - True - SCENE - 0 - 0 - 0 - 0 - - - Chapter 2 - FOLDER - NOVEL + + Timeline + ROOT + TIMELINE New False - - Chapter 2 - FILE - NOVEL - New - True - CHAPTER - 0 - 0 - 0 - 0 - - - Scene 2.1 - FILE - NOVEL - New - True - SCENE - 0 - 0 - 0 - 0 - - - Scene 2.2 - FILE - NOVEL - New - True - SCENE - 0 - 0 - 0 - 0 - - - Scene 2.3 - FILE - NOVEL - New - True - SCENE - 0 - 0 - 0 - 0 - - - Chapter 3 - FOLDER - NOVEL + + Object + ROOT + OBJECT New False - - Chapter 3 - FILE - NOVEL + + Custom1 + ROOT + CUSTOM New - True - CHAPTER - 0 - 0 - 0 - 0 + False - - Scene 3.1 - FILE - NOVEL + + Custom2 + ROOT + CUSTOM New - True - SCENE - 0 - 0 - 0 - 0 - - - Scene 3.2 - FILE - NOVEL - New - True - SCENE - 0 - 0 - 0 - 0 - - - Scene 3.3 - FILE - NOVEL - New - True - SCENE - 0 - 0 - 0 - 0 + False diff --git a/tests/reference/coreProject_5_nwProject.nwx b/tests/reference/coreProject_5_nwProject.nwx index 11d007aa..66488434 100644 --- a/tests/reference/coreProject_5_nwProject.nwx +++ b/tests/reference/coreProject_5_nwProject.nwx @@ -1,11 +1,9 @@ - + - Test Custom - Test Novel - Jane Doe - John Doh - 1 + New Project + + 2 1 0 @@ -40,7 +38,7 @@ Main - + Novel ROOT @@ -63,34 +61,13 @@ False - Locations + World ROOT WORLD New False - - Timeline - ROOT - TIMELINE - New - False - - - Objects - ROOT - OBJECT - New - False - - - Entity - ROOT - ENTITY - New - False - - + Title Page FILE NOVEL @@ -102,8 +79,27 @@ 0 0 - - Scene 1 + + New Chapter + FOLDER + NOVEL + New + False + + + New Chapter + FILE + NOVEL + New + True + CHAPTER + 0 + 0 + 0 + 0 + + + New Scene FILE NOVEL New @@ -114,8 +110,8 @@ 0 0 - - Scene 2 + + Hello FILE NOVEL New @@ -126,49 +122,13 @@ 0 0 - - Scene 3 + + Jane FILE - NOVEL + CHARACTER New True - SCENE - 0 - 0 - 0 - 0 - - - Scene 4 - FILE - NOVEL - New - True - SCENE - 0 - 0 - 0 - 0 - - - Scene 5 - FILE - NOVEL - New - True - SCENE - 0 - 0 - 0 - 0 - - - Scene 6 - FILE - NOVEL - New - True - SCENE + NOTE 0 0 0 diff --git a/tests/test_core_project.py b/tests/test_core_project.py index 6cf20033..869603fe 100644 --- a/tests/test_core_project.py +++ b/tests/test_core_project.py @@ -7,15 +7,18 @@ import os from shutil import copyfile from zipfile import ZipFile +from lxml import etree -from tools import cmpFiles +from tools import cmpFiles, writeFile, readFile +from dummy import causeOSError from nw.core.project import NWProject from nw.constants import nwItemClass, nwItemType, nwItemLayout, nwFiles @pytest.mark.core -def testCoreProject_NewOpenSave(fncDir, outDir, refDir, tmpDir, dummyGUI): - """Test that a basic project can be created, opened and saved. +def testCoreProject_NewMinimal(fncDir, outDir, refDir, tmpDir, dummyGUI): + """Create a new project from a project wizard dictionary. With + default setting, creating a Minimal project. """ projFile = os.path.join(fncDir, "nwProject.nwx") testFile = os.path.join(outDir, "coreProject_1_nwProject.nwx") @@ -29,7 +32,6 @@ def testCoreProject_NewOpenSave(fncDir, outDir, refDir, tmpDir, dummyGUI): # Try again with a proper path assert theProject.newProject({"projPath": fncDir}) - assert theProject.setProjectPath(fncDir) assert theProject.saveProject() assert theProject.closeProject() @@ -59,72 +61,7 @@ def testCoreProject_NewOpenSave(fncDir, outDir, refDir, tmpDir, dummyGUI): copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [2, 6, 7, 8]) -# END Test testCoreProject_NewOpenSave - -@pytest.mark.core -def testCoreProject_NewRoot(fncDir, outDir, refDir, dummyGUI): - """Check that new root folders can be added to the project. - """ - projFile = os.path.join(fncDir, "nwProject.nwx") - testFile = os.path.join(outDir, "coreProject_2_nwProject.nwx") - compFile = os.path.join(refDir, "coreProject_2_nwProject.nwx") - - theProject = NWProject(dummyGUI) - theProject.projTree.setSeed(42) - - assert theProject.newProject({"projPath": fncDir}) - assert theProject.setProjectPath(fncDir) - assert theProject.saveProject() - assert theProject.closeProject() - assert theProject.openProject(projFile) - - assert isinstance(theProject.newRoot("Novel", nwItemClass.NOVEL), type(None)) - assert isinstance(theProject.newRoot("Plot", nwItemClass.PLOT), type(None)) - assert isinstance(theProject.newRoot("Character", nwItemClass.CHARACTER), type(None)) - assert isinstance(theProject.newRoot("World", nwItemClass.WORLD), type(None)) - assert isinstance(theProject.newRoot("Timeline", nwItemClass.TIMELINE), str) - assert isinstance(theProject.newRoot("Object", nwItemClass.OBJECT), str) - assert isinstance(theProject.newRoot("Custom1", nwItemClass.CUSTOM), str) - assert isinstance(theProject.newRoot("Custom2", nwItemClass.CUSTOM), str) - - assert theProject.projChanged - assert theProject.saveProject() - assert theProject.closeProject() - - copyfile(projFile, testFile) - assert cmpFiles(testFile, compFile, [2, 6, 7, 8]) - assert not theProject.projChanged - -# END Test testCoreProject_NewRoot - -@pytest.mark.core -def testCoreProject_NewFile(fncDir, outDir, refDir, dummyGUI): - """Check that new files can be added to the project. - """ - projFile = os.path.join(fncDir, "nwProject.nwx") - testFile = os.path.join(outDir, "coreProject_3_nwProject.nwx") - compFile = os.path.join(refDir, "coreProject_3_nwProject.nwx") - - theProject = NWProject(dummyGUI) - theProject.projTree.setSeed(42) - - assert theProject.newProject({"projPath": fncDir}) - assert theProject.setProjectPath(fncDir) - assert theProject.saveProject() - assert theProject.closeProject() - assert theProject.openProject(projFile) - - assert isinstance(theProject.newFile("Hello", nwItemClass.NOVEL, "31489056e0916"), str) - assert isinstance(theProject.newFile("Jane", nwItemClass.CHARACTER, "71ee45a3c0db9"), str) - assert theProject.projChanged - assert theProject.saveProject() - assert theProject.closeProject() - - copyfile(projFile, testFile) - assert cmpFiles(testFile, compFile, [2, 6, 7, 8]) - assert not theProject.projChanged - -# END Test testCoreProject_NewFile +# END Test testCoreProject_NewMinimal @pytest.mark.core def testCoreProject_NewCustomA(fncDir, outDir, refDir, dummyGUI): @@ -132,8 +69,8 @@ def testCoreProject_NewCustomA(fncDir, outDir, refDir, dummyGUI): Custom type with chapters and scenes. """ projFile = os.path.join(fncDir, "nwProject.nwx") - testFile = os.path.join(outDir, "coreProject_4_nwProject.nwx") - compFile = os.path.join(refDir, "coreProject_4_nwProject.nwx") + testFile = os.path.join(outDir, "coreProject_2_nwProject.nwx") + compFile = os.path.join(refDir, "coreProject_2_nwProject.nwx") projData = { "projName": "Test Custom", @@ -173,8 +110,8 @@ def testCoreProject_NewCustomB(fncDir, outDir, refDir, dummyGUI): Custom type without chapters, but with scenes. """ projFile = os.path.join(fncDir, "nwProject.nwx") - testFile = os.path.join(outDir, "coreProject_5_nwProject.nwx") - compFile = os.path.join(refDir, "coreProject_5_nwProject.nwx") + testFile = os.path.join(outDir, "coreProject_3_nwProject.nwx") + compFile = os.path.join(refDir, "coreProject_3_nwProject.nwx") projData = { "projName": "Test Custom", @@ -296,7 +233,418 @@ def testCoreProject_NewSampleB(monkeypatch, fncDir, tmpConf, dummyGUI, tmpDir): # END Test testCoreProject_NewSampleB @pytest.mark.core -def testCoreProject_Methods(monkeypatch, nwMinimal, dummyGUI): +def testCoreProject_NewRoot(fncDir, outDir, refDir, dummyGUI): + """Check that new root folders can be added to the project. + """ + projFile = os.path.join(fncDir, "nwProject.nwx") + testFile = os.path.join(outDir, "coreProject_4_nwProject.nwx") + compFile = os.path.join(refDir, "coreProject_4_nwProject.nwx") + + theProject = NWProject(dummyGUI) + theProject.projTree.setSeed(42) + + assert theProject.newProject({"projPath": fncDir}) + assert theProject.setProjectPath(fncDir) + assert theProject.saveProject() + assert theProject.closeProject() + assert theProject.openProject(projFile) + + assert isinstance(theProject.newRoot("Novel", nwItemClass.NOVEL), type(None)) + assert isinstance(theProject.newRoot("Plot", nwItemClass.PLOT), type(None)) + assert isinstance(theProject.newRoot("Character", nwItemClass.CHARACTER), type(None)) + assert isinstance(theProject.newRoot("World", nwItemClass.WORLD), type(None)) + assert isinstance(theProject.newRoot("Timeline", nwItemClass.TIMELINE), str) + assert isinstance(theProject.newRoot("Object", nwItemClass.OBJECT), str) + assert isinstance(theProject.newRoot("Custom1", nwItemClass.CUSTOM), str) + assert isinstance(theProject.newRoot("Custom2", nwItemClass.CUSTOM), str) + + assert theProject.projChanged + assert theProject.saveProject() + assert theProject.closeProject() + + copyfile(projFile, testFile) + assert cmpFiles(testFile, compFile, [2, 6, 7, 8]) + assert not theProject.projChanged + +# END Test testCoreProject_NewRoot + +@pytest.mark.core +def testCoreProject_NewFile(fncDir, outDir, refDir, dummyGUI): + """Check that new files can be added to the project. + """ + projFile = os.path.join(fncDir, "nwProject.nwx") + testFile = os.path.join(outDir, "coreProject_5_nwProject.nwx") + compFile = os.path.join(refDir, "coreProject_5_nwProject.nwx") + + theProject = NWProject(dummyGUI) + theProject.projTree.setSeed(42) + + assert theProject.newProject({"projPath": fncDir}) + assert theProject.setProjectPath(fncDir) + assert theProject.saveProject() + assert theProject.closeProject() + assert theProject.openProject(projFile) + + assert isinstance(theProject.newFile("Hello", nwItemClass.NOVEL, "31489056e0916"), str) + assert isinstance(theProject.newFile("Jane", nwItemClass.CHARACTER, "71ee45a3c0db9"), str) + assert theProject.projChanged + assert theProject.saveProject() + assert theProject.closeProject() + + copyfile(projFile, testFile) + assert cmpFiles(testFile, compFile, [2, 6, 7, 8]) + assert not theProject.projChanged + +# END Test testCoreProject_NewFile + +@pytest.mark.core +def testCoreProject_Open(monkeypatch, nwMinimal, dummyGUI): + """Test opening a project. + """ + theProject = NWProject(dummyGUI) + + # Rename the project file to check handling + rName = os.path.join(nwMinimal, nwFiles.PROJ_FILE) + wName = os.path.join(nwMinimal, nwFiles.PROJ_FILE+"_sdfghj") + os.rename(rName, wName) + assert theProject.openProject(nwMinimal) is False + os.rename(wName, rName) + + # Fail on folder structure check + monkeypatch.setattr("os.mkdir", causeOSError) + assert theProject.openProject(nwMinimal) is False + monkeypatch.undo() + + # Fail on lock file + theProject.setProjectPath(nwMinimal) + assert theProject._writeLockFile() + assert theProject.openProject(nwMinimal) is False + + # Fail to read lockfile (which still opens the project) + monkeypatch.setattr("builtins.open", causeOSError) + assert theProject.openProject(nwMinimal) is True + monkeypatch.undo() + assert theProject.closeProject() + + # Force open with lockfile + theProject.setProjectPath(nwMinimal) + assert theProject._writeLockFile() + assert theProject.openProject(nwMinimal, overrideLock=True) is True + assert theProject.closeProject() + + # Make a junk XML file + oName = os.path.join(nwMinimal, nwFiles.PROJ_FILE[:-3]+"orig") + bName = os.path.join(nwMinimal, nwFiles.PROJ_FILE[:-3]+"bak") + os.rename(rName, oName) + writeFile(rName, "dummy") + assert theProject.openProject(nwMinimal) is False + + # Also write a jun XML backup file + writeFile(bName, "dummy") + assert theProject.openProject(nwMinimal) is False + + # Wrong root item + writeFile(rName, "\n") + assert theProject.openProject(nwMinimal) is False + + # Wrong file version + writeFile(rName, ( + "\n" + "\n" + "\n" + )) + dummyGUI.askResponse = False + assert theProject.openProject(nwMinimal) is False + dummyGUI.undo() + + # Future file version + writeFile(rName, ( + "\n" + "\n" + "\n" + )) + assert theProject.openProject(nwMinimal) is False + + # Larger hex version + writeFile(rName, ( + "\n" + "\n" + "\n" + )) + dummyGUI.askResponse = False + assert theProject.openProject(nwMinimal) is False + dummyGUI.undo() + + # Test skipping XML entries + writeFile(rName, ( + "\n" + "\n" + "\n" + "\n" + "\n" + )) + assert theProject.openProject(nwMinimal) is True + assert theProject.closeProject() + + # Test deprecated XML entries + writeFile(rName, ( + "\n" + "\n" + "\n" + "\n" + "B\n" + "\n" + "\n" + "\n" + )) + assert theProject.openProject(nwMinimal) is True + assert theProject.autoReplace == {"A": "B"} + assert theProject.closeProject() + + # Clean up XML files + os.unlink(rName) + os.unlink(bName) + os.rename(oName, rName) + + # Add some legacy stuff that cannot be removed + writeFile(os.path.join(nwMinimal, "junk"), "dummy") + os.mkdir(os.path.join(nwMinimal, "data_0")) + writeFile(os.path.join(nwMinimal, "data_0", "junk"), "dummy") + dummyGUI.clear() + assert theProject.openProject(nwMinimal) is True + assert "data_0" in dummyGUI.lastAlert + assert theProject.closeProject() + +# END Test testCoreProject_Open + +@pytest.mark.core +def testCoreProject_Save(monkeypatch, nwMinimal, dummyGUI, refDir): + """Test saving a project. + """ + theProject = NWProject(dummyGUI) + testFile = os.path.join(nwMinimal, "nwProject.nwx") + compFile = os.path.join(refDir, os.path.pardir, "minimal", "nwProject.nwx") + + # Nothing to save + assert theProject.saveProject() is False + + # Open test project + assert theProject.openProject(nwMinimal) + + # Fail on folder structure check + monkeypatch.setattr("os.path.isdir", lambda *args: False) + assert theProject.saveProject() is False + monkeypatch.undo() + + # Fail on open file + monkeypatch.setattr("builtins.open", causeOSError) + assert theProject.saveProject() is False + monkeypatch.undo() + + # Successful save + saveCount = theProject.saveCount + autoCount = theProject.autoCount + assert theProject.saveProject() is True + assert theProject.saveCount == saveCount + 1 + assert theProject.autoCount == autoCount + assert cmpFiles(testFile, compFile, [2, 6, 7, 8, 9]) + + # Successful autosave + saveCount = theProject.saveCount + autoCount = theProject.autoCount + assert theProject.saveProject(autoSave=True) is True + assert theProject.saveCount == saveCount + assert theProject.autoCount == autoCount + 1 + assert cmpFiles(testFile, compFile, [2, 6, 7, 8, 9]) + + # Close test project + assert theProject.closeProject() + +# END Test testCoreProject_Save + +@pytest.mark.core +def testCoreProject_LockFile(monkeypatch, fncDir, dummyGUI): + """Test lock file functions for the project folder. + """ + theProject = NWProject(dummyGUI) + + lockFile = os.path.join(fncDir, nwFiles.PROJ_LOCK) + + # No project + assert theProject._writeLockFile() is False + assert theProject._readLockFile() == ["ERROR"] + assert theProject._clearLockFile() is False + + theProject.projPath = fncDir + theProject.mainConf.hostName = "TestHost" + theProject.mainConf.osType = "TestOS" + theProject.mainConf.kernelVer = "1.0" + + # Block open + monkeypatch.setattr("builtins.open", causeOSError) + assert theProject._writeLockFile() is False + monkeypatch.undo() + + # Write lock file + monkeypatch.setattr("nw.core.project.time", lambda: 123.4) + assert theProject._writeLockFile() is True + monkeypatch.undo() + assert readFile(lockFile) == "TestHost\nTestOS\n1.0\n123\n" + + # Block open + monkeypatch.setattr("builtins.open", causeOSError) + assert theProject._readLockFile() == ["ERROR"] + monkeypatch.undo() + + # Read lock file + assert theProject._readLockFile() == ["TestHost", "TestOS", "1.0", "123"] + + # Block unlink + monkeypatch.setattr("os.unlink", causeOSError) + assert os.path.isfile(lockFile) + assert theProject._clearLockFile() is False + assert os.path.isfile(lockFile) + monkeypatch.undo() + + # Clear file + assert os.path.isfile(lockFile) + assert theProject._clearLockFile() is True + assert not os.path.isfile(lockFile) + + # Read again, no file + assert theProject._readLockFile() == [] + + # Read an invalid lock file + writeFile(lockFile, "A\nB") + assert theProject._readLockFile() == ["ERROR"] + assert theProject._clearLockFile() is True + +# END Test testCoreProject_LockFile + +@pytest.mark.core +def testCoreProject_Helpers(monkeypatch, fncDir, dummyGUI): + """Test helper functions for the project folder. + """ + theProject = NWProject(dummyGUI) + + # No path + assert theProject.ensureFolderStructure() is False + + # Set the correct dir + theProject.projPath = fncDir + + # Block user's home folder + monkeypatch.setattr("os.path.expanduser", lambda *args, **kwargs: fncDir) + assert theProject.ensureFolderStructure() is False + monkeypatch.undo() + + # Create a file to block meta folder + metaDir = os.path.join(fncDir, "meta") + writeFile(metaDir, "dummy") + assert theProject.ensureFolderStructure() is False + os.unlink(metaDir) + + # Create a file to block cache folder + cacheDir = os.path.join(fncDir, "cache") + writeFile(cacheDir, "dummy") + assert theProject.ensureFolderStructure() is False + os.unlink(cacheDir) + + # Create a file to block content folder + contentDir = os.path.join(fncDir, "content") + writeFile(contentDir, "dummy") + assert theProject.ensureFolderStructure() is False + os.unlink(contentDir) + + # Now, do it right + assert theProject.ensureFolderStructure() is True + assert os.path.isdir(metaDir) + assert os.path.isdir(cacheDir) + assert os.path.isdir(contentDir) + +# END Test testCoreProject_Helpers + +@pytest.mark.core +def testCoreProject_AccessItems(nwMinimal, dummyGUI): + """Test helper functions for the project folder. + """ + theProject = NWProject(dummyGUI) + theProject.openProject(nwMinimal) + + # Move Novel ROOT to after its files + oldOrder = [ + "a508bb932959c", # ROOT: Novel + "a35baf2e93843", # FILE: Title Page + "a6d311a93600a", # FOLDER: New Chapter + "f5ab3e30151e1", # FILE: New Chapter + "8c659a11cd429", # FILE: New Scene + "7695ce551d265", # ROOT: Plot + "afb3043c7b2b3", # ROOT: Characters + "9d5247ab588e0", # ROOT: World + ] + newOrder = [ + "a35baf2e93843", # FILE: Title Page + "f5ab3e30151e1", # FILE: New Chapter + "8c659a11cd429", # FILE: New Scene + "a6d311a93600a", # FOLDER: New Chapter + "a508bb932959c", # ROOT: Novel + "7695ce551d265", # ROOT: Plot + "afb3043c7b2b3", # ROOT: Characters + "9d5247ab588e0", # ROOT: World + ] + assert theProject.projTree.handles() == oldOrder + assert theProject.setTreeOrder(newOrder) + assert theProject.projTree.handles() == newOrder + + # Add a non-existing item + theProject.projTree._treeOrder.append("01234567789abc") + + # Add an item with a non-existent parent + nHandle = theProject.newFile("Test File", nwItemClass.NOVEL, "a6d311a93600a") + theProject.projTree[nHandle].setParent("cba9876543210") + assert theProject.projTree[nHandle].itemParent == "cba9876543210" + + retOrder = [] + for tItem in theProject.getProjectItems(): + retOrder.append(tItem.itemHandle) + + assert retOrder == [ + "a508bb932959c", # ROOT: Novel + "7695ce551d265", # ROOT: Plot + "afb3043c7b2b3", # ROOT: Characters + "9d5247ab588e0", # ROOT: World + nHandle, # FILE: Test File + "a35baf2e93843", # FILE: Title Page + "a6d311a93600a", # FOLDER: New Chapter + "f5ab3e30151e1", # FILE: New Chapter + "8c659a11cd429", # FILE: New Scene + ] + assert theProject.projTree[nHandle].itemParent is None + +# END Test testCoreProject_AccessItems + +@pytest.mark.core +def testCoreProject_Methods(monkeypatch, nwMinimal, dummyGUI, tmpDir): """Test other project class methods and functions. """ theProject = NWProject(dummyGUI) @@ -317,13 +665,13 @@ def testCoreProject_Methods(monkeypatch, nwMinimal, dummyGUI): assert theProject.setProjectPath(projPath, newProject=True) # Make os.mkdir fail - def altMkdir(*args): - raise Exception("Oops!") - - monkeypatch.setattr("os.mkdir", altMkdir) + monkeypatch.setattr("os.mkdir", causeOSError) projPath = os.path.join(nwMinimal, "dummy2") assert not theProject.setProjectPath(projPath, newProject=True) + # Set back + assert theProject.setProjectPath(nwMinimal) + # Project Name assert theProject.setProjectName(" A Name ") assert theProject.projName == "A Name" @@ -337,6 +685,191 @@ def testCoreProject_Methods(monkeypatch, nwMinimal, dummyGUI): assert theProject.setBookAuthors(" Jane Doe \n John Doh \n ") assert theProject.bookAuthors == ["Jane Doe", "John Doh"] + # Trash folder + # Should create on first call, and just returned on later calls + assert theProject.projTree["73475cb40a568"] is None + assert theProject.trashFolder() == "73475cb40a568" + assert theProject.trashFolder() == "73475cb40a568" + + # Project backup + assert theProject.doBackup is True + assert theProject.setProjBackup(False) + assert theProject.doBackup is False + + assert not theProject.setProjBackup(True) + theProject.mainConf.backupPath = tmpDir + assert theProject.setProjBackup(True) + + assert theProject.setProjectName("") + assert not theProject.setProjBackup(True) + assert theProject.setProjectName("A Name") + assert theProject.setProjBackup(True) + + # Spell check + theProject.projChanged = False + assert theProject.setSpellCheck(True) + assert not theProject.setSpellCheck(False) + assert theProject.projChanged + + # Spell language + theProject.projChanged = False + assert theProject.setSpellLang(None) + assert theProject.projLang is None + assert theProject.setSpellLang("None") + assert theProject.projLang is None + assert theProject.setSpellLang("en_GB") + assert theProject.projLang == "en_GB" + assert theProject.projChanged + + # Automatic outline update + theProject.projChanged = False + assert theProject.setAutoOutline(True) + assert not theProject.setAutoOutline(False) + assert theProject.projChanged + + # Last edited + theProject.projChanged = False + assert theProject.setLastEdited("0123456789abc") + assert theProject.lastEdited == "0123456789abc" + assert theProject.projChanged + + # Last viewed + theProject.projChanged = False + assert theProject.setLastViewed("0123456789abc") + assert theProject.lastViewed == "0123456789abc" + assert theProject.projChanged + + # Autoreplace + theProject.projChanged = False + assert theProject.setAutoReplace({"A": "B", "C": "D"}) + assert theProject.autoReplace == {"A": "B", "C": "D"} + assert theProject.projChanged + + # Change project tree order + oldOrder = [ + "a508bb932959c", "a35baf2e93843", "a6d311a93600a", + "f5ab3e30151e1", "8c659a11cd429", "7695ce551d265", + "afb3043c7b2b3", "9d5247ab588e0", "73475cb40a568", + ] + newOrder = [ + "f5ab3e30151e1", "8c659a11cd429", "7695ce551d265", + "a508bb932959c", "a35baf2e93843", "a6d311a93600a", + "afb3043c7b2b3", "9d5247ab588e0", + ] + assert theProject.projTree.handles() == oldOrder + assert theProject.setTreeOrder(newOrder) + assert theProject.projTree.handles() == newOrder + assert theProject.setTreeOrder(oldOrder) + assert theProject.projTree.handles() == oldOrder + + # Change status + theProject.projTree["a35baf2e93843"].setStatus("Finished") + theProject.projTree["a6d311a93600a"].setStatus("Draft") + theProject.projTree["f5ab3e30151e1"].setStatus("Note") + theProject.projTree["8c659a11cd429"].setStatus("Finished") + newList = [ + ("New", 1, 1, 1, "New"), + ("Draft", 2, 2, 2, "Note"), # These are swapped + ("Note", 3, 3, 3, "Draft"), # These are swapped + ("Edited", 4, 4, 4, "Finished"), # Renamed + ("Finished", 5, 5, 5, None), # New, with reused name + ] + assert theProject.setStatusColours(newList) + assert theProject.statusItems._theLabels == [ + "New", "Draft", "Note", "Edited", "Finished" + ] + assert theProject.statusItems._theColours == [ + (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5) + ] + assert theProject.projTree["a35baf2e93843"].itemStatus == "Edited" # Renamed + assert theProject.projTree["a6d311a93600a"].itemStatus == "Note" # Swapped + assert theProject.projTree["f5ab3e30151e1"].itemStatus == "Draft" # Swapped + assert theProject.projTree["8c659a11cd429"].itemStatus == "Edited" # Renamed + + # Change importance + fHandle = theProject.newFile("Jane Doe", nwItemClass.CHARACTER, "afb3043c7b2b3") + theProject.projTree[fHandle].setStatus("Main") + newList = [ + ("New", 1, 1, 1, "New"), + ("Minor", 2, 2, 2, "Minor"), + ("Major", 3, 3, 3, "Major"), + ("Min", 4, 4, 4, "Main"), + ("Max", 5, 5, 5, None), + ] + assert theProject.setImportColours(newList) + assert theProject.importItems._theLabels == [ + "New", "Minor", "Major", "Min", "Max" + ] + assert theProject.importItems._theColours == [ + (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5) + ] + assert theProject.projTree[fHandle].itemStatus == "Min" + + # Check status counts + assert theProject.statusItems._theCounts == [0, 0, 0, 0, 0] + assert theProject.importItems._theCounts == [0, 0, 0, 0, 0] + theProject.countStatus() + assert theProject.statusItems._theCounts == [1, 1, 1, 2, 0] + assert theProject.importItems._theCounts == [3, 0, 0, 1, 0] + + # Check word counts + theProject.currWCount = 200 + theProject.lastWCount = 100 + assert theProject.getSessionWordCount() == 100 + + # Session stats + monkeypatch.setattr("os.path.isdir", lambda *args, **kwargs: False) + assert not theProject._appendSessionStats() + monkeypatch.undo() + + # Block open + monkeypatch.setattr("builtins.open", causeOSError) + assert not theProject._appendSessionStats() + monkeypatch.undo() + + # Write entry + assert theProject.projMeta == os.path.join(nwMinimal, "meta") + statsFile = os.path.join(theProject.projMeta, nwFiles.SESS_STATS) + + theProject.projOpened = 1600002000 + theProject.novelWCount = 200 + theProject.notesWCount = 100 + + monkeypatch.setattr("nw.core.project.time", lambda: 1600005600) + assert theProject._appendSessionStats() + monkeypatch.undo() + + assert readFile(statsFile) == ( + "# Offset 100\n" + "# Start Time End Time Novel Notes\n" + "2020-09-13 13:00:00 2020-09-13 14:00:00 200 100\n" + ) + + # Pack XML Value + xElem = etree.Element("element") + theProject._packProjectValue(xElem, "A", "B", allowNone=False) + assert etree.tostring(xElem, pretty_print=False, encoding="utf-8") == ( + b"B" + ) + + xElem = etree.Element("element") + theProject._packProjectValue(xElem, "A", "", allowNone=False) + assert etree.tostring(xElem, pretty_print=False, encoding="utf-8") == ( + b"" + ) + + # Pack XML Key/Value + xElem = etree.Element("element") + theProject._packProjectKeyValue(xElem, "item", {"A": "B", "C": "D"}) + assert etree.tostring(xElem, pretty_print=False, encoding="utf-8") == ( + b"" + b"" + b"B" + b"D" + b"" + b"" + ) + # END Test testCoreProject_Methods @pytest.mark.core @@ -347,6 +880,7 @@ def testCoreProject_OrphanedFiles(dummyGUI, nwLipsum): the meta line at the top of the document file. """ theProject = NWProject(dummyGUI) + assert theProject.openProject(nwLipsum) assert theProject.projTree["636b6aa9b697b"] is None assert theProject.closeProject() @@ -408,6 +942,10 @@ def testCoreProject_OrphanedFiles(dummyGUI, nwLipsum): assert theProject.saveProject(nwLipsum) assert theProject.closeProject() + # Finally, check that the orphaned files function returns + # if no project is open and no path is set + assert not theProject._scanProjectFolder() + # END Test testCoreProject_OrphanedFiles @pytest.mark.core @@ -418,7 +956,6 @@ def testCoreProject_OldFormat(dummyGUI, nwOldProj): contained in a single 'content' folder. """ theProject = NWProject(dummyGUI) - theProject.mainConf.showGUI = False # Create dummy files for known legacy files deleteFiles = [ @@ -451,8 +988,7 @@ def testCoreProject_OldFormat(dummyGUI, nwOldProj): # Create dummy files os.mkdir(os.path.join(nwOldProj, "cache")) for aFile in deleteFiles: - with open(aFile, mode="w+", encoding="utf8") as outFile: - outFile.write("Hi") + writeFile(aFile, "Hi") for aFile in deleteFiles: assert os.path.isfile(aFile) @@ -503,7 +1039,112 @@ def testCoreProject_OldFormat(dummyGUI, nwOldProj): # END Test testCoreProject_OldFormat @pytest.mark.core -def testCoreProject_Backup(dummyGUI, nwMinimal, tmpDir): +def testCoreProject_LegacyData(monkeypatch, dummyGUI, fncDir): + """Test the functins that handle legacy data folders and structure + with additional tests of failure handling. + """ + theProject = NWProject(dummyGUI) + theProject.setProjectPath(fncDir) + + # assert theProject.newProject({"projPath": fncDir}) + # assert theProject.saveProject() + # assert theProject.closeProject() + + # Check behaviour of deprecated files function on OSError + tstFile = os.path.join(fncDir, "ToC.json") + writeFile(tstFile, "dummy") + assert os.path.isfile(tstFile) + + monkeypatch.setattr("os.unlink", causeOSError) + assert not theProject._deprecatedFiles() + monkeypatch.undo() + + assert theProject._deprecatedFiles() + assert not os.path.isfile(tstFile) + + # Check processing non-folders + tstFile = os.path.join(fncDir, "data_0") + writeFile(tstFile, "dummy") + assert os.path.isfile(tstFile) + + errList = [] + errList = theProject._legacyDataFolder(tstFile, errList) + assert len(errList) > 0 + + # Move folder in data folder, shouldn't be there + tstData = os.path.join(fncDir, "data_1") + errItem = os.path.join(fncDir, "data_1", "stuff") + os.mkdir(tstData) + os.mkdir(errItem) + assert os.path.isdir(tstData) + assert os.path.isdir(errItem) + + # This causes a failure to create the 'junk' folder + monkeypatch.setattr("os.mkdir", causeOSError) + errList = [] + errList = theProject._legacyDataFolder(tstData, errList) + assert len(errList) > 0 + monkeypatch.undo() + + # This causes a failure to move 'stuff' to 'junk' + monkeypatch.setattr("os.rename", causeOSError) + errList = [] + errList = theProject._legacyDataFolder(tstData, errList) + assert len(errList) > 0 + monkeypatch.undo() + + # This should be successful + errList = [] + errList = theProject._legacyDataFolder(tstData, errList) + assert len(errList) == 0 + assert os.path.isdir(os.path.join(fncDir, "junk", "stuff")) + + # Check renaming/deleting of old document files + tstData = os.path.join(fncDir, "data_2") + tstDoc1m = os.path.join(tstData, "000000000001_main.nwd") + tstDoc1b = os.path.join(tstData, "000000000001_main.bak") + tstDoc2m = os.path.join(tstData, "000000000002_main.nwd") + tstDoc2b = os.path.join(tstData, "000000000002_main.bak") + tstDoc3m = os.path.join(tstData, "tooshort003_main.nwd") + tstDoc3b = os.path.join(tstData, "tooshort003_main.bak") + + os.mkdir(tstData) + writeFile(tstDoc1m, "dummy") + writeFile(tstDoc1b, "dummy") + writeFile(tstDoc2m, "dummy") + writeFile(tstDoc2b, "dummy") + writeFile(tstDoc3m, "dummy") + writeFile(tstDoc3b, "dummy") + + # Make the above fail + monkeypatch.setattr("os.rename", causeOSError) + monkeypatch.setattr("os.unlink", causeOSError) + errList = [] + errList = theProject._legacyDataFolder(tstData, errList) + assert len(errList) > 0 + assert os.path.isfile(tstDoc1m) + assert os.path.isfile(tstDoc1b) + assert os.path.isfile(tstDoc2m) + assert os.path.isfile(tstDoc2b) + assert os.path.isfile(tstDoc3m) + assert os.path.isfile(tstDoc3b) + monkeypatch.undo() + + # And succeed ... + errList = [] + errList = theProject._legacyDataFolder(tstData, errList) + assert len(errList) == 0 + + assert not os.path.isdir(tstData) + assert os.path.isfile(os.path.join(fncDir, "content", "2000000000001.nwd")) + assert os.path.isfile(os.path.join(fncDir, "content", "2000000000002.nwd")) + assert os.path.isfile(os.path.join(fncDir, "junk", "tooshort003_main.nwd")) + assert os.path.isfile(os.path.join(fncDir, "junk", "tooshort003_main.bak")) + +# END Test testCoreProject_LegacyData + +@pytest.mark.core +def testCoreProject_Backup(monkeypatch, dummyGUI, nwMinimal, tmpDir): """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 @@ -513,6 +1154,12 @@ def testCoreProject_Backup(dummyGUI, nwMinimal, tmpDir): assert theProject.openProject(nwMinimal) # Test faulty settings + + # No project + dummyGUI.hasProject = False + assert not theProject.zipIt(doNotify=False) + dummyGUI.hasProject = True + # Invalid path theProject.mainConf.backupPath = None assert not theProject.zipIt(doNotify=False) @@ -531,9 +1178,21 @@ def testCoreProject_Backup(dummyGUI, nwMinimal, tmpDir): theProject.mainConf.backupPath = nwMinimal assert not theProject.zipIt(doNotify=False) - # Test correct settings + # Set a valid folder theProject.mainConf.backupPath = tmpDir - assert theProject.zipIt(doNotify=False) + + # Can't make folder + monkeypatch.setattr("os.mkdir", causeOSError) + assert not theProject.zipIt(doNotify=False) + monkeypatch.undo() + + # Can't write archive + monkeypatch.setattr("shutil.make_archive", causeOSError) + assert not theProject.zipIt(doNotify=False) + monkeypatch.undo() + + # Test correct settings + assert theProject.zipIt(doNotify=True) theFiles = os.listdir(os.path.join(tmpDir, "Test Minimal")) assert len(theFiles) == 1 @@ -548,7 +1207,8 @@ def testCoreProject_Backup(dummyGUI, nwMinimal, tmpDir): # Check that the main project file was restored assert cmpFiles( - os.path.join(nwMinimal, "nwProject.nwx"), os.path.join(tmpDir, "extract", "nwProject.nwx") + os.path.join(nwMinimal, "nwProject.nwx"), + os.path.join(tmpDir, "extract", "nwProject.nwx") ) # END Test testCoreProject_Backup diff --git a/tests/test_core_tree.py b/tests/test_core_tree.py index f417fd6a..29c1ca95 100644 --- a/tests/test_core_tree.py +++ b/tests/test_core_tree.py @@ -10,7 +10,7 @@ from lxml import etree from nw.core.project import NWProject, NWItem, NWTree from nw.constants import nwItemClass, nwItemType, nwItemLayout, nwFiles -@pytest.fixture(scope="session") +@pytest.fixture(scope="function") def dummyItems(dummyGUI): """Create a list of dummy items. """ @@ -353,7 +353,7 @@ def testCoreTree_XMLPackUnpack(dummyGUI, dummyItems): b"True" b"" b"Chapter OneFILENOVELNone" - b"TrueUNNUMBERED300" + b"TrueCHAPTER300" b"5020" b"" b"Scene OneFILENOVELNone" @@ -425,7 +425,7 @@ def testCoreTree_ToCFile(monkeypatch, dummyGUI, dummyItems, tmpDir): "\n" "File Name Class Layout Document Label\n" "-------------------------------------------------------------\n" - f"{pathA} NOVEL UNNUMBERED Chapter One\n" + f"{pathA} NOVEL CHAPTER Chapter One\n" f"{pathB} NOVEL SCENE Scene One\n" f"{pathC} CHARACTER NOTE Jane Doe\n" )