From ea34884d8cac13f14bb2d34a94f6ddc6e29ab324 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Sun, 12 May 2019 11:59:47 +0200 Subject: [PATCH 1/5] Updated config class to split the initialisation into a function --- nw/__init__.py | 4 +-- nw/config.py | 67 +++++++++++++++++++++++++++++++------------------- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/nw/__init__.py b/nw/__init__.py index c1388a58..8f5c06dc 100644 --- a/nw/__init__.py +++ b/nw/__init__.py @@ -62,10 +62,10 @@ logger = logging.getLogger(__name__) # Load the main config as a global object CONFIG = Config() +CONFIG.initConfig() def main(sysArgs): - """ - Parses command line, sets up logging, and launches main GUI. + """Parses command line, sets up logging, and launches main GUI. """ # Valid Input Options diff --git a/nw/config.py b/nw/config.py index 68b76411..2555c58c 100644 --- a/nw/config.py +++ b/nw/config.py @@ -6,7 +6,7 @@ This class reads and store the main preferences of the application File History: - Created: 2018-0+-22 [0.0.1] + Created: 2018-09-22 [0.0.1] """ @@ -28,25 +28,18 @@ class Config: def __init__(self): # Set Application Variables - self.appName = nw.__package__ - self.appHandle = nw.__package__.lower() - self.showGUI = True - self.debugGUI = False + self.appName = nw.__package__ + self.appHandle = nw.__package__.lower() + self.showGUI = True + self.debugGUI = False # Set Paths - self.confPath = user_config_dir(self.appHandle) - self.confFile = self.appHandle+".conf" - self.homePath = path.expanduser("~") - self.appPath = path.dirname(__file__) - self.guiPath = path.join(self.appPath,"gui") - self.themePath = path.join(self.appPath,"themes") - self.recentList = [""]*10 - - # If config folder does not exist, make it. - # This assumes that the os config folder itself exists. - # TODO: This does not work on Windows - if not path.isdir(self.confPath): - mkdir(self.confPath) + self.confPath = None + self.confFile = None + self.homePath = None + self.appPath = None + self.guiPath = None + self.themePath = None # Set default values self.confChanged = False @@ -81,13 +74,8 @@ class Config: self.spellLanguage = "en_GB" - # Check if config file exists - if path.isfile(path.join(self.confPath,self.confFile)): - self.loadConfig() - - # Save a copy of the default config if no file exists - if not path.isfile(path.join(self.confPath,self.confFile)): - self.saveConfig() + # Path + self.recentList = [""]*10 return @@ -95,6 +83,35 @@ class Config: # Actions ## + def initConfig(self, confPath=None): + + if confPath is None: + self.confPath = user_config_dir(self.appHandle) + else: + self.confPath = confPath + + self.confFile = self.appHandle+".conf" + self.homePath = path.expanduser("~") + self.appPath = path.dirname(__file__) + self.guiPath = path.join(self.appPath,"gui") + self.themePath = path.join(self.appPath,"themes") + + # If config folder does not exist, make it. + # This assumes that the os config folder itself exists. + # TODO: This does not work on Windows + if not path.isdir(self.confPath): + mkdir(self.confPath) + + # Check if config file exists + if path.isfile(path.join(self.confPath,self.confFile)): + # If it exists, load it + self.loadConfig() + else: + # If it does not exist, save a copy of the defaults + self.saveConfig() + + return + def loadConfig(self): logger.debug("Loading config file") From 223db59e3ddf3401ed19d3d3c069b3f7a29ab018 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Sun, 12 May 2019 13:29:18 +0200 Subject: [PATCH 2/5] Added test framwork and two simple tests for the config class --- tests/nwtools.py | 34 ++++++++++++++++++++++++++++ tests/reference/novelwriter.conf | 38 ++++++++++++++++++++++++++++++++ tests/test_config.py | 35 +++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 tests/nwtools.py create mode 100644 tests/reference/novelwriter.conf create mode 100644 tests/test_config.py diff --git a/tests/nwtools.py b/tests/nwtools.py new file mode 100644 index 00000000..b689a50e --- /dev/null +++ b/tests/nwtools.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +"""novelWriter Test Tools +""" + +def cmpFiles(fileOne, fileTwo, ignoreLines=[]): + foOne = open(fileOne,mode="r") + foTwo = open(fileTwo,mode="r") + + txtOne = foOne.readlines() + txtTwo = foTwo.readlines() + + if len(txtOne) != len(txtTwo): + print("Files are not the same length") + return False + + diffFound = False + for n in range(len(txtOne)): + lnOne = txtOne[n].strip() + lnTwo = txtTwo[n].strip() + + if n+1 in ignoreLines: + print("Ignoring line %d" % (n+1)) + continue + + if lnOne != lnTwo: + print("Diff on line %d:" % (n+1)) + print(" << '%s'" % lnOne) + print(" >> '%s'" % lnTwo) + diffFound = True + + foOne.close() + foTwo.close() + + return not diffFound diff --git a/tests/reference/novelwriter.conf b/tests/reference/novelwriter.conf new file mode 100644 index 00000000..00e800be --- /dev/null +++ b/tests/reference/novelwriter.conf @@ -0,0 +1,38 @@ +[Main] +timestamp = 2019-05-12 12:04:16 + +[Sizes] +geometry = 1100, 650 +treecols = 120, 30, 50 +mainpane = 300, 800 + +[Project] +autosaveproject = 60 +autosavedoc = 30 + +[Editor] +fixedwidth = True +width = 600 +margins = 40, 40 +textsize = 13 +justify = True +autoselect = True +autoreplace = True +repsquotes = True +repdquotes = True +repdash = True +repdots = True +spellcheck = en_GB + +[Path] +recent0 = +recent1 = +recent2 = +recent3 = +recent4 = +recent5 = +recent6 = +recent7 = +recent8 = +recent9 = + diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 00000000..ce1c2ad2 --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +"""novelWriter Config Class Tester + + novelWriter – Config Class Tester +=================================== + +""" + +import nw +import filecmp + +from nwtools import cmpFiles + +from os import path, unlink + +from nw.config import Config + +theConf = Config() +testDir = path.dirname(__file__) +testTemp = path.join(testDir,"temp") +testRef = path.join(testDir,"reference") +tmpConf = path.join(testTemp,"novelwriter.conf") +refConf = path.join(testRef, "novelwriter.conf") + +# Clean out old stuff +if path.isfile(tmpConf): + unlink(tmpConf) + +def testConfigInit(): + assert theConf.initConfig(testTemp) + assert cmpFiles(tmpConf, refConf, [2]) + +def testConfigSave(): + assert theConf.saveConfig() + assert cmpFiles(tmpConf, refConf, [2]) From edab608c3b5d32e19b4cbe6fcce4c00482fe8f32 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Sun, 12 May 2019 13:29:41 +0200 Subject: [PATCH 3/5] Some changes to core classes and files to support the test suite --- nw/__init__.py | 7 ++++--- nw/config.py | 15 ++++++++++----- nw/gui/winmain.py | 3 ++- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/nw/__init__.py b/nw/__init__.py index 8f5c06dc..a1755d6c 100644 --- a/nw/__init__.py +++ b/nw/__init__.py @@ -62,7 +62,6 @@ logger = logging.getLogger(__name__) # Load the main config as a global object CONFIG = Config() -CONFIG.initConfig() def main(sysArgs): """Parses command line, sets up logging, and launches main GUI. @@ -149,10 +148,10 @@ def main(sysArgs): showGUI = False elif inOpt in ("-D","--debuggui"): debugLevel = logging.DEBUG - debugStr = "{name:>22}:{lineno:<4d} {levelname:8} {message:}" + debugStr = "{name:>20}:{lineno:<4d} {levelname:8} {message:}" debugGUI = True - # Set GUI options + # Set Config Options CONFIG.showGUI = showGUI CONFIG.debugGUI = debugGUI @@ -179,6 +178,8 @@ def main(sysArgs): logger.setLevel(debugLevel) + CONFIG.initConfig(confPath) + nwApp = QApplication([]) nwGUI = NovelWriter() exit(nwApp.exec_()) diff --git a/nw/config.py b/nw/config.py index 2555c58c..254c06df 100644 --- a/nw/config.py +++ b/nw/config.py @@ -88,6 +88,7 @@ class Config: if confPath is None: self.confPath = user_config_dir(self.appHandle) else: + logger.info("Setting config from alternative path: %s" % confPath) self.confPath = confPath self.confFile = self.appHandle+".conf" @@ -110,13 +111,13 @@ class Config: # If it does not exist, save a copy of the defaults self.saveConfig() - return + return True def loadConfig(self): logger.debug("Loading config file") confParser = configparser.ConfigParser() - confParser.readfp(open(path.join(self.confPath,self.confFile))) + confParser.read_file(open(path.join(self.confPath,self.confFile))) # Get options @@ -231,10 +232,14 @@ class Config: confParser.set(cnfSec,"recent%d" % i, str(self.recentList[i])) # Write config file - confParser.write(open(path.join(self.confPath,self.confFile),"w")) - self.confChanged = False + try: + confParser.write(open(path.join(self.confPath,self.confFile),"w")) + self.confChanged = False + except Exception as e: + logger.error("Could not save config file") + return False - return + return True def unpackList(self, inStr, listLen, listDefault, castTo=int): inData = inStr.split(",") diff --git a/nw/gui/winmain.py b/nw/gui/winmain.py index a6125afe..e0b6693b 100644 --- a/nw/gui/winmain.py +++ b/nw/gui/winmain.py @@ -106,7 +106,8 @@ class GuiMain(QMainWindow): self.asDocTimer.timeout.connect(self._autoSaveDocument) self.asDocTimer.start() - self.show() + if self.mainConf.showGUI: + self.show() logger.debug("GUI initialisation complete") From f1d30ae253d50d9a14edc76ae1c564e83df328b6 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Sun, 12 May 2019 14:08:52 +0200 Subject: [PATCH 4/5] Project class should not contain any GUI elements. Status icons moved to main GUI class. --- nw/gui/docdetails.py | 5 +++-- nw/gui/doctree.py | 4 ++-- nw/gui/winmain.py | 26 ++++++++++++++++++++++++-- nw/project/project.py | 29 +++++------------------------ 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/nw/gui/docdetails.py b/nw/gui/docdetails.py index 9851d590..c8b6a078 100644 --- a/nw/gui/docdetails.py +++ b/nw/gui/docdetails.py @@ -35,6 +35,7 @@ class GuiDocDetails(QFrame): logger.debug("Initialising DocDetails ...") self.mainConf = nw.CONFIG self.debugGUI = self.mainConf.debugGUI + self.theParent = theParent self.theProject = theProject self.mainBox = QGridLayout(self) @@ -70,11 +71,11 @@ class GuiDocDetails(QFrame): colTwo = [""]*4 else: itemStatus = nwItem.itemStatus - if itemStatus < 0 or itemStatus >= len(self.theProject.statusLabels): + if itemStatus < 0 or itemStatus >= len(self.theParent.statusLabels): itemStatus = 0 colTwo = [ nwItem.itemName, - self.theProject.statusLabels[itemStatus], + self.theParent.statusLabels[itemStatus], nwLabels.CLASS_NAME[nwItem.itemClass], nwLabels.LAYOUT_NAME[nwItem.itemLayout], ] diff --git a/nw/gui/doctree.py b/nw/gui/doctree.py index 859ff0c9..4ef921f2 100644 --- a/nw/gui/doctree.py +++ b/nw/gui/doctree.py @@ -252,12 +252,12 @@ class GuiDocTree(QTreeWidget): if nwItem.itemType == nwItemType.FILE: tStatus += "."+nwLabels.LAYOUT_FLAG[nwItem.itemLayout] nStatus = nwItem.itemStatus - if nStatus < 0 or nStatus >= len(self.theProject.statusIcons): + if nStatus < 0 or nStatus >= len(self.theParent.statusIcons): nStatus = 0 trItem.setText(self.C_NAME,tName) trItem.setText(self.C_FLAGS,tStatus) - trItem.setIcon(self.C_FLAGS,self.theProject.statusIcons[nStatus]) + trItem.setIcon(self.C_FLAGS,self.theParent.statusIcons[nStatus]) return diff --git a/nw/gui/winmain.py b/nw/gui/winmain.py index e0b6693b..aef80173 100644 --- a/nw/gui/winmain.py +++ b/nw/gui/winmain.py @@ -15,7 +15,7 @@ import nw from os import path from PyQt5.QtWidgets import QWidget, QMainWindow, QVBoxLayout, QFrame, QSplitter, QFileDialog, QStackedWidget, QShortcut, QMessageBox -from PyQt5.QtGui import QIcon +from PyQt5.QtGui import QIcon, QPixmap, QColor from PyQt5.QtCore import Qt, QTimer from nw.gui.doctree import GuiDocTree @@ -57,6 +57,10 @@ class GuiMain(QMainWindow): self.mainMenu = GuiMainMenu(self, self.theProject) self.statusBar = GuiMainStatus(self) + # Minor Gui Elements + self.statusIcons = [] + self.statusLabels = [] + # Assemble Main Window self.stackPane = QStackedWidget() self.stackNone = self.stackPane.addWidget(QWidget()) @@ -82,7 +86,7 @@ class GuiMain(QMainWindow): self.treeView.itemSelectionChanged.connect(self._treeSingleClick) self.treeView.itemDoubleClicked.connect(self._treeDoubleClick) self.treeView.buildTree() - QShortcut(Qt.Key_Return, self.treeView, context=Qt.WidgetShortcut, activated=self._treeKeyPressReturn) + self._makeStatusIcons() # Set Main Window Elements self.setMenuBar(self.mainMenu) @@ -106,6 +110,13 @@ class GuiMain(QMainWindow): self.asDocTimer.timeout.connect(self._autoSaveDocument) self.asDocTimer.start() + # Keyboard Shortcuts + QShortcut(Qt.Key_Return, self.treeView, context=Qt.WidgetShortcut, activated=self._treeKeyPressReturn) + + # Forward Functions + self.setStatus = self.statusBar.setStatus + self.setProjectStatus = self.statusBar.setProjectStatus + if self.mainConf.showGUI: self.show() @@ -162,6 +173,7 @@ class GuiMain(QMainWindow): self.treeView.buildTree() self.mainMenu.updateRecentProjects() self._setWindowTitle(self.theProject.projName) + self._makeStatusIcons() return True def saveProject(self): @@ -340,6 +352,16 @@ class GuiMain(QMainWindow): return False return True + def _makeStatusIcons(self): + self.statusIcons = [] + self.statusLabels = [] + for sLabel, sR, sG, sB in self.theProject.statusCols: + theIcon = QPixmap(32,32) + theIcon.fill(QColor(sR,sG,sB)) + self.statusIcons.append(QIcon(theIcon)) + self.statusLabels.append(sLabel) + return + ## # Events ## diff --git a/nw/project/project.py b/nw/project/project.py index 1ba4685a..11090f2f 100644 --- a/nw/project/project.py +++ b/nw/project/project.py @@ -19,8 +19,6 @@ from hashlib import sha256 from datetime import datetime from time import time -from PyQt5.QtGui import QIcon, QPixmap, QColor - from nw.enum import nwItemType, nwItemClass, nwItemLayout from nw.project.item import NWItem @@ -31,8 +29,8 @@ class NWProject(): def __init__(self, theParent): # Internal - self.mainConf = nw.CONFIG self.theParent = theParent + self.mainConf = self.theParent.mainConf self.projChanged = None # Project Settings @@ -46,8 +44,6 @@ class NWProject(): self.bookTitle = None self.bookAuthors = None self.statusCols = None - self.statusIcons = None - self.statusLabels = None self.clearProject() @@ -108,7 +104,7 @@ class NWProject(): hChapt = self.newFolder("New Chapter", nwItemClass.NOVEL, hNovel) hScene = self.newFile("New Scene", nwItemClass.NOVEL, hChapt) - return + return True def clearProject(self): @@ -124,16 +120,12 @@ class NWProject(): self.projName = "" self.bookTitle = "" self.bookAuthors = [] - self.statusCols = [ ("New", 100,100,100), ("Note", 200, 50, 0), ("Draft", 200,150, 0), ("Finished", 50,200, 0), ] - self.statusIcons = [] - self.statusLabels = [] - self._makeStatusIcons() return @@ -195,9 +187,8 @@ class NWProject(): nwItem.setFromTag(xValue.tag,xValue.text) self._appendItem(tHandle,pHandle,nwItem) - self._makeStatusIcons() self.mainConf.setRecent(self.projPath) - self.theParent.statusBar.setStatus("Opened Project: %s" % self.projName) + self.theParent.setStatus("Opened Project: %s" % self.projName) self._scanProjectFolder() self.setProjectChanged(False) @@ -258,7 +249,7 @@ class NWProject(): return False self.mainConf.setRecent(self.projPath) - self.theParent.statusBar.setStatus("Saved Project: %s" % self.projName) + self.theParent.setStatus("Saved Project: %s" % self.projName) self.setProjectChanged(False) return True @@ -301,7 +292,7 @@ class NWProject(): def setProjectChanged(self, bValue): self.projChanged = bValue - self.theParent.statusBar.setProjectStatus(self.projChanged) + self.theParent.setProjectStatus(self.projChanged) return ## @@ -411,16 +402,6 @@ class NWProject(): return - def _makeStatusIcons(self): - self.statusIcons = [] - self.statusLabels = [] - for sLabel, sR, sG, sB in self.statusCols: - theIcon = QPixmap(32,32) - theIcon.fill(QColor(sR,sG,sB)) - self.statusIcons.append(QIcon(theIcon)) - self.statusLabels.append(sLabel) - return - def _makeHandle(self, addSeed=""): newSeed = str(time()) + addSeed logger.verbose("Generating handle with seed '%s'" % newSeed) From c39efc34fdca33ef18d81b5d5e3cddde8affaecd Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" Date: Sun, 12 May 2019 14:54:02 +0200 Subject: [PATCH 5/5] A good start on project tests. needed some tewaking of the project class. --- .gitignore | 12 ++++- nw/project/project.py | 13 ++++- tests/nwdummy.py | 31 +++++++++++ tests/nwtools.py | 7 +++ tests/reference/new_nwProject.nwx | 55 +++++++++++++++++++ tests/reference/roots_nwProject.nwx | 83 +++++++++++++++++++++++++++++ tests/test_config.py | 12 ++--- tests/test_project.py | 61 +++++++++++++++++++++ 8 files changed, 263 insertions(+), 11 deletions(-) create mode 100644 tests/nwdummy.py create mode 100644 tests/reference/new_nwProject.nwx create mode 100644 tests/reference/roots_nwProject.nwx create mode 100644 tests/test_project.py 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