From 494b94430ca2bdff24fb8ba3520687ec8bd60347 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 1 Nov 2022 18:31:03 +0100
Subject: [PATCH] Fix tests broken by xml rewrite
---
novelwriter/core/item.py | 16 +-
tests/test_core/test_core_item.py | 422 ++++++++++++---------------
tests/test_core/test_core_project.py | 312 +++++++-------------
tests/test_core/test_core_status.py | 87 +++---
4 files changed, 355 insertions(+), 482 deletions(-)
diff --git a/novelwriter/core/item.py b/novelwriter/core/item.py
index 5b7deabe..8a45fa35 100644
--- a/novelwriter/core/item.py
+++ b/novelwriter/core/item.py
@@ -190,7 +190,7 @@ class NWItem:
if "handle" in data:
self.setHandle(data["handle"])
else:
- logger.error("XML item entry does not have a handle")
+ logger.error("Item does not have a handle")
return False
self.setName(data.get("label", ""))
@@ -217,12 +217,14 @@ class NWItem:
self._parent = None # Root items cannot have a parent
if self._type != nwItemType.FILE:
- self._heading = "H0" # Only files have headers
- self._active = False # Can only be True for files
- self._charCount = 0 # Only set for files
- self._wordCount = 0 # Only set for files
- self._paraCount = 0 # Only set for files
- self._cursorPos = 0 # Only set for files
+ # Reset values that should only be set for files
+ self._layout = nwItemLayout.NO_LAYOUT
+ self._heading = "H0"
+ self._active = False
+ self._charCount = 0
+ self._wordCount = 0
+ self._paraCount = 0
+ self._cursorPos = 0
return True
diff --git a/tests/test_core/test_core_item.py b/tests/test_core/test_core_item.py
index 02fe3f8f..714d6d57 100644
--- a/tests/test_core/test_core_item.py
+++ b/tests/test_core/test_core_item.py
@@ -21,8 +21,6 @@ along with this program. If not, see .
import pytest
-from lxml import etree
-
from PyQt5.QtGui import QIcon
from tools import C, buildTestProject
@@ -497,257 +495,199 @@ def testCoreItem_ClassDefaults(mockGUI):
@pytest.mark.core
-@pytest.mark.skip
-def testCoreItem_XMLPackUnpack(mockGUI, caplog, mockRnd):
- """Test packing and unpacking XML objects for the NWItem class.
+def testCoreItem_PackUnpack(mockGUI, caplog, mockRnd):
+ """Test packing and unpacking entries for the NWItem class.
"""
theProject = NWProject(mockGUI)
- nwXML = etree.Element("novelWriterXML")
+ theProject.data.itemStatus.write(None, "New", (100, 100, 100))
+ theProject.data.itemImport.write(None, "New", (100, 100, 100))
- statusKeys = ["s000000", "s000001", "s000002", "s000003"]
- importKeys = ["i000004", "i000005", "i000006", "i000007"]
+ # Invalid
+ theItem = NWItem(theProject)
+ assert theItem.unpack({}) is False
# File
- # ====
-
theItem = NWItem(theProject)
- theItem.setHandle("0123456789abc")
- theItem.setParent("0123456789abc")
- theItem.setRoot("0123456789abc")
- theItem.setOrder(1)
- theItem.setName("A Name")
- theItem.setClass("NOVEL")
- theItem.setType("FILE")
- theItem.setImport(importKeys[3])
- theItem.setLayout("NOTE")
- theItem.setActive(False)
- theItem.setParaCount(3)
- theItem.setWordCount(5)
- theItem.setCharCount(7)
- theItem.setCursorPos(11)
+ assert theItem.unpack({
+ "label": "A File",
+ "handle": "0000000000003",
+ "parent": "0000000000002",
+ "root": "0000000000001",
+ "order": 1,
+ "type": "FILE",
+ "class": "NOVEL",
+ "layout": "DOCUMENT",
+ "expanded": True,
+ "status": None,
+ "import": None,
+ "heading": "H1",
+ "charCount": 100,
+ "wordCount": 20,
+ "paraCount": 2,
+ "cursorPos": 50,
+ "active": False,
+ }) is True
- # Pack
- xContent = etree.SubElement(nwXML, "content")
- theItem.packXML(xContent)
- assert etree.tostring(xContent, pretty_print=False, encoding="utf-8") == (
- b''
- b'- A Name
'
- b''
- ) % bytes(importKeys[3], encoding="utf8")
-
- # Unpack
- theItem = NWItem(theProject)
- assert theItem.unpackXML(xContent[0])
- assert theItem.itemHandle == "0123456789abc"
- assert theItem.itemParent == "0123456789abc"
- assert theItem.itemRoot == "0123456789abc"
+ assert theItem.itemName == "A File"
+ assert theItem.itemHandle == "0000000000003"
+ assert theItem.itemParent == "0000000000002"
+ assert theItem.itemRoot == "0000000000001"
assert theItem.itemOrder == 1
+ assert theItem.itemType == nwItemType.FILE
+ assert theItem.itemClass == nwItemClass.NOVEL
+ assert theItem.itemLayout == nwItemLayout.DOCUMENT
+ assert theItem.itemStatus == "s000000"
+ assert theItem.itemImport == "i000001"
assert theItem.isActive is False
- assert theItem.paraCount == 3
- assert theItem.wordCount == 5
- assert theItem.charCount == 7
- assert theItem.cursorPos == 11
- assert theItem.itemClass == nwItemClass.NOVEL
- assert theItem.itemType == nwItemType.FILE
- assert theItem.itemLayout == nwItemLayout.NOTE
- assert theItem.itemStatus == statusKeys[0] # Was None, should now be default
- assert theItem.itemImport == importKeys[3]
-
- # Folder
- # ======
-
- theItem = NWItem(theProject)
- theItem.setHandle("0123456789abc")
- theItem.setParent("0123456789abc")
- theItem.setRoot("0123456789abc")
- theItem.setOrder(1)
- theItem.setName("A Name")
- theItem.setClass("NOVEL")
- theItem.setType("FOLDER")
- theItem.setStatus(statusKeys[1])
- theItem.setLayout("NOTE")
- theItem.setExpanded(True)
- theItem.setActive(False)
- theItem.setParaCount(3)
- theItem.setWordCount(5)
- theItem.setCharCount(7)
- theItem.setCursorPos(11)
-
- # Pack
- xContent = etree.SubElement(nwXML, "content")
- theItem.packXML(xContent)
- assert etree.tostring(xContent, pretty_print=False, encoding="utf-8") == (
- b''
- b'- A Name
'
- b''
- ) % bytes(statusKeys[1], encoding="utf8")
-
- # Unpack
- theItem = NWItem(theProject)
- assert theItem.unpackXML(xContent[0])
- assert theItem.itemHandle == "0123456789abc"
- assert theItem.itemParent == "0123456789abc"
- assert theItem.itemRoot == "0123456789abc"
- assert theItem.itemOrder == 1
assert theItem.isExpanded is True
- assert theItem.isActive is True
- assert theItem.paraCount == 0
- assert theItem.wordCount == 0
- assert theItem.charCount == 0
- assert theItem.cursorPos == 0
- assert theItem.itemClass == nwItemClass.NOVEL
- assert theItem.itemType == nwItemType.FOLDER
- assert theItem.itemLayout == nwItemLayout.NO_LAYOUT
- assert theItem.itemStatus == statusKeys[1]
- assert theItem.itemImport == importKeys[0] # Was None, should now be default
-
- # Errors
- # ======
-
- # Not an Item
- mockXml = etree.SubElement(nwXML, "stuff")
- assert theItem.unpackXML(mockXml) is False
-
- # Item without Handle
- mockXml = etree.SubElement(nwXML, "item", attrib={"stuff": "nah"})
- assert theItem.unpackXML(mockXml) is False
-
- # Item with Invalid SubElement is Accepted w/Error
- mockXml = etree.SubElement(nwXML, "item", attrib={"handle": "0123456789abc"})
- xParam = etree.SubElement(mockXml, "invalid")
- xParam.text = "stuff"
- caplog.clear()
- assert theItem.unpackXML(mockXml) is True
- assert "Unknown tag 'invalid'" in caplog.text
-
- # Pack Valid Item
- mockXml = etree.SubElement(nwXML, "group")
- theItem._subPack(mockXml, "subGroup", {"one": "two"}, "value", False)
- assert etree.tostring(mockXml, pretty_print=False, encoding="utf-8") == (
- b"value"
- )
-
- # Pack Not Allowed None
- mockXml = etree.SubElement(nwXML, "group")
- assert theItem._subPack(mockXml, "subGroup", {}, None, False) is None
- assert theItem._subPack(mockXml, "subGroup", {}, "None", False) is None
- assert etree.tostring(mockXml, pretty_print=False, encoding="utf-8") == (
- b""
- )
-
-# END Test testCoreItem_XMLPackUnpack
-
-
-@pytest.mark.core
-@pytest.mark.skip
-def testCoreItem_ConvertFromFmt12(mockGUI):
- """Test the setter for all the nwItemLayout values for the NWItem
- class using the class names that were present in file format 1.2.
- """
- theProject = NWProject(mockGUI)
- theItem = NWItem(theProject)
-
- # Deprecated Layouts
- theItem.setLayout("TITLE")
- assert theItem.itemLayout == nwItemLayout.DOCUMENT
- theItem.setLayout("PAGE")
- assert theItem.itemLayout == nwItemLayout.DOCUMENT
- theItem.setLayout("BOOK")
- assert theItem.itemLayout == nwItemLayout.DOCUMENT
- theItem.setLayout("PARTITION")
- assert theItem.itemLayout == nwItemLayout.DOCUMENT
- theItem.setLayout("UNNUMBERED")
- assert theItem.itemLayout == nwItemLayout.DOCUMENT
- theItem.setLayout("CHAPTER")
- assert theItem.itemLayout == nwItemLayout.DOCUMENT
- theItem.setLayout("SCENE")
- assert theItem.itemLayout == nwItemLayout.DOCUMENT
- theItem.setLayout("MUMBOJUMBO")
- assert theItem.itemLayout == nwItemLayout.NO_LAYOUT
-
-# END Test testCoreItem_ConvertFromFmt12
-
-
-@pytest.mark.core
-@pytest.mark.skip
-def testCoreItem_ConvertFromFmt13(mockGUI):
- """Test packing and unpacking XML objects for the NWItem class from
- format version 1.3
- """
- theProject = NWProject(mockGUI)
-
- # Make Version 1.3 XML
- nwXML = etree.Element("novelWriterXML")
- xContent = etree.SubElement(nwXML, "content")
-
- # Folder
- xPack = etree.SubElement(xContent, "item", attrib={
- "handle": "a000000000001",
- "order": "1",
- "parent": "b000000000001",
- })
- NWItem._subPack(xPack, "name", text="Folder")
- NWItem._subPack(xPack, "type", text="FOLDER")
- NWItem._subPack(xPack, "class", text="NOVEL")
- NWItem._subPack(xPack, "status", text="New")
- NWItem._subPack(xPack, "expanded", text="True")
-
- # Unpack Folder
- theItem = NWItem(theProject)
- theItem.unpackXML(xContent[0])
- assert theItem.itemHandle == "a000000000001"
- assert theItem.itemParent == "b000000000001"
- assert theItem.itemOrder == 1
- assert theItem.isExpanded is True
- assert theItem.isActive is True
- assert theItem.charCount == 0
- assert theItem.wordCount == 0
- assert theItem.paraCount == 0
- assert theItem.cursorPos == 0
- assert theItem.itemClass == nwItemClass.NOVEL
- assert theItem.itemType == nwItemType.FOLDER
- assert theItem.itemLayout == nwItemLayout.NO_LAYOUT
-
- # File
- xPack = etree.SubElement(xContent, "item", attrib={
- "handle": "c000000000001",
- "order": "2",
- "parent": "a000000000001",
- })
- NWItem._subPack(xPack, "name", text="Scene")
- NWItem._subPack(xPack, "type", text="FILE")
- NWItem._subPack(xPack, "class", text="NOVEL")
- NWItem._subPack(xPack, "status", text="New")
- NWItem._subPack(xPack, "exported", text="True")
- NWItem._subPack(xPack, "layout", text="DOCUMENT")
- NWItem._subPack(xPack, "charCount", text="600")
- NWItem._subPack(xPack, "wordCount", text="100")
- NWItem._subPack(xPack, "paraCount", text="6")
- NWItem._subPack(xPack, "cursorPos", text="50")
-
- # Unpack File
- theItem = NWItem(theProject)
- theItem.unpackXML(xContent[1])
- assert theItem.itemHandle == "c000000000001"
- assert theItem.itemParent == "a000000000001"
- assert theItem.itemOrder == 2
- assert theItem.isExpanded is False
- assert theItem.isActive is True
- assert theItem.charCount == 600
- assert theItem.wordCount == 100
- assert theItem.paraCount == 6
+ assert theItem.mainHeading == "H1"
+ assert theItem.charCount == 100
+ assert theItem.wordCount == 20
+ assert theItem.paraCount == 2
assert theItem.cursorPos == 50
+
+ assert theItem.pack() == {
+ "name": "A File",
+ "itemAttr": {
+ "handle": "0000000000003",
+ "parent": "0000000000002",
+ "root": "0000000000001",
+ "order": "1",
+ "type": "FILE",
+ "class": "NOVEL",
+ "layout": "DOCUMENT",
+ },
+ "metaAttr": {
+ "expanded": "True",
+ "heading": "H1",
+ "charCount": "100",
+ "wordCount": "20",
+ "paraCount": "2",
+ "cursorPos": "50",
+ },
+ "nameAttr": {
+ "status": "s000000",
+ "import": "i000001",
+ "active": "False",
+ }
+ }
+
+ # Folder
+ theItem = NWItem(theProject)
+ assert theItem.unpack({
+ "label": "A Folder",
+ "handle": "0000000000003",
+ "parent": "0000000000002",
+ "root": "0000000000001",
+ "order": 1,
+ "type": "FOLDER",
+ "class": "NOVEL",
+ "layout": "DOCUMENT",
+ "expanded": True,
+ "status": "",
+ "import": "",
+ "heading": "H1",
+ "charCount": 100,
+ "wordCount": 20,
+ "paraCount": 2,
+ "cursorPos": 50,
+ "active": True,
+ }) is True
+
+ assert theItem.itemName == "A Folder"
+ assert theItem.itemHandle == "0000000000003"
+ assert theItem.itemParent == "0000000000002"
+ assert theItem.itemRoot == "0000000000001"
+ assert theItem.itemOrder == 1
+ assert theItem.itemType == nwItemType.FOLDER
assert theItem.itemClass == nwItemClass.NOVEL
- assert theItem.itemType == nwItemType.FILE
- assert theItem.itemLayout == nwItemLayout.DOCUMENT
+ assert theItem.itemLayout == nwItemLayout.NO_LAYOUT
+ assert theItem.itemStatus == "s000000"
+ assert theItem.itemImport == "i000001"
+ assert theItem.isActive is False
+ assert theItem.isExpanded is True
+ assert theItem.mainHeading == "H0"
+ assert theItem.charCount == 0
+ assert theItem.wordCount == 0
+ assert theItem.paraCount == 0
+ assert theItem.cursorPos == 0
- # Deprecated Type
- theItem.setType("TRASH")
+ assert theItem.pack() == {
+ "name": "A Folder",
+ "itemAttr": {
+ "handle": "0000000000003",
+ "parent": "0000000000002",
+ "root": "0000000000001",
+ "order": "1",
+ "type": "FOLDER",
+ "class": "NOVEL",
+ },
+ "metaAttr": {
+ "expanded": "True",
+ },
+ "nameAttr": {
+ "status": "s000000",
+ "import": "i000001",
+ }
+ }
+
+ # Root
+ theItem = NWItem(theProject)
+ assert theItem.unpack({
+ "label": "A Novel",
+ "handle": "0000000000003",
+ "parent": "0000000000002",
+ "root": "0000000000001",
+ "order": 1,
+ "type": "ROOT",
+ "class": "NOVEL",
+ "layout": "DOCUMENT",
+ "expanded": True,
+ "status": None,
+ "import": None,
+ "heading": "H1",
+ "charCount": 100,
+ "wordCount": 20,
+ "paraCount": 2,
+ "cursorPos": 50,
+ "active": True,
+ }) is True
+
+ assert theItem.itemName == "A Novel"
+ assert theItem.itemHandle == "0000000000003"
+ assert theItem.itemParent is None
+ assert theItem.itemRoot == "0000000000003"
+ assert theItem.itemOrder == 1
assert theItem.itemType == nwItemType.ROOT
+ assert theItem.itemClass == nwItemClass.NOVEL
+ assert theItem.itemLayout == nwItemLayout.NO_LAYOUT
+ assert theItem.itemStatus == "s000000"
+ assert theItem.itemImport == "i000001"
+ assert theItem.isActive is False
+ assert theItem.isExpanded is True
+ assert theItem.mainHeading == "H0"
+ assert theItem.charCount == 0
+ assert theItem.wordCount == 0
+ assert theItem.paraCount == 0
+ assert theItem.cursorPos == 0
-# END Test testCoreItem_ConvertFromFmt13
+ assert theItem.pack() == {
+ "name": "A Novel",
+ "itemAttr": {
+ "handle": "0000000000003",
+ "parent": "None",
+ "root": "0000000000003",
+ "order": "1",
+ "type": "ROOT",
+ "class": "NOVEL",
+ },
+ "metaAttr": {
+ "expanded": "True",
+ },
+ "nameAttr": {
+ "status": "s000000",
+ "import": "i000001",
+ }
+ }
+
+# END Test testCoreItem_PackUnpack
diff --git a/tests/test_core/test_core_project.py b/tests/test_core/test_core_project.py
index 710d8160..02ce6c27 100644
--- a/tests/test_core/test_core_project.py
+++ b/tests/test_core/test_core_project.py
@@ -20,13 +20,14 @@ along with this program. If not, see .
"""
import os
+import shutil
import pytest
from shutil import copyfile
from zipfile import ZipFile
-from tools import cmpFiles, writeFile, readFile, buildTestProject, XML_IGNORE, C
from mock import causeOSError
+from tools import cmpFiles, writeFile, readFile, buildTestProject, XML_IGNORE, C
from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
from novelwriter.common import formatTimeStamp
@@ -36,6 +37,7 @@ from novelwriter.core.index import NWIndex
from novelwriter.core.project import NWProject
from novelwriter.core.options import OptionState
from novelwriter.core.document import NWDoc
+from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter, XMLReadState
@pytest.mark.core
@@ -380,140 +382,90 @@ def testCoreProject_NewFileFolder(monkeypatch, fncDir, outDir, refDir, mockGUI,
@pytest.mark.core
-@pytest.mark.skip
-def testCoreProject_Open(monkeypatch, nwMinimal, mockGUI):
+def testCoreProject_Open(monkeypatch, caplog, mockGUI, fncDir, mockRnd):
"""Test opening a project.
"""
theProject = NWProject(mockGUI)
+ mockRnd.reset()
+ buildTestProject(theProject, fncDir)
# Rename the project file to check handling
- rName = os.path.join(nwMinimal, nwFiles.PROJ_FILE)
- wName = os.path.join(nwMinimal, nwFiles.PROJ_FILE+"_sdfghj")
+ rName = os.path.join(fncDir, nwFiles.PROJ_FILE)
+ wName = os.path.join(fncDir, nwFiles.PROJ_FILE+"_sdfghj")
os.rename(rName, wName)
- assert theProject.openProject(nwMinimal) is False
+ assert theProject.openProject(fncDir) is False
os.rename(wName, rName)
# Fail on folder structure check
with monkeypatch.context() as mp:
mp.setattr("os.mkdir", causeOSError)
- assert theProject.openProject(nwMinimal) is False
+ shutil.rmtree(os.path.join(fncDir, "meta"))
+ assert theProject.openProject(fncDir) is False
# Fail on lock file
- theProject.setProjectPath(nwMinimal)
+ theProject.setProjectPath(fncDir)
assert theProject._writeLockFile()
- assert theProject.openProject(nwMinimal) is False
+ assert theProject.openProject(fncDir) is False
# Fail to read lockfile (which still opens the project)
with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError)
- assert theProject.openProject(nwMinimal) is True
+ caplog.clear()
+ assert theProject.openProject(fncDir) is True
+ assert "Failed to check lock file" in caplog.text
assert theProject.closeProject()
# Force open with lockfile
- theProject.setProjectPath(nwMinimal)
+ theProject.setProjectPath(fncDir)
assert theProject._writeLockFile()
- assert theProject.openProject(nwMinimal, overrideLock=True) is True
+ assert theProject.openProject(fncDir, 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, "stuff")
- assert theProject.openProject(nwMinimal) 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 "Project file does not appear" in mockGUI.lastAlert
- # Also write a jun XML backup file
- writeFile(bName, "stuff")
- assert theProject.openProject(nwMinimal) is False
+ # 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 "Unknown or unsupported novelWriter project file" in mockGUI.lastAlert
- # Wrong root item
- writeFile(rName, "\n")
- assert theProject.openProject(nwMinimal) is False
+ # 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 "Failed to parse project xml" in mockGUI.lastAlert
- # Wrong file version
- writeFile(rName, (
- "\n"
- "\n"
- "\n"
- ))
- mockGUI.askResponse = False
- assert theProject.openProject(nwMinimal) is False
- mockGUI.undo()
+ # 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 "The file format of your project is about to be" in mockGUI.lastQuestion[1]
+ mockGUI.askResponse = True
- # Future file version
- writeFile(rName, (
- "\n"
- "\n"
- "\n"
- ))
- assert theProject.openProject(nwMinimal) is False
-
- # Update file version
- writeFile(rName, (
- "\n"
- "\n"
- "\n"
- ))
- mockGUI.askResponse = False
- assert theProject.openProject(nwMinimal) is False
- assert mockGUI.lastQuestion[0] == "File Version"
- mockGUI.undo()
-
- # Larger hex version
- writeFile(rName, (
- "\n"
- "\n"
- "\n"
- ) % theProject.FILE_VERSION)
- mockGUI.askResponse = False
- assert theProject.openProject(nwMinimal) is False
- assert mockGUI.lastQuestion[0] == "Version Conflict"
- mockGUI.undo()
-
- # Test skipping XML entries
- writeFile(rName, (
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- ))
- assert theProject.openProject(nwMinimal) is True
- assert theProject.closeProject()
-
- # Clean up XML files
- os.unlink(rName)
- os.unlink(bName)
- os.rename(oName, rName)
+ # Won't convert legacy file
+ with monkeypatch.context() as mp:
+ mp.setattr(ProjectXMLReader, "hexVersion", property(lambda *a: "0x99999999"))
+ mockGUI.askResponse = False
+ assert theProject.openProject(fncDir) is False
+ assert "This project was saved by a newer version" in mockGUI.lastQuestion[1]
+ mockGUI.askResponse = True
# Add some legacy stuff that cannot be removed
with monkeypatch.context() as mp:
mp.setattr(theProject, "_legacyDataFolder", causeOSError)
- os.mkdir(os.path.join(nwMinimal, "data_0"))
- writeFile(os.path.join(nwMinimal, "data_0", "123456789abc_main.nwd"), "stuff")
- writeFile(os.path.join(nwMinimal, "data_0", "123456789abc_main.bak"), "stuff")
+ os.mkdir(os.path.join(fncDir, "data_0"))
+ writeFile(os.path.join(fncDir, "data_0", "123456789abc_main.nwd"), "stuff")
+ writeFile(os.path.join(fncDir, "data_0", "123456789abc_main.bak"), "stuff")
mockGUI.clear()
- assert theProject.openProject(nwMinimal) is True
+ assert theProject.openProject(fncDir) is True
assert "There was an error updating the project." in mockGUI.lastAlert
assert theProject.closeProject()
@@ -522,57 +474,31 @@ def testCoreProject_Open(monkeypatch, nwMinimal, mockGUI):
@pytest.mark.core
-@pytest.mark.skip
-def testCoreProject_Save(monkeypatch, nwMinimal, mockGUI, refDir):
+def testCoreProject_Save(monkeypatch, mockGUI, mockRnd, fncDir, refDir):
"""Test saving a project.
"""
theProject = NWProject(mockGUI)
- testFile = os.path.join(nwMinimal, "nwProject.nwx")
- backFile = os.path.join(nwMinimal, "nwProject.bak")
- 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)
+ mockRnd.reset()
+ buildTestProject(theProject, fncDir)
# Fail on folder structure check
with monkeypatch.context() as mp:
- mp.setattr("os.path.isdir", lambda *a: False)
+ mp.setattr("os.mkdir", causeOSError)
+ shutil.rmtree(os.path.join(fncDir, "meta"))
assert theProject.saveProject() is False
- # Fail on open file
+ # Fail writing
with monkeypatch.context() as mp:
- mp.setattr("builtins.open", causeOSError)
+ mp.setattr(ProjectXMLWriter, "write", lambda *a: False)
assert theProject.saveProject() is False
- # Fail on creating .bak file
- with monkeypatch.context() as mp:
- mp.setattr("os.replace", causeOSError)
- assert theProject.saveProject() is False
- assert os.path.isfile(backFile) is False
-
- # Successful save
- saveCount = theProject.data.saveCount
- autoCount = theProject.data.autoCount
- assert theProject.saveProject() is True
- assert theProject.data.saveCount == saveCount + 1
- assert theProject.data.autoCount == autoCount
- assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE)
-
- # Check that a second save creates a .bak file
- assert os.path.isfile(backFile) is True
-
- # Successful autosave
- saveCount = theProject.data.saveCount
- autoCount = theProject.data.autoCount
+ # Save with and without autosave
+ assert theProject.saveProject(autoSave=False) is True
assert theProject.saveProject(autoSave=True) is True
- assert theProject.data.saveCount == saveCount
- assert theProject.data.autoCount == autoCount + 1
- assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE)
-
- # Close test project
assert theProject.closeProject()
# END Test testCoreProject_Save
@@ -683,11 +609,11 @@ def testCoreProject_Helpers(monkeypatch, fncDir, mockGUI):
@pytest.mark.core
-def testCoreProject_AccessItems(nwMinimal, mockGUI):
+def testCoreProject_AccessItems(mockGUI, fncDir, mockRnd):
"""Test helper functions for the project folder.
"""
theProject = NWProject(mockGUI)
- theProject.openProject(nwMinimal)
+ buildTestProject(theProject, fncDir)
# Storage Objects
assert isinstance(theProject.index, NWIndex)
@@ -696,34 +622,34 @@ def testCoreProject_AccessItems(nwMinimal, mockGUI):
# 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
+ C.hNovelRoot,
+ C.hPlotRoot,
+ C.hCharRoot,
+ C.hWorldRoot,
+ C.hTitlePage,
+ C.hChapterDir,
+ C.hChapterDoc,
+ C.hSceneDoc,
]
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
+ C.hTitlePage,
+ C.hChapterDoc,
+ C.hSceneDoc,
+ C.hChapterDir,
+ C.hNovelRoot,
+ C.hPlotRoot,
+ C.hCharRoot,
+ C.hWorldRoot,
]
assert theProject.tree.handles() == oldOrder
assert theProject.setTreeOrder(newOrder)
assert theProject.tree.handles() == newOrder
# Add a non-existing item
- theProject.tree._treeOrder.append("01234567789abc")
+ theProject.tree._treeOrder.append(C.hInvalid)
# Add an item with a non-existent parent
- nHandle = theProject.newFile("Test File", "a6d311a93600a")
+ nHandle = theProject.newFile("Test File", C.hChapterDir)
theProject.tree[nHandle].setParent("cba9876543210")
assert theProject.tree[nHandle].itemParent == "cba9876543210"
@@ -732,15 +658,15 @@ def testCoreProject_AccessItems(nwMinimal, mockGUI):
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
+ C.hNovelRoot,
+ C.hPlotRoot,
+ C.hCharRoot,
+ C.hWorldRoot,
+ nHandle,
+ C.hTitlePage,
+ C.hChapterDir,
+ C.hChapterDoc,
+ C.hSceneDoc,
]
assert theProject.tree[nHandle].itemParent is None
@@ -748,28 +674,28 @@ def testCoreProject_AccessItems(nwMinimal, mockGUI):
@pytest.mark.core
-@pytest.mark.skip
def testCoreProject_StatusImport(mockGUI, fncDir, mockRnd):
"""Test the status and importance flag handling.
"""
theProject = NWProject(mockGUI)
+ mockRnd.reset()
buildTestProject(theProject, fncDir)
- statusKeys = ["s000008", "s000009", "s00000a", "s00000b"]
- importKeys = ["i00000c", "i00000d", "i00000e", "i00000f"]
+ statusKeys = [C.sNew, C.sNote, C.sDraft, C.sFinished]
+ importKeys = [C.iNew, C.iMinor, C.iMajor, C.iMain]
# Change Status
# =============
- theProject.tree["0000000000014"].setStatus(statusKeys[3])
- theProject.tree["0000000000015"].setStatus(statusKeys[2])
- theProject.tree["0000000000016"].setStatus(statusKeys[1])
- theProject.tree["0000000000017"].setStatus(statusKeys[3])
+ theProject.tree[C.hNovelRoot].setStatus(statusKeys[3])
+ theProject.tree[C.hPlotRoot].setStatus(statusKeys[2])
+ theProject.tree[C.hCharRoot].setStatus(statusKeys[1])
+ theProject.tree[C.hWorldRoot].setStatus(statusKeys[3])
- assert theProject.tree["0000000000014"].itemStatus == statusKeys[3]
- assert theProject.tree["0000000000015"].itemStatus == statusKeys[2]
- assert theProject.tree["0000000000016"].itemStatus == statusKeys[1]
- assert theProject.tree["0000000000017"].itemStatus == statusKeys[3]
+ assert theProject.tree[C.hNovelRoot].itemStatus == statusKeys[3]
+ assert theProject.tree[C.hPlotRoot].itemStatus == statusKeys[2]
+ assert theProject.tree[C.hCharRoot].itemStatus == statusKeys[1]
+ assert theProject.tree[C.hWorldRoot].itemStatus == statusKeys[3]
newList = [
{"key": statusKeys[0], "name": "New", "cols": (1, 1, 1)},
@@ -792,8 +718,8 @@ def testCoreProject_StatusImport(mockGUI, fncDir, mockRnd):
assert theProject.data.itemStatus.cols(statusKeys[3]) == (4, 4, 4)
# Check the new entry
- lastKey = theProject.data.itemStatus.check("s000018")
- assert lastKey == "s000018"
+ lastKey = theProject.data.itemStatus.check("s000010")
+ assert lastKey == "s000010"
assert theProject.data.itemStatus.name(lastKey) == "Finished"
assert theProject.data.itemStatus.cols(lastKey) == (5, 5, 5)
@@ -804,7 +730,7 @@ def testCoreProject_StatusImport(mockGUI, fncDir, mockRnd):
# Change Importance
# =================
- fHandle = theProject.newFile("Jane Doe", "0000000000012")
+ fHandle = theProject.newFile("Jane Doe", C.hCharRoot)
theProject.tree[fHandle].setImport(importKeys[3])
assert theProject.tree[fHandle].itemImport == importKeys[3]
@@ -829,8 +755,8 @@ def testCoreProject_StatusImport(mockGUI, fncDir, mockRnd):
assert theProject.data.itemImport.cols(importKeys[3]) == (4, 4, 4)
# Check the new entry
- lastKey = theProject.data.itemImport.check("i00001a")
- assert lastKey == "i00001a"
+ lastKey = theProject.data.itemImport.check("i000012")
+ assert lastKey == "i000012"
assert theProject.data.itemImport.name(lastKey) == "Max"
assert theProject.data.itemImport.cols(lastKey) == (5, 5, 5)
@@ -854,18 +780,6 @@ def testCoreProject_StatusImport(mockGUI, fncDir, mockRnd):
assert theProject.saveProject() is True
assert theProject.closeProject() is True
- # This should restore the default status/import labels
- assert theProject.openProject(fncDir) is True
- assert theProject.saveProject() is True
- assert theProject.data.itemStatus.name("s000023") == "New"
- assert theProject.data.itemStatus.name("s000024") == "Note"
- assert theProject.data.itemStatus.name("s000025") == "Draft"
- assert theProject.data.itemStatus.name("s000026") == "Finished"
- assert theProject.data.itemImport.name("i000027") == "New"
- assert theProject.data.itemImport.name("i000028") == "Minor"
- assert theProject.data.itemImport.name("i000029") == "Major"
- assert theProject.data.itemImport.name("i00002a") == "Main"
-
# END Test testCoreProject_StatusImport
@@ -1268,14 +1182,14 @@ def testCoreProject_LegacyData(monkeypatch, mockGUI, fncDir):
@pytest.mark.core
-def testCoreProject_Backup(monkeypatch, mockGUI, nwMinimal, tmpDir):
+def testCoreProject_Backup(monkeypatch, mockGUI, fncDir, 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
the original file.
"""
theProject = NWProject(mockGUI)
- assert theProject.openProject(nwMinimal)
+ buildTestProject(theProject, fncDir)
# Test faulty settings
@@ -1299,11 +1213,11 @@ def testCoreProject_Backup(monkeypatch, mockGUI, nwMinimal, tmpDir):
assert theProject.zipIt(doNotify=False) is False
# Same folder as project (causes infinite loop in zipping)
- theProject.mainConf.backupPath = nwMinimal
+ theProject.mainConf.backupPath = fncDir
assert theProject.zipIt(doNotify=False) is False
# Subfolder of project (causes infinite loop in zipping)
- theProject.mainConf.backupPath = os.path.join(nwMinimal, "subdir")
+ theProject.mainConf.backupPath = os.path.join(fncDir, "subdir")
assert theProject.zipIt(doNotify=False) is False
# Set a valid folder
@@ -1335,7 +1249,7 @@ def testCoreProject_Backup(monkeypatch, mockGUI, nwMinimal, tmpDir):
# Check that the main project file was restored
assert cmpFiles(
- os.path.join(nwMinimal, "nwProject.nwx"),
+ os.path.join(fncDir, "nwProject.nwx"),
os.path.join(tmpDir, "extract", "nwProject.nwx")
)
diff --git a/tests/test_core/test_core_status.py b/tests/test_core/test_core_status.py
index 9f01136c..760f31f5 100644
--- a/tests/test_core/test_core_status.py
+++ b/tests/test_core/test_core_status.py
@@ -20,23 +20,21 @@ along with this program. If not, see .
"""
import pytest
-import random
-from lxml import etree
+from tools import C
from PyQt5.QtGui import QIcon
from novelwriter.core.status import NWStatus
-statusKeys = ["sa3b179", "s1c8031", "s06671a", "sbdd640"]
-importKeys = ["i466852", "i3eb13b", "i392456", "i23b8c1"]
+statusKeys = [C.sNew, C.sNote, C.sDraft, C.sFinished]
+importKeys = [C.iNew, C.iMinor, C.iMajor, C.iMain]
@pytest.mark.core
-def testCoreStatus_Internal():
+def testCoreStatus_Internal(mockRnd):
"""Test all the internal functions of the NWStatus class.
"""
- random.seed(42)
theStatus = NWStatus(NWStatus.STATUS)
theImport = NWStatus(NWStatus.IMPORT)
@@ -87,10 +85,9 @@ def testCoreStatus_Internal():
@pytest.mark.core
-def testCoreStatus_Iterator():
+def testCoreStatus_Iterator(mockRnd):
"""Test the iterator functions of the NWStatus class.
"""
- random.seed(42)
theStatus = NWStatus(NWStatus.STATUS)
theStatus.write(None, "New", (100, 100, 100))
@@ -132,10 +129,9 @@ def testCoreStatus_Iterator():
@pytest.mark.core
-def testCoreStatus_Entries():
+def testCoreStatus_Entries(mockRnd):
"""Test all the simple setters for the NWStatus class.
"""
- random.seed(42)
theStatus = NWStatus(NWStatus.STATUS)
# Write
@@ -300,11 +296,9 @@ def testCoreStatus_Entries():
@pytest.mark.core
-@pytest.mark.skip
-def testCoreStatus_XMLPackUnpack():
- """Test all the XML pack/unpack of the NWStatus class.
+def testCoreStatus_PackUnpack(mockRnd):
+ """Test all the pack/unpack of the NWStatus class.
"""
- random.seed(42)
theStatus = NWStatus(NWStatus.STATUS)
theStatus.write(None, "New", (100, 100, 100))
theStatus.write(None, "Note", (200, 50, 0))
@@ -316,36 +310,59 @@ def testCoreStatus_XMLPackUnpack():
for _ in range(n):
theStatus.increment(statusKeys[i])
- nwXML = etree.Element("novelWriterXML")
-
# Pack
- xStatus = etree.SubElement(nwXML, "status")
- theStatus.packXML(xStatus)
- assert etree.tostring(xStatus, pretty_print=False, encoding="utf-8") == (
- b''
- b'New'
- b'Note'
- b'Draft'
- b'Finished'
- b''
- )
+ assert list(theStatus.pack()) == [
+ ("New", {
+ "key": statusKeys[0],
+ "count": "3",
+ "red": "100",
+ "green": "100",
+ "blue": "100"
+ }),
+ ("Note", {
+ "key": statusKeys[1],
+ "count": "5",
+ "red": "200",
+ "green": "50",
+ "blue": "0"
+ }),
+ ("Draft", {
+ "key": statusKeys[2],
+ "count": "7",
+ "red": "200",
+ "green": "150",
+ "blue": "0"
+ }),
+ ("Finished", {
+ "key": statusKeys[3],
+ "count": "9",
+ "red": "50",
+ "green": "200",
+ "blue": "0"
+ }),
+ ]
# Unpack
theStatus = NWStatus(NWStatus.STATUS)
- assert theStatus.unpackXML(xStatus)
+ assert theStatus.unpack({
+ statusKeys[0]: {"label": "New0", "colour": (100, 100, 100), "count": countTo[0]},
+ statusKeys[1]: {"label": "New1", "colour": (150, 150, 150), "count": countTo[1]},
+ statusKeys[2]: {"label": "New2", "colour": (200, 200, 200), "count": countTo[2]},
+ statusKeys[3]: {"label": "New3", "colour": (250, 250, 250), "count": countTo[3]},
+ })
assert len(theStatus._store) == 4
assert list(theStatus._store.keys()) == statusKeys
- assert theStatus._store[statusKeys[0]]["name"] == "New"
- assert theStatus._store[statusKeys[1]]["name"] == "Note"
- assert theStatus._store[statusKeys[2]]["name"] == "Draft"
- assert theStatus._store[statusKeys[3]]["name"] == "Finished"
+ assert theStatus._store[statusKeys[0]]["name"] == "New0"
+ assert theStatus._store[statusKeys[1]]["name"] == "New1"
+ assert theStatus._store[statusKeys[2]]["name"] == "New2"
+ assert theStatus._store[statusKeys[3]]["name"] == "New3"
assert theStatus._store[statusKeys[0]]["cols"] == (100, 100, 100)
- assert theStatus._store[statusKeys[1]]["cols"] == (200, 50, 0)
- assert theStatus._store[statusKeys[2]]["cols"] == (200, 150, 0)
- assert theStatus._store[statusKeys[3]]["cols"] == (50, 200, 0)
+ assert theStatus._store[statusKeys[1]]["cols"] == (150, 150, 150)
+ assert theStatus._store[statusKeys[2]]["cols"] == (200, 200, 200)
+ assert theStatus._store[statusKeys[3]]["cols"] == (250, 250, 250)
assert theStatus._store[statusKeys[0]]["count"] == countTo[0]
assert theStatus._store[statusKeys[1]]["count"] == countTo[1]
assert theStatus._store[statusKeys[2]]["count"] == countTo[2]
assert theStatus._store[statusKeys[3]]["count"] == countTo[3]
-# END Test testCoreStatus_XMLPackUnpack
+# END Test testCoreStatus_PackUnpack