diff --git a/.gitignore b/.gitignore
index ff89acd8..cf07a362 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,12 @@
+# Python Temp
__pycache__
-*.bak
+
+# Sample Project
+sample/**/cache
+sample/**/wordlist.txt
+sample/**/*.bak
+
+# PyTest
+tests/temp
+.pytest_cache
+pytestdebug.log
diff --git a/nw/project/project.py b/nw/project/project.py
index e03d9103..25a96609 100644
--- a/nw/project/project.py
+++ b/nw/project/project.py
@@ -33,6 +33,9 @@ class NWProject():
self.mainConf = self.theParent.mainConf
self.projChanged = None
+ # Debug
+ self.handleSeed = None
+
# Project Settings
self.projTree = None
self.treeOrder = None
@@ -56,6 +59,9 @@ class NWProject():
##
def newRoot(self, rootName, rootClass):
+ if not self.checkRootUnique(rootClass):
+ self.theParent.makeAlert("Duplicate root item detected!",2)
+ return None
newItem = NWItem()
newItem.setName(rootName)
newItem.setType(nwItemType.ROOT)
@@ -422,7 +428,12 @@ class NWProject():
return
def _makeHandle(self, addSeed=""):
- newSeed = str(time()) + addSeed
+ if self.handleSeed is None:
+ newSeed = str(time()) + addSeed
+ else:
+ # This is used for debugging
+ newSeed = str(self.handleSeed)
+ self.handleSeed += 1
logger.verbose("Generating handle with seed '%s'" % newSeed)
itemHandle = sha256(newSeed.encode()).hexdigest()[0:13]
if itemHandle in self.projTree.keys():
diff --git a/tests/nwdummy.py b/tests/nwdummy.py
new file mode 100644
index 00000000..d033668e
--- /dev/null
+++ b/tests/nwdummy.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+"""novelWriter Test Dummy GUI Classes
+"""
+
+class DummyMain():
+
+ def __init__(self):
+ self.mainConf = None
+ return
+
+ def makeAlert(self, theMessage, theLevel):
+ if theLevel == 1:
+ lvlMsg = "WARNING: "
+ elif theLevel == 2:
+ lvlMsg = "ERROR: "
+ else:
+ lvlMsg = ""
+ if isinstance(theMessage, list):
+ for msgLine in logMsg:
+ print(lvlMsg+msgLine)
+ else:
+ print(lvlMsg+theMessage)
+ return
+
+ def setStatus(self, theMessage):
+ return
+
+ def setProjectStatus(self, isChanged):
+ return
+
+# END Class GuiMain
diff --git a/tests/nwtools.py b/tests/nwtools.py
index b689a50e..dc3bd24b 100644
--- a/tests/nwtools.py
+++ b/tests/nwtools.py
@@ -2,6 +2,13 @@
"""novelWriter Test Tools
"""
+from os import path, mkdir
+
+def ensureDir(theDir):
+ if not path.isdir(theDir):
+ mkdir(theDir)
+ return
+
def cmpFiles(fileOne, fileTwo, ignoreLines=[]):
foOne = open(fileOne,mode="r")
foTwo = open(fileTwo,mode="r")
diff --git a/tests/reference/new_nwProject.nwx b/tests/reference/new_nwProject.nwx
new file mode 100644
index 00000000..742afe41
--- /dev/null
+++ b/tests/reference/new_nwProject.nwx
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+ -
+ Novel
+ ROOT
+ NOVEL
+ 0
+ False
+
+ -
+ Characters
+ ROOT
+ CHARACTER
+ 0
+ False
+
+ -
+ Plot
+ ROOT
+ PLOT
+ 0
+ False
+
+ -
+ World
+ ROOT
+ WORLD
+ 0
+ False
+
+ -
+ New Chapter
+ FOLDER
+ NOVEL
+ 0
+ False
+
+ -
+ New Scene
+ FILE
+ NOVEL
+ 0
+ False
+ SCENE
+ 0
+ 0
+ 0
+
+
+
diff --git a/tests/reference/roots_nwProject.nwx b/tests/reference/roots_nwProject.nwx
new file mode 100644
index 00000000..1971370a
--- /dev/null
+++ b/tests/reference/roots_nwProject.nwx
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+ -
+ Novel
+ ROOT
+ NOVEL
+ 0
+ False
+
+ -
+ Characters
+ ROOT
+ CHARACTER
+ 0
+ False
+
+ -
+ Plot
+ ROOT
+ PLOT
+ 0
+ False
+
+ -
+ World
+ ROOT
+ WORLD
+ 0
+ False
+
+ -
+ New Chapter
+ FOLDER
+ NOVEL
+ 0
+ False
+
+ -
+ New Scene
+ FILE
+ NOVEL
+ 0
+ False
+ SCENE
+ 0
+ 0
+ 0
+
+ -
+ Timeline
+ ROOT
+ TIMELINE
+ 0
+ False
+
+ -
+ Object
+ ROOT
+ OBJECT
+ 0
+ False
+
+ -
+ Custom1
+ ROOT
+ CUSTOM
+ 0
+ False
+
+ -
+ Custom2
+ ROOT
+ CUSTOM
+ 0
+ False
+
+
+
diff --git a/tests/test_config.py b/tests/test_config.py
index ce1c2ad2..90c68d8b 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -1,18 +1,10 @@
# -*- coding: utf-8 -*-
"""novelWriter Config Class Tester
-
- novelWriter – Config Class Tester
-===================================
-
"""
import nw
-import filecmp
-
-from nwtools import cmpFiles
-
+from nwtools import *
from os import path, unlink
-
from nw.config import Config
theConf = Config()
@@ -22,6 +14,8 @@ testRef = path.join(testDir,"reference")
tmpConf = path.join(testTemp,"novelwriter.conf")
refConf = path.join(testRef, "novelwriter.conf")
+ensureDir(testTemp)
+
# Clean out old stuff
if path.isfile(tmpConf):
unlink(tmpConf)
diff --git a/tests/test_project.py b/tests/test_project.py
new file mode 100644
index 00000000..9aa0d2d1
--- /dev/null
+++ b/tests/test_project.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+"""novelWriter Project Class Tester
+"""
+
+import nw
+import types
+from os import path, unlink
+
+from nwtools import *
+from nwdummy import DummyMain
+
+from nw.config import Config
+from nw.project.project import NWProject
+from nw.project.item import NWItem
+from nw.enum import nwItemClass
+
+theConf = Config()
+theMain = DummyMain()
+theMain.mainConf = theConf
+testDir = path.dirname(__file__)
+testTemp = path.join(testDir,"temp")
+testRef = path.join(testDir,"reference")
+testProj = path.join(testTemp,"proj")
+
+ensureDir(testTemp)
+ensureDir(testProj)
+
+theConf.initConfig(testRef)
+theProject = NWProject(theMain)
+theProject.handleSeed = 42
+
+projFile = path.join(testProj,"nwProject.nwx")
+
+def testProjectNew():
+ assert theProject.newProject()
+ assert theProject.setProjectPath(testProj)
+ assert theProject.saveProject()
+ assert cmpFiles(projFile, path.join(testRef,"new_nwProject.nwx"), [2])
+
+def testProjectOpen():
+ assert theProject.openProject(projFile)
+
+def testProjectSave():
+ assert theProject.saveProject()
+ assert cmpFiles(projFile, path.join(testRef,"new_nwProject.nwx"), [2])
+ assert not theProject.projChanged
+
+def testProjectNewRoot():
+ 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 cmpFiles(projFile, path.join(testRef,"roots_nwProject.nwx"), [2])
+ assert not theProject.projChanged