From 470daf0036ef12eca6afdd601928651a4f68cef9 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 25 Apr 2021 23:01:20 +0200 Subject: [PATCH 01/12] Make NWDoc class non-reusable --- nw/core/document.py | 38 ++++++++++++++------------------------ nw/core/index.py | 4 ++-- nw/core/project.py | 29 ++++++++++------------------- nw/core/tokenizer.py | 4 ++-- nw/dialogs/docmerge.py | 9 +++++---- nw/dialogs/docsplit.py | 15 ++++++++------- nw/gui/doceditor.py | 8 +++++--- nw/gui/projtree.py | 8 ++++---- 8 files changed, 50 insertions(+), 65 deletions(-) diff --git a/nw/core/document.py b/nw/core/document.py index c645a840..4607ebe0 100644 --- a/nw/core/document.py +++ b/nw/core/document.py @@ -38,16 +38,16 @@ logger = logging.getLogger(__name__) class NWDoc(): - def __init__(self, theProject): + def __init__(self, theProject, theHandle): self.theProject = theProject self.theParent = theProject.theParent # Internal Variables - self._theItem = None # The currently open item - self._docHandle = None # The handle of the currently open item - self._fileLoc = None # The file location of the currently open item - self._docMeta = {} # The meta data of the currently open item + self._docHandle = theHandle + self._theItem = self.theProject.projTree[theHandle] + self._fileLoc = None + self._docMeta = {} # Internal Mapping self.makeAlert = self.theParent.makeAlert @@ -68,26 +68,16 @@ class NWDoc(): self._docMeta = {} return - def readDocument(self, tHandle, isOrphan=False): - """Read a document from handle, capturing potential file system - errors and parse meta data. If the document doesn't exist on - disk, return an empty string. If something went wrong, return + def readDocument(self, isOrphan=False): + """Read a document from set handle, capturing potential file + system errors and parse meta data. If the document doesn't exist + on disk, return an empty string. If something went wrong, return None. """ - if not isHandle(tHandle): + if not isHandle(self._docHandle): return None - # Always clear first, since the object will often be reused. - self.clearDocument() - - self._docHandle = tHandle - if not isOrphan: - self._theItem = self.theProject.projTree[tHandle] - else: - self._theItem = None - if self._theItem is None and not isOrphan: - self.clearDocument() return None docFile = self._docHandle+".nwd" @@ -133,7 +123,7 @@ class NWDoc(): """Write the document. The file is saved via a temp file in case of save failure. Returns True if successful, False if not. """ - if self._docHandle is None: + if not isHandle(self._docHandle): return False self.theProject.ensureFolderStructure() @@ -170,14 +160,14 @@ class NWDoc(): return True - def deleteDocument(self, tHandle): + def deleteDocument(self): """Permanently delete a document source file and related files from the project data folder. """ - if not isHandle(tHandle): + if not isHandle(self._docHandle): return False - docFile = tHandle+".nwd" + docFile = self._docHandle+".nwd" chkList = [] chkList.append(os.path.join(self.theProject.projContent, docFile)) diff --git a/nw/core/index.py b/nw/core/index.py index d7b09ec4..16b5f1b8 100644 --- a/nw/core/index.py +++ b/nw/core/index.py @@ -115,8 +115,8 @@ class NWIndex(): if tItem.itemType != nwItemType.FILE: return False - theDoc = NWDoc(self.theProject) - theText = theDoc.readDocument(tHandle) + theDoc = NWDoc(self.theProject, tHandle) + theText = theDoc.readDocument() if theText: self.scanText(tHandle, theText) diff --git a/nw/core/project.py b/nw/core/project.py index e0e978ee..7c95b997 100644 --- a/nw/core/project.py +++ b/nw/core/project.py @@ -265,9 +265,6 @@ class NWProject(): if self.bookAuthors: titlePage = "%s%s %s\n" % (titlePage, self.tr("By"), self.getAuthors()) - # Document object for writing files - aDoc = NWDoc(self) - if popMinimal: # Creating a minimal project with a few root folders and a # single chapter folder with a single file. @@ -284,17 +281,14 @@ class NWProject(): self.projTree.setFileItemLayout(xHandle[5], nwItemLayout.TITLE) self.projTree.setFileItemLayout(xHandle[7], nwItemLayout.CHAPTER) - aDoc.readDocument(xHandle[5]) + aDoc = NWDoc(self, xHandle[5]) aDoc.writeDocument(titlePage) - aDoc.clearDocument() - aDoc.readDocument(xHandle[7]) + aDoc = NWDoc(self, xHandle[7]) aDoc.writeDocument("## %s\n\n" % self.tr("New Chapter")) - aDoc.clearDocument() - aDoc.readDocument(xHandle[8]) + aDoc = NWDoc(self, xHandle[8]) aDoc.writeDocument("### %s\n\n" % self.tr("New Scene")) - aDoc.clearDocument() elif popCustom: # Create a project structure based on selected root folders @@ -311,9 +305,8 @@ class NWProject(): tHandle = self.newFile(self.tr("Title Page"), nwItemClass.NOVEL, nHandle) self.projTree.setFileItemLayout(tHandle, nwItemLayout.TITLE) - aDoc.readDocument(tHandle) + aDoc = NWDoc(self, tHandle) aDoc.writeDocument(titlePage) - aDoc.clearDocument() # Create chapters and scenes numChapters = projData.get("numChapters", 0) @@ -331,9 +324,8 @@ class NWProject(): cHandle = self.newFile(chTitle, nwItemClass.NOVEL, pHandle) self.projTree.setFileItemLayout(cHandle, nwItemLayout.CHAPTER) - aDoc.readDocument(cHandle) + aDoc = NWDoc(self, cHandle) aDoc.writeDocument("## %s\n\n" % chTitle) - aDoc.clearDocument() # Create chapter scenes if numScenes > 0: @@ -341,9 +333,8 @@ class NWProject(): scTitle = self.tr("Scene {0}").format(f"{ch+1:d}.{sc+1:d}") sHandle = self.newFile(scTitle, nwItemClass.NOVEL, pHandle) - aDoc.readDocument(sHandle) + aDoc = NWDoc(self, sHandle) aDoc.writeDocument("### %s\n\n" % scTitle) - aDoc.clearDocument() # Create scenes (no chapters) elif numScenes > 0: @@ -351,9 +342,8 @@ class NWProject(): scTitle = self.tr("Scene {0}").format(f"{sc+1:d}") sHandle = self.newFile(scTitle, nwItemClass.NOVEL, nHandle) - aDoc.readDocument(sHandle) + aDoc = NWDoc(self, sHandle) aDoc.writeDocument("### %s\n\n" % scTitle) - aDoc.clearDocument() # Finalise if popCustom or popMinimal: @@ -1393,7 +1383,6 @@ class NWProject(): return # Handle orphans - aDoc = NWDoc(self) nOrph = 0 noWhere = False oPrefix = self.tr("Recovered") @@ -1404,7 +1393,9 @@ class NWProject(): oParent = None oClass = None oLayout = None - if aDoc.readDocument(oHandle, isOrphan=True) is not None: + + aDoc = NWDoc(self, oHandle) + if aDoc.readDocument(isOrphan=True) is not None: oName, oParent, oClass, oLayout = aDoc.getMeta() if oName: diff --git a/nw/core/tokenizer.py b/nw/core/tokenizer.py index d04ffe47..583eb948 100644 --- a/nw/core/tokenizer.py +++ b/nw/core/tokenizer.py @@ -284,8 +284,8 @@ class Tokenizer(): self.theText = theText else: # Otherwise, load it from file - theDoc = NWDoc(self.theProject) - theText = theDoc.readDocument(theHandle) + theDoc = NWDoc(self.theProject, theHandle) + theText = theDoc.readDocument() if theText: self.theText = theText diff --git a/nw/dialogs/docmerge.py b/nw/dialogs/docmerge.py index 80c0f0e6..ede75adc 100644 --- a/nw/dialogs/docmerge.py +++ b/nw/dialogs/docmerge.py @@ -107,10 +107,10 @@ class GuiDocMerge(QDialog): ) return - theDoc = NWDoc(self.theProject) theText = "" for tHandle in finalOrder: - docText = theDoc.readDocument(tHandle).rstrip("\n") + inDoc = NWDoc(self.theProject, tHandle) + docText = inDoc.readDocument().rstrip("\n") if docText: theText += docText+"\n\n" @@ -131,8 +131,9 @@ class GuiDocMerge(QDialog): newItem = self.theProject.projTree[nHandle] newItem.setStatus(srcItem.itemStatus) - theDoc.readDocument(nHandle) - theDoc.writeDocument(theText) + outDoc = NWDoc(self.theProject, nHandle) + outDoc.writeDocument(theText) + self.theParent.treeView.revealNewTreeItem(nHandle) self.theParent.openDocument(nHandle, doScroll=True) diff --git a/nw/dialogs/docsplit.py b/nw/dialogs/docsplit.py index 1944c875..2c8b1271 100644 --- a/nw/dialogs/docsplit.py +++ b/nw/dialogs/docsplit.py @@ -127,8 +127,8 @@ class GuiDocSplit(QDialog): ) return - theDoc = NWDoc(self.theProject) - theText = theDoc.readDocument(self.sourceItem) + inDoc = NWDoc(self.theProject, self.sourceItem) + theText = inDoc.readDocument() if theText is None: theText = "" @@ -217,9 +217,10 @@ class GuiDocSplit(QDialog): theText = "\n".join(theLines[iStart:iEnd]) theText = theText.rstrip("\n") + "\n\n" - theDoc.readDocument(nHandle) - theDoc.writeDocument(theText) - theDoc.clearDocument() + + outDoc = NWDoc(self.theProject, nHandle) + outDoc.writeDocument(theText) + self.theParent.treeView.revealNewTreeItem(nHandle) self._doClose() @@ -259,8 +260,8 @@ class GuiDocSplit(QDialog): return self.listBox.clear() - theDoc = NWDoc(self.theProject) - theText = theDoc.readDocument(self.sourceItem) + inDoc = NWDoc(self.theProject, self.sourceItem) + theText = inDoc.readDocument() if theText is None: theText = "" diff --git a/nw/gui/doceditor.py b/nw/gui/doceditor.py index 759c0053..73c6c41e 100644 --- a/nw/gui/doceditor.py +++ b/nw/gui/doceditor.py @@ -75,7 +75,7 @@ class GuiDocEditor(QTextEdit): self.theTheme = theParent.theTheme self.theIndex = theParent.theIndex self.theProject = theParent.theProject - self.nwDocument = NWDoc(self.theProject) + self.nwDocument = NWDoc(self.theProject, None) self.docChanged = False # Flag for changed status of document self.spellCheck = False # Flag for spell checking enabled @@ -165,7 +165,7 @@ class GuiDocEditor(QTextEdit): """Clear the current document and reset all document related flags and counters. """ - self.nwDocument.clearDocument() + self.nwDocument = NWDoc(self.theProject, None) self.setReadOnly(True) self.clear() self.wcTimer.stop() @@ -297,7 +297,9 @@ class GuiDocEditor(QTextEdit): document is new (empty string), we set up the editor for editing the file. """ - theDoc = self.nwDocument.readDocument(tHandle) + self.nwDocument = NWDoc(self.theProject, tHandle) + + theDoc = self.nwDocument.readDocument() if theDoc is None: # There was an io error self.clearEditor() diff --git a/nw/gui/projtree.py b/nw/gui/projtree.py index 84415f80..6cd6a580 100644 --- a/nw/gui/projtree.py +++ b/nw/gui/projtree.py @@ -286,8 +286,8 @@ class GuiProjectTree(QTreeWidget): return True # This is a new files, so let's add some content - newDoc = NWDoc(self.theProject) - curTxt = newDoc.readDocument(tHandle) + newDoc = NWDoc(self.theProject, tHandle) + curTxt = newDoc.readDocument() if curTxt is None: curTxt = "" @@ -527,8 +527,8 @@ class GuiProjectTree(QTreeWidget): if self.theParent.docEditor.theHandle == tHandle: self.theParent.closeDocument() - theDoc = NWDoc(self.theProject) - theDoc.deleteDocument(tHandle) + delDoc = NWDoc(self.theProject, tHandle) + delDoc.deleteDocument() self.theIndex.deleteHandle(tHandle) self._deleteTreeItem(tHandle) self._setTreeChanged(True) From 0eb09a2136040c860e753a104c7aed7460bfba6d Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 25 Apr 2021 23:21:51 +0200 Subject: [PATCH 02/12] Move error reporting out of the NWDoc class --- nw/core/document.py | 33 ++++++++++++++++++--------------- nw/dialogs/docmerge.py | 10 +++++++++- nw/dialogs/docsplit.py | 12 +++++++++++- nw/gui/doceditor.py | 7 ++++++- nw/gui/projtree.py | 7 ++++++- 5 files changed, 50 insertions(+), 19 deletions(-) diff --git a/nw/core/document.py b/nw/core/document.py index 4607ebe0..44f94203 100644 --- a/nw/core/document.py +++ b/nw/core/document.py @@ -27,11 +27,7 @@ along with this program. If not, see . import logging import os -from functools import partial - -from PyQt5.QtCore import QCoreApplication - -from nw.enum import nwAlert, nwItemLayout, nwItemClass +from nw.enum import nwItemLayout, nwItemClass from nw.common import isHandle logger = logging.getLogger(__name__) @@ -41,17 +37,13 @@ class NWDoc(): def __init__(self, theProject, theHandle): self.theProject = theProject - self.theParent = theProject.theParent # Internal Variables self._docHandle = theHandle self._theItem = self.theProject.projTree[theHandle] self._fileLoc = None self._docMeta = {} - - # Internal Mapping - self.makeAlert = self.theParent.makeAlert - self.tr = partial(QCoreApplication.translate, "NWDoc") + self._docError = "" return @@ -74,10 +66,13 @@ class NWDoc(): on disk, return an empty string. If something went wrong, return None. """ + self._docError = "" if not isHandle(self._docHandle): + self._docError = "No document handle set." return None if self._theItem is None and not isOrphan: + self._docError = "Unknown novelWriter document." return None docFile = self._docHandle+".nwd" @@ -105,12 +100,13 @@ class NWDoc(): theText += inFile.read() except Exception as e: - self.makeAlert([self.tr("Failed to open document file."), str(e)], nwAlert.ERROR) + self._docError = str(e) # Note: Document must be cleared in case of an io error, # or else the auto-save or save will try to overwrite it # with an empty file. Return None to alert the caller. self.clearDocument() return None + else: # The document file does not exist, so we assume it's a new # document and initialise an empty text string. @@ -123,7 +119,9 @@ class NWDoc(): """Write the document. The file is saved via a temp file in case of save failure. Returns True if successful, False if not. """ + self._docError = "" if not isHandle(self._docHandle): + self._docError = "No document handle set." return False self.theProject.ensureFolderStructure() @@ -149,7 +147,7 @@ class NWDoc(): outFile.write(docMeta) outFile.write(docText) except Exception as e: - self.makeAlert([self.tr("Could not save document."), str(e)], nwAlert.ERROR) + self._docError = str(e) return False # If we're here, the file was successfully saved, so we can @@ -164,7 +162,9 @@ class NWDoc(): """Permanently delete a document source file and related files from the project data folder. """ + self._docError = "" if not isHandle(self._docHandle): + self._docError = "No document handle set." return False docFile = self._docHandle+".nwd" @@ -179,9 +179,7 @@ class NWDoc(): os.unlink(chkFile) logger.debug("Deleted: %s" % chkFile) except Exception as e: - self.makeAlert( - [self.tr("Could not delete document file."), str(e)], nwAlert.ERROR - ) + self._docError = str(e) return False return True @@ -211,6 +209,11 @@ class NWDoc(): return theName, theParent, theClass, theLayout + def getError(self): + """Return the last recorded exception. + """ + return self._docError + ## # Internal Functions ## diff --git a/nw/dialogs/docmerge.py b/nw/dialogs/docmerge.py index ede75adc..b873575a 100644 --- a/nw/dialogs/docmerge.py +++ b/nw/dialogs/docmerge.py @@ -111,6 +111,11 @@ class GuiDocMerge(QDialog): for tHandle in finalOrder: inDoc = NWDoc(self.theProject, tHandle) docText = inDoc.readDocument().rstrip("\n") + docErr = inDoc.getError() + if docText is None and docErr: + self.makeAlert( + [self.tr("Failed to open document file."), docErr], nwAlert.ERROR + ) if docText: theText += docText+"\n\n" @@ -132,7 +137,10 @@ class GuiDocMerge(QDialog): newItem.setStatus(srcItem.itemStatus) outDoc = NWDoc(self.theProject, nHandle) - outDoc.writeDocument(theText) + if not outDoc.writeDocument(theText): + self.theParent.makeAlert( + [self.tr("Could not save document."), outDoc.getError()], nwAlert.ERROR + ) self.theParent.treeView.revealNewTreeItem(nHandle) self.theParent.openDocument(nHandle, doScroll=True) diff --git a/nw/dialogs/docsplit.py b/nw/dialogs/docsplit.py index 2c8b1271..d284056f 100644 --- a/nw/dialogs/docsplit.py +++ b/nw/dialogs/docsplit.py @@ -129,6 +129,13 @@ class GuiDocSplit(QDialog): inDoc = NWDoc(self.theProject, self.sourceItem) theText = inDoc.readDocument() + + docErr = inDoc.getError() + if theText is None and docErr: + self.theParent.makeAlert( + [self.tr("Failed to open document file."), docErr], nwAlert.ERROR + ) + if theText is None: theText = "" @@ -219,7 +226,10 @@ class GuiDocSplit(QDialog): theText = theText.rstrip("\n") + "\n\n" outDoc = NWDoc(self.theProject, nHandle) - outDoc.writeDocument(theText) + if not outDoc.writeDocument(theText): + self.theParent.makeAlert( + [self.tr("Could not save document."), outDoc.getError()], nwAlert.ERROR + ) self.theParent.treeView.revealNewTreeItem(nHandle) diff --git a/nw/gui/doceditor.py b/nw/gui/doceditor.py index 73c6c41e..3a9fe5c4 100644 --- a/nw/gui/doceditor.py +++ b/nw/gui/doceditor.py @@ -446,7 +446,12 @@ class GuiDocEditor(QTextEdit): theItem.setParaCount(self.paraCount) self.saveCursorPosition() - self.nwDocument.writeDocument(docText) + if not self.nwDocument.writeDocument(docText): + self.theParent.makeAlert([ + self.tr("Could not save document."), self.nwDocument.getError() + ], nwAlert.ERROR) + return False + self.setDocumentChanged(False) self.theIndex.scanText(tHandle, docText) diff --git a/nw/gui/projtree.py b/nw/gui/projtree.py index 6cd6a580..03f5c0c5 100644 --- a/nw/gui/projtree.py +++ b/nw/gui/projtree.py @@ -528,7 +528,12 @@ class GuiProjectTree(QTreeWidget): self.theParent.closeDocument() delDoc = NWDoc(self.theProject, tHandle) - delDoc.deleteDocument() + if not delDoc.deleteDocument(): + self.makeAlert([ + self.tr("Could not delete document file."), delDoc.getError() + ], nwAlert.ERROR) + return False + self.theIndex.deleteHandle(tHandle) self._deleteTreeItem(tHandle) self._setTreeChanged(True) From bd2886780440ca8a7d10a453a7b81b6673efd7cf Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 25 Apr 2021 23:22:05 +0200 Subject: [PATCH 03/12] Update tests --- tests/dummy.py | 4 +-- tests/test_core/test_core_document.py | 46 ++++++++++++++------------ tests/test_core/test_core_tokenizer.py | 6 ++-- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/tests/dummy.py b/tests/dummy.py index 653fca58..14f2ef91 100644 --- a/tests/dummy.py +++ b/tests/dummy.py @@ -107,7 +107,7 @@ class DummyApp: # =========================================================================== # def causeOSError(*args, **kwargs): - raise OSError + raise OSError("OSError") def causeException(*args, **kwargs): - raise Exception + raise Exception("Exception") diff --git a/tests/test_core/test_core_document.py b/tests/test_core/test_core_document.py index 056b212e..d44b3a08 100644 --- a/tests/test_core/test_core_document.py +++ b/tests/test_core/test_core_document.py @@ -26,7 +26,6 @@ import pytest from dummy import causeOSError from nw.core import NWProject, NWDoc -from nw.core.item import NWItem from nw.enum import nwItemClass, nwItemLayout @pytest.mark.core @@ -37,39 +36,37 @@ def testCoreDocument_LoadSave(monkeypatch, dummyGUI, nwMinimal): assert theProject.openProject(nwMinimal) assert theProject.projPath == nwMinimal - theDoc = NWDoc(theProject) sHandle = "8c659a11cd429" # Not a valid handle - assert theDoc.readDocument("dummy") is None + theDoc = NWDoc(theProject, "dummy") + assert theDoc.readDocument() is None # Non-existent handle - assert theDoc.readDocument("0000000000000") is None + theDoc = NWDoc(theProject, "0000000000000") + assert theDoc.readDocument() is None # Cause open() to fail while loading - def dummyOpen(*args, **kwargs): - raise OSError - with monkeypatch.context() as mp: - mp.setattr("builtins.open", dummyOpen) - assert theDoc.readDocument(sHandle) is None + mp.setattr("builtins.open", causeOSError) + theDoc = NWDoc(theProject, sHandle) + assert theDoc.readDocument() is None + assert theDoc.getError() == "OSError" # Load the text - assert theDoc.readDocument(sHandle) == "### New Scene\n\n" + theDoc = NWDoc(theProject, sHandle) + assert theDoc.readDocument() == "### New Scene\n\n" # Try to open a new (non-existent) file nHandle = theProject.projTree.findRoot(nwItemClass.NOVEL) assert nHandle is not None xHandle = theProject.newFile("New File", nwItemClass.NOVEL, nHandle) - assert theDoc.readDocument(xHandle) == "" - - # Check cached item - assert isinstance(theDoc._theItem, NWItem) - assert theDoc.readDocument(xHandle, isOrphan=True) == "" - assert theDoc._theItem is None + theDoc = NWDoc(theProject, xHandle) + assert theDoc.readDocument() == "" # Set handle and save again theText = "### Test File\n\nText ...\n\n" + theDoc = NWDoc(theProject, xHandle) assert theDoc.readDocument(xHandle) == "" assert theDoc.writeDocument(theText) @@ -98,22 +95,27 @@ def testCoreDocument_LoadSave(monkeypatch, dummyGUI, nwMinimal): with monkeypatch.context() as mp: mp.setattr("builtins.open", causeOSError) assert not theDoc.writeDocument(theText) + assert theDoc.getError() == "OSError" # Saving with no handle theDoc.clearDocument() assert not theDoc.writeDocument(theText) # Delete the last document - assert not theDoc.deleteDocument("dummy") + theDoc = NWDoc(theProject, "dummy") + assert not theDoc.deleteDocument() assert os.path.isfile(docPath) # Cause the delete to fail with monkeypatch.context() as mp: mp.setattr("os.unlink", causeOSError) - assert not theDoc.deleteDocument(xHandle) + theDoc = NWDoc(theProject, xHandle) + assert not theDoc.deleteDocument() + assert theDoc.getError() == "OSError" # Make the delete pass - assert theDoc.deleteDocument(xHandle) + theDoc = NWDoc(theProject, xHandle) + assert theDoc.deleteDocument() assert not os.path.isfile(docPath) # END Test testCoreDocument_Load @@ -126,11 +128,11 @@ def testCoreDocument_Methods(monkeypatch, dummyGUI, nwMinimal): assert theProject.openProject(nwMinimal) assert theProject.projPath == nwMinimal - theDoc = NWDoc(theProject) sHandle = "8c659a11cd429" + theDoc = NWDoc(theProject, sHandle) docPath = os.path.join(nwMinimal, "content", sHandle+".nwd") - assert theDoc.readDocument(sHandle) == "### New Scene\n\n" + assert theDoc.readDocument() == "### New Scene\n\n" # Check location assert theDoc.getFileLocation() == docPath @@ -158,6 +160,6 @@ def testCoreDocument_Methods(monkeypatch, dummyGUI, nwMinimal): "Text ...\n\n" ) - assert theDoc.readDocument(sHandle) == "### Test File\n\nText ...\n\n" + assert theDoc.readDocument() == "### Test File\n\nText ...\n\n" # END Test testCoreDocument_Methods diff --git a/tests/test_core/test_core_tokenizer.py b/tests/test_core/test_core_tokenizer.py index 6d13faee..e766450b 100644 --- a/tests/test_core/test_core_tokenizer.py +++ b/tests/test_core/test_core_tokenizer.py @@ -137,10 +137,8 @@ def testCoreToken_TextOps(monkeypatch, nwMinimal, dummyGUI): ) docTextR = docText.replace("", "this").replace("", "that") - nDoc = NWDoc(theProject) - nDoc.readDocument(sHandle) - nDoc.writeDocument(docText) - nDoc.clearDocument() + nDoc = NWDoc(theProject, sHandle) + assert nDoc.writeDocument(docText) theProject.setAutoReplace({"A": "this", "B": "that"}) From e7102725bd2d723a83c9e756fa699b24a0cbb004 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 25 Apr 2021 23:24:21 +0200 Subject: [PATCH 04/12] Update translations --- i18n/nw_en_US.ts | 288 ++++++++++++++++++++++++----------------------- i18n/nw_fr.ts | 286 ++++++++++++++++++++++++---------------------- i18n/nw_nb_NO.ts | 286 ++++++++++++++++++++++++---------------------- i18n/nw_pt.ts | 286 ++++++++++++++++++++++++---------------------- 4 files changed, 597 insertions(+), 549 deletions(-) diff --git a/i18n/nw_en_US.ts b/i18n/nw_en_US.ts index fb56ab76..6dff7f40 100644 --- a/i18n/nw_en_US.ts +++ b/i18n/nw_en_US.ts @@ -798,22 +798,22 @@ GuiDocEditFooter - + Status - + Line: {0} ({1}) - + Words: {0} ({1}) - + Document size is {0} bytes @@ -821,22 +821,22 @@ GuiDocEditHeader - + Edit document meta - + Search document - + Toggle Focus Mode - + Close the document @@ -844,97 +844,97 @@ GuiDocEditSearch - + Search - + Replace - + Case Sensitive - + Match case - + Whole Words Only - + Match whole words - + RegEx Mode - + Search using regular expressions - + Loop Search - + Loop the search when reaching the end - + Search Next File - + Continue searching in the next file - + Preserve Case - + Preserve case on replace - + Close Search - + Close the search box [{0}] - + Show/hide the replace text box - + Find in current document - + Find and replace in current document @@ -942,99 +942,104 @@ GuiDocEditor - + The document you are trying to open is too big. The document size is {0} MB. The maximum size allowed is {1} MB. - + The text you are trying to add is too big. The text size is {0} MB. The maximum size allowed is {1} MB. - + Spell check complete - + File Location - + The currently open file is saved in: - + The document has grown too big and you cannot add more text to it. The maximum size of a single novelWriter document is {0} MB. - + Follow Tag - + Cut - + Copy - + Paste - + Select All - + Select Word - + Select Paragraph - + Spelling Suggestion(s) - + No Suggestions - + Add Word to Dictionary - + Please select some text before calling replace quotes. - + Opened Document: {0} - + Saved Document: {0} - + + + + + Could not save document. + @@ -1060,25 +1065,35 @@ - + No source document selected. Nothing to do. - + Could not parse source document. - + Element selected in the project tree must be a folder. + + + Failed to open document file. + + + + + Could not save document. + + GuiDocSplit - + Split Document @@ -1123,30 +1138,40 @@ - + No headers found. Nothing to do. - + Cannot add new folder for the document split. Maximum folder depth has been reached. Please move the file to another level in the project tree. - + The document will be split into {0} file(s) in a new folder. The original document will remain intact. - + Continue with the splitting process? - + Element selected in the project tree must be a file. + + + Failed to open document file. + + + + + Could not save document. + + GuiDocViewFooter @@ -3970,7 +3995,7 @@ - + Delete File @@ -3980,80 +4005,85 @@ - + Move file '{0}' to Trash? - + Cannot delete folder. It is not empty. Recursive deletion is not supported. Please delete the content first. - + Cannot delete root folder. It is not empty. Recursive deletion is not supported. Please delete the content first. - + The item cannot be moved to that location. - + There is nowhere to add item with name '{0}'. + + + Could not delete document file. + + GuiProjectTreeMenu - + Edit Project Item - + Open Document - + View Document - + Toggle Included Flag - + New File - + New Folder - + Delete Item - + Empty Trash - + Move Item Up - + Move Item Down @@ -4242,24 +4272,6 @@ - - NWDoc - - - Failed to open document file. - - - - - Could not save document. - - - - - Could not delete document file. - - - NWProject @@ -4318,242 +4330,242 @@ - + Novel - + Plot - + Characters - + World - + Title Page - + New Chapter - + New Scene - + Chapter {0} - + Scene {0} - + File not found: {0} - + Failed to parse project xml. - + Attempting to open backup project file instead. - + Unknown - + Project file does not appear to be a novelWriterXML file. - + Unknown or unsupported novelWriter project file format. The project cannot be opened by this version of novelWriter. The file was saved with novelWriter version {0}. - + Version Conflict - + This project was saved by a newer version of novelWriter, version {0}. This is version {1}. If you continue to open the project, some attributes and settings may not be preserved, but the overall project should be fine. Continue opening the project? - + Opened Project: {0} - + Project path not set, cannot save project. - + Failed to save project. - + Saved Project: {0} - + Backing up project ... - + Cannot backup project because no backup path is set. Please set a valid backup location in Tools > Preferences. - + Cannot backup project because no project name is set. Please set a Working Title in Project > Project Settings. - + Cannot backup project because the backup path does not exist. Please set a valid backup location in Tools > Preferences. - + Could not create backup folder. - + Cannot backup project because the backup path is within the project folder to be backed up. Please choose a different backup path in Tools > Preferences. - + Backup from {0} - + Backup archive file written to: {0} - + Could not write backup archive. - + Project backed up to '{0}' - + Failed to create a new example project. - + Failed to create a new example project. Could not find the necessary files. They seem to be missing from this installation. - + Could not create new project folder. - + New project folder is not empty. Each project requires a dedicated project folder. - + You must set a valid backup path in Preferences to use the automatic project backup feature. - + You must set a valid project name in Project Settings to use the automatic project backup feature. - + and - + Found {0} orphaned file(s) in project folder. - + Recovered - + [{0}] {1} - + Recovered File {0} - + One or more orphaned files could not be added back into the project. Make sure at least a Novel root folder exists. - + Not a folder: {0} - + Could not move: {0} - + Could not delete: {0} - + Could not make folder: {0} - + Could not move item {0} to {1}. diff --git a/i18n/nw_fr.ts b/i18n/nw_fr.ts index e3630f05..09bac02b 100644 --- a/i18n/nw_fr.ts +++ b/i18n/nw_fr.ts @@ -798,22 +798,22 @@ GuiDocEditFooter - + Status État - + Line: {0} ({1}) Ligne: {0} ({1}) - + Words: {0} ({1}) Mots: {0} ({1}) - + Document size is {0} bytes La taille du document est de {0} octets @@ -821,22 +821,22 @@ GuiDocEditHeader - + Edit document meta Modifier les métadonnées du document - + Search document Chercher dans le document - + Toggle Focus Mode Basculer le mode focus - + Close the document Fermer le document @@ -844,97 +844,97 @@ GuiDocEditSearch - + Search Chercher - + Replace Remplacer - + Case Sensitive Sensible à la casse - + Match case Respecter la casse - + Whole Words Only Mots entiers uniquement - + Match whole words Ne vérifier la correspondance que sur des mots entiers - + RegEx Mode Expressions régulières - + Search using regular expressions Chercher en utilisant des expressions régulières - + Loop Search Recherche en boucle - + Loop the search when reaching the end Reprendre la recherche au début du texte lorsque la fin est atteinte - + Search Next File Chercher dans le fichier suivant - + Continue searching in the next file Continuer la recherche dans le fichier suivant - + Preserve Case Conserver la casse - + Preserve case on replace Conserver la casse lors d'un remplacement - + Close Search Terminer la recherche - + Close the search box [{0}] Fermer la boîte de recherche [{0}] - + Show/hide the replace text box Montrer/cacher le texte de remplacement - + Find in current document Chercher dans le document actuel - + Find and replace in current document Chercher et remplacer dans le document actuel @@ -942,100 +942,105 @@ GuiDocEditor - + The document you are trying to open is too big. The document size is {0} MB. The maximum size allowed is {1} MB. Le document que vous essayez d'ouvrir est trop grand. La taille du document est de {0} MB alors que la taille maximale est de {1} MB. - + The text you are trying to add is too big. The text size is {0} MB. The maximum size allowed is {1} MB. Le texte que vous voulez ajouter est trop grand. La taille du texte est de {0} MB alors que la taille maximale est de {1} MB. - + Spell check complete La vérification orthographique est terminée - + File Location Emplacement du fichier - + The currently open file is saved in: Le fichier actuellement ouvert est enregistré dans : - + The document has grown too big and you cannot add more text to it. The maximum size of a single novelWriter document is {0} MB. Le document est devenu trop grand et vous ne pouvez plus lui ajouter de texte. La taille maximale d'un fichier novelWriter est de {0} MB. - + Follow Tag Suivre cette étiquette - + Cut Couper - + Copy Copier - + Paste Coller - + Select All Sélectionner tout - + Select Word Sélectionner le mot - + Select Paragraph Sélectionner le paragraphe - + Spelling Suggestion(s) Orthographe suggérée - + No Suggestions Pas de suggestion - + Add Word to Dictionary Ajouter ce mot au dictionnaire - + Please select some text before calling replace quotes. Veuillez sélectionner du texte avant de demander le remplacement des guillemets. - + Opened Document: {0} Document ouvert : {0} - + Saved Document: {0} Document enregistré : {0} + + + Could not save document. + Impossible d'enregistrer le document. + GuiDocMerge @@ -1060,25 +1065,35 @@ Pas de document source trouvé. Aucune action. - + No source document selected. Nothing to do. Pas de document source sélectionné. Aucune action. - + Could not parse source document. Impossible d'interpréter le nom du document source. - + Element selected in the project tree must be a folder. L'élement selectionné dans l'arborescence doit être un dossier. + + + Failed to open document file. + Impossible d'ouvrir le document. + + + + Could not save document. + Impossible d'enregistrer le document. + GuiDocSplit - + Split Document Découper un document @@ -1123,30 +1138,40 @@ Impossible d'interpréter le nom du document source. - + No headers found. Nothing to do. Pas d'en-tête trouvé. Aucune action. - + Cannot add new folder for the document split. Maximum folder depth has been reached. Please move the file to another level in the project tree. Impossible d'ajouter un nouveau dossier lors du découpage. Le nombre maximum de dossiers a été atteint. Veuillez placer ce fichier à un autre niveau dans l'arborescence. - + The document will be split into {0} file(s) in a new folder. The original document will remain intact. Ce document va être découpé en {0} fichier(s) dans un nouveau dossier. Le document d'origine restera intact. - + Continue with the splitting process? Continuer le découpage ? - + Element selected in the project tree must be a file. L'élément sélectionné dans l'arborescence doit être un fichier. + + + Failed to open document file. + Impossible d'ouvrir le document. + + + + Could not save document. + Impossible d'enregistrer le document. + GuiDocViewFooter @@ -3970,7 +3995,7 @@ Effacer définitivement {0} fichier(s) dans la Corbeille ? - + Delete File Effacer un fichier @@ -3980,80 +4005,85 @@ Effacer définitivement le fichier '{0}' ? - + Move file '{0}' to Trash? Mettre le fichier '{0}' dans la Corbeille ? - + Cannot delete folder. It is not empty. Recursive deletion is not supported. Please delete the content first. Impossible d'effacer le dossier car il n'est pas vide. Les effacements récursifs n'étant pas permis vous devez d'abord effacer le contenu. - + Cannot delete root folder. It is not empty. Recursive deletion is not supported. Please delete the content first. Impossible d'effacer le dossier racine car il n'est pas vide. Les effacements récursifs n'étant pas permis vous devez d'abord effacer le contenu. - + The item cannot be moved to that location. Impossible de déplacer cet item vers cet emplacement. - + There is nowhere to add item with name '{0}'. Il n'y a pas d'emplacement pour ajouter l'item nommé '{0}'. + + + Could not delete document file. + Impossible d'effacer le document. + GuiProjectTreeMenu - + Edit Project Item Éditer les caractéristiques - + Open Document Ouvrir ce document - + View Document Afficher ce document - + Toggle Included Flag Basculer le marqueur d'inclusion - + New File Nouveau fichier - + New Folder Nouveau dossier - + Delete Item Supprimer ce composant - + Empty Trash Vider la corbeille - + Move Item Up Faire monter ce composant - + Move Item Down Faire descendre ce composant @@ -4242,24 +4272,6 @@ Impossible de lire le fichier log de la session. - - NWDoc - - - Failed to open document file. - Impossible d'ouvrir le document. - - - - Could not save document. - Impossible d'enregistrer le document. - - - - Could not delete document file. - Impossible d'effacer le document. - - NWProject @@ -4318,242 +4330,242 @@ Par - + Novel Roman - + Plot Intrigue - + Characters Personnages - + World Monde - + Title Page Page de titre - + New Chapter Nouveau chapitre - + New Scene Nouvelle scène - + Chapter {0} Chapitre{0} - + Scene {0} Scène {0} - + File not found: {0} Fichier introuvable : {0} - + Failed to parse project xml. Impossible de décoder le xml du projet. - + Attempting to open backup project file instead. Essai d'ouverture depuis le fichier de sauvegarde du projet. - + Unknown Inconnu - + Project file does not appear to be a novelWriterXML file. Ce fichier projet ne semble pas être un fichier novelWriterXML. - + Unknown or unsupported novelWriter project file format. The project cannot be opened by this version of novelWriter. The file was saved with novelWriter version {0}. Format de projet novelWriter inconnu ou non supporté. Ce projet ne peut pas être ouvert avec cette version de novelWriter, il a été enregistré avec novelWriter version {0}. - + Version Conflict Conflit de version - + This project was saved by a newer version of novelWriter, version {0}. This is version {1}. If you continue to open the project, some attributes and settings may not be preserved, but the overall project should be fine. Continue opening the project? Ce projet a été enregistré par une version plus récente de novelWriter, la version {0}. Ceci est la version {1}. Si vous ouvrez quand même ce projet, certaines propriétés ou certains réglages risquent d'être perdus, toutefois le projet dans son ensemble devrait être intact. Voulez-vous quand même ouvrir ce projet ? - + Opened Project: {0} Projet ouvert : {0} - + Project path not set, cannot save project. L'emplacement du projet n'est pas défini, il est impossible de l'enregistrer. - + Failed to save project. Impossible d'enregistrer le projet. - + Saved Project: {0} Projet enregistré : {0} - + Backing up project ... Sauvegarde du projet en cours ... - + Cannot backup project because no backup path is set. Please set a valid backup location in Tools > Preferences. Il est impossible de sauvegarder le projet car aucun emplacement de sauvegarde n'a été défini. Veuillez en définir un dans Outils > Préférences. - + Cannot backup project because no project name is set. Please set a Working Title in Project > Project Settings. Il est impossible de sauvegarder le projet car il n'a pas reçu de nom. Veuillez définir un titre de travail dans Projet > Caractéristiques du projet. - + Cannot backup project because the backup path does not exist. Please set a valid backup location in Tools > Preferences. Il est impossible de sauvegarder le projet car l'emplacement de sauvegarde défini n'existe pas. Veuillez définir un emplacement correct dans Outils > Préférences. - + Could not create backup folder. Il n'a pas été possible de créer le répertoire de sauvegarde. - + Cannot backup project because the backup path is within the project folder to be backed up. Please choose a different backup path in Tools > Preferences. La sauvegarde du projet est impossible car l'emplacement défini est situé dans le dossier à sauvegarder. Veuillez définir un autre répertoire de sauvegarde dans Outils > Préférences. - + Backup from {0} Sauvegarde depuis {0} - + Backup archive file written to: {0} Archivage du fichier de sauvegarde effectué en : {0} - + Could not write backup archive. Il n'a pas été possible d'écrire l'archive de sauvegarde. - + Project backed up to '{0}' Projet sauvegardé en '{0}' - + Failed to create a new example project. Il n'a pas été possible de créer un nouveau projet exemple. - + Failed to create a new example project. Could not find the necessary files. They seem to be missing from this installation. Il n'a pas été possible de créer un nouveau projet exemple. Il semble que les fichiers nécessaires soient manquants dans cette installation. - + Could not create new project folder. Il n'a pas été possible de créer un nouveau dossier de projet. - + New project folder is not empty. Each project requires a dedicated project folder. Le dossier pour le nouveau projet n'est pas vide. Chaque projet doit résider dans un dossier spécifique. - + You must set a valid backup path in Preferences to use the automatic project backup feature. Vous devez spécifier un répertoire de sauvegarde valide dans les préférences du projet avant d'utiliser la fonction de sauvegarde automatique. - + You must set a valid project name in Project Settings to use the automatic project backup feature. Vous devez spécifier un titre de travail valide dans les préférences du projet avant d'utiliser la fonction de sauvegarde automatique. - + and et - + Found {0} orphaned file(s) in project folder. Trouvé {0} fichier(s) orphelin(s) dans le dossier du projet. - + Recovered Récupéré - + [{0}] {1} [{0}] {1} - + Recovered File {0} Fichier récupéré {0} - + One or more orphaned files could not be added back into the project. Make sure at least a Novel root folder exists. Un ou plusieurs fichiers orphelins n'ont pas pu être repris dans le projet. Vérifiez qu'il y a au moins un dossier racine Roman. - + Not a folder: {0} Pas un dossier : {0} - + Could not move: {0} Pas pu déplacer : {0} - + Could not delete: {0} Pas pu effacer : {0} - + Could not make folder: {0} Pas pu crér le dossier : {0} - + Could not move item {0} to {1}. Pas pu déplacer l'item {0} vers {1}. diff --git a/i18n/nw_nb_NO.ts b/i18n/nw_nb_NO.ts index e8bc9641..db8a69a7 100644 --- a/i18n/nw_nb_NO.ts +++ b/i18n/nw_nb_NO.ts @@ -798,22 +798,22 @@ GuiDocEditFooter - + Status Status - + Line: {0} ({1}) Linje: {0} ({1}) - + Words: {0} ({1}) Ord: {0} ({1}) - + Document size is {0} bytes Dokumentet er {0} byte @@ -821,22 +821,22 @@ GuiDocEditHeader - + Edit document meta Rediger dokumentinstillinger - + Search document Søk i dokumentet - + Toggle Focus Mode Slå av/på "Fokus-modus" - + Close the document Lukk dokumentet @@ -844,97 +844,97 @@ GuiDocEditSearch - + Search Søk - + Replace Erstatt - + Case Sensitive Skill store/små bokstaver - + Match case Søket skiller mellom store og små bokstaver - + Whole Words Only Kun hele ord - + Match whole words Søk kun etter hele ord - + RegEx Mode RegEx-modus - + Search using regular expressions Søk ved hjelp av "regular expressions" - + Loop Search Søk rundt - + Loop the search when reaching the end Begynn søket på nytt når enden er nådd - + Search Next File Søk i neste file - + Continue searching in the next file Fortsett søket i neste fil - + Preserve Case Behold store/små bokstaver - + Preserve case on replace Behold store og små bokstaver på samme sted ved erstatt - + Close Search Lukk søk - + Close the search box [{0}] Lukk søkeboksen [{0}] - + Show/hide the replace text box Vis/skjul erstatt-boksen - + Find in current document Søk i det åpne dokumentet - + Find and replace in current document Søk og erstatt i det åpne dokumentet @@ -942,100 +942,105 @@ GuiDocEditor - + The document you are trying to open is too big. The document size is {0} MB. The maximum size allowed is {1} MB. Dokumentet du prøver å åpne er for stort. Dokumenter er på {0} MB. Den maksimale størrelsen tillat er {1} MB. - + The text you are trying to add is too big. The text size is {0} MB. The maximum size allowed is {1} MB. Teksten du forsøker å legge til er for stor. Teksten er {0} MB. Den maksimale tillatte størrelsen er {1} MB. - + Spell check complete Stavekontrollen er ferdig - + File Location Filens plassering - + The currently open file is saved in: Det åpne dokumentet er lagret på følgende sted: - + The document has grown too big and you cannot add more text to it. The maximum size of a single novelWriter document is {0} MB. Dokumentet har blitt for stort og du kan ikke legge til mer tekst. Den maksimale tillatte størrelsen for et novelWriter-dokument er {0} MB. - + Follow Tag Følg knagg - + Cut Klipp - + Copy Kopier - + Paste Lim inn - + Select All Velg hele teksten - + Select Word Velg hele ordet - + Select Paragraph Velg hele avsnittet - + Spelling Suggestion(s) Forslag fra stavekontrollen - + No Suggestions Ingen forslag - + Add Word to Dictionary Legg til ord i ordbok - + Please select some text before calling replace quotes. Venligst velg en del av teksten før du velger å erstatte sitattegn. - + Opened Document: {0} Åpnet dokument: {0} - + Saved Document: {0} Lagret dokument: {0} + + + Could not save document. + Kunne ikke lagre dokumentet. + GuiDocMerge @@ -1060,25 +1065,35 @@ Ingen kilde-dokument funnet. Det er ingenting å gjøre. - + No source document selected. Nothing to do. Ingen kilde-dokument er valgt. Det er ingenting å gjøre. - + Could not parse source document. Klarte ikke å lese kilde-dokumentet. - + Element selected in the project tree must be a folder. Elementet som er valgt i prosjekttreet må være en mappe. + + + Failed to open document file. + Kunne ikke åpne dokumentets fil. + + + + Could not save document. + Kunne ikke lagre dokumentet. + GuiDocSplit - + Split Document Del opp dokument @@ -1123,30 +1138,40 @@ Klarte ikke å lese kilde-dokumentet. - + No headers found. Nothing to do. Ingen overskrifter ble funnet i dokumentet. Det er ikke noe å gjøre. - + Cannot add new folder for the document split. Maximum folder depth has been reached. Please move the file to another level in the project tree. Kan ikke legge til ny mappe for å dele opp dokumentet. Dokumentet har allerede maksimal dybde i prosjekttreet. Flytt dokumentet til et annet nivå først. - + The document will be split into {0} file(s) in a new folder. The original document will remain intact. Dokumentet vil nå bli delt opp i {0} nye filer i en ny mappe. Det originale dokumentet vil ikke bli endret eller fjernet. - + Continue with the splitting process? Fortsette med oppdelingen? - + Element selected in the project tree must be a file. Elementet som er valgt i prosjekttreet må være et dokument. + + + Failed to open document file. + Kunne ikke åpne dokumentets fil. + + + + Could not save document. + Kunne ikke lagre dokumentet. + GuiDocViewFooter @@ -3965,7 +3990,7 @@ Vil du slette {0} filer i søppel-mappen for godt? - + Delete File Slett fil @@ -3975,22 +4000,22 @@ Slette filen '{0}' for godt? - + Move file '{0}' to Trash? Vil du flytte filen '{0}' til søpla? - + Cannot delete folder. It is not empty. Recursive deletion is not supported. Please delete the content first. Kan ikke slette mappen da den ikke er tom. Rekursiv sletting er ikke støttet. Du må slette innholdet først. - + Cannot delete root folder. It is not empty. Recursive deletion is not supported. Please delete the content first. Kan ikke slette hovedmappen da den ikke er tom. Rekursiv sletting er ikke støttet. Du må slette innholdet først. - + The item cannot be moved to that location. Denne enheten kan ikke flyttes til denne lokasjonen. @@ -4000,60 +4025,65 @@ Kan ikke legge til nye filer eller mapper til søppel-mappen. - + There is nowhere to add item with name '{0}'. Fant ikke noe sted å legge til enheten med navn '{0}'. + + + Could not delete document file. + Kunne ikke slette dokumentets fil. + GuiProjectTreeMenu - + Edit Project Item Endre enhet - + Open Document Åpne dokument - + View Document Vis dokument - + Toggle Included Flag Slå av/på inkludering - + New File Ny fil - + New Folder Ny mappe - + Delete Item Slett enhet - + Empty Trash Tøm søppel - + Move Item Up Flytt enhet opp - + Move Item Down Flytt enhet ned @@ -4242,24 +4272,6 @@ Lagre data som - - NWDoc - - - Failed to open document file. - Kunne ikke åpne dokumentets fil. - - - - Could not save document. - Kunne ikke lagre dokumentet. - - - - Could not delete document file. - Kunne ikke slette dokumentets fil. - - NWProject @@ -4313,237 +4325,237 @@ Av - + Novel Roman - + Plot Plott - + Characters Karakterer - + World Verden - + Title Page Tittelside - + New Chapter Nytt kapittel - + New Scene Ny scene - + Chapter {0} Kapittel {0} - + Scene {0} Scene {0} - + File not found: {0} Fant ikke filen: {0} - + Failed to parse project xml. Kunne ikke lese prosjektets xml-data. - + Attempting to open backup project file instead. Forsøker å åpne prosjektets sekundære prosjektfil istedet. - + Unknown Ukjent - + Project file does not appear to be a novelWriterXML file. Prosjektfilen later ikke til å være en novelWriterXML-fil. - + Unknown or unsupported novelWriter project file format. The project cannot be opened by this version of novelWriter. The file was saved with novelWriter version {0}. Prosjektfilen har et ukjent eller ikke støttet format, og kan ikke åpnes med denne versjonen av novelWriter. Prosjektet ble lagret av novelWriter versjon {0}. - + Version Conflict Versjonskonflikt - + Opened Project: {0} Åpnet prosjekt: {0} - + Project path not set, cannot save project. Prosjektet mangler filbane, og kan ikke lagres. - + Failed to save project. Kunne ikke lagre prosjektet. - + Saved Project: {0} Lagret prosjekt: {0} - + Backing up project ... Lager sikkerhetskopi ... - + Cannot backup project because no backup path is set. Please set a valid backup location in Tools > Preferences. Kan ikke ta sikkerhetskopi av prosjektet da ingen filbane er satt. Du må først sette en filbane i Verktøy > Innstillinger. - + Cannot backup project because no project name is set. Please set a Working Title in Project > Project Settings. Kan ikke ta sikkerhetskopi av prosjektet da ingen arbeidstittel er satt. Du må først sette en arbeidstittel i Prosjekt > Prosjektinnstillinger. - + Cannot backup project because the backup path does not exist. Please set a valid backup location in Tools > Preferences. Kan ikke ta sikkerhetskopi av prosjektet da filbane ikke finnes. Du må sette en ny filbane i Verktøy > Innstillinger. - + Could not create backup folder. Kunne ikke lage mappe til sikkerhetskopi. - + Cannot backup project because the backup path is within the project folder to be backed up. Please choose a different backup path in Tools > Preferences. Kan ikke ta sikkerhetskopi av prosjektet da filbanen er inne i prosjektmappen. Du må sette en ny filbane i Verktøy > Innstillinger. - + Backup from {0} Sikkerhetskopi fra {0} - + Backup archive file written to: {0} Sikkerhetskopi skrevet til: {0} - + Could not write backup archive. Kunne ikke lage sikkerhetskopi. - + Project backed up to '{0}' Sikkerhetskopi skrevet til '{0}' - + Failed to create a new example project. Kunne ikke lage nytt eksempel-prosjekt. - + Failed to create a new example project. Could not find the necessary files. They seem to be missing from this installation. Kunne ikke lage nytt eksempel-prosjekt. Kunne ikke finne de nødvendige filene. De ser ut til å mangle i denne installasjonen. - + Could not create new project folder. Kunne ikke lage ny prosjekt-mappe. - + New project folder is not empty. Each project requires a dedicated project folder. Ny prosjektmappe er ikke tom. Hvert prosjekt trenger sin egen mappe. - + You must set a valid backup path in Preferences to use the automatic project backup feature. Du må sette en gyldig filbane i innstillingene for å kunne bruke automatisk sikkerhetskopi. - + You must set a valid project name in Project Settings to use the automatic project backup feature. Du må sette en gyldig arbeidstittel i prosjektinnstillingene for å kunne bruke automatisk sikkerhetskopi. - + and og - + Found {0} orphaned file(s) in project folder. Fant {0} tapte filer i prosjektmappen. - + Recovered Gjennopprettet - + [{0}] {1} - + Recovered File {0} Gjennopprettet fil {0} - + One or more orphaned files could not be added back into the project. Make sure at least a Novel root folder exists. Én eller flere gjennopprettede filer kunne ikke bli lagt til i posjektet. Pass på at "Roman"-mappen i det minste eksisterer. - + Not a folder: {0} Ikke en mappe: {0} - + Could not move: {0} Kunne ikke flytte: {0} - + Could not delete: {0} Kunne ikke slette: {0} - + Could not make folder: {0} Kunne ikke lage mappe: {0} - + Could not move item {0} to {1}. Kunne ikke flytte {0} til {1}. @@ -4553,7 +4565,7 @@ Kapittel - + This project was saved by a newer version of novelWriter, version {0}. This is version {1}. If you continue to open the project, some attributes and settings may not be preserved, but the overall project should be fine. Continue opening the project? Dette prosjektet ble lagret av en nyere versjon av novelWriter, versjon {0}. Dette er versjon {1}. Hvis du ønsker å fortsette med å åpne prosjektet, kan noen av innstillingene bli borte, men selve prosjektet vil være i orden. Vil du fortsatt åpne prosjektet? diff --git a/i18n/nw_pt.ts b/i18n/nw_pt.ts index b9008aec..bf9bb715 100644 --- a/i18n/nw_pt.ts +++ b/i18n/nw_pt.ts @@ -798,22 +798,22 @@ GuiDocEditFooter - + Line: {0} ({1}) Linha: {0} ({1}) - + Words: {0} ({1}) Palavras: {0} ({1}) - + Status Estado - + Document size is {0} bytes O tamanho do documento é {0} bytes @@ -821,22 +821,22 @@ GuiDocEditHeader - + Edit document meta Editar os meta-dados do documento - + Search document Procurar no documento - + Toggle Focus Mode Alternar o "Modo Foco" - + Close the document Fechar o documento @@ -844,97 +844,97 @@ GuiDocEditSearch - + Search Pesquisa - + Replace Substituir - + Case Sensitive Diferenciar Maiúsculas e Minúsculas - + Match case Diferencia Maiúsculas e Minúsculas - + Whole Words Only Apenas Palavras Inteiras - + Match whole words Encontra apenas palavras inteiras - + RegEx Mode Expressão Regular - + Loop Search Pesquisa do Início - + Loop the search when reaching the end Pesquisa do início quando chega no final do documento - + Search Next File Busca no Próximo Arquivo - + Continue searching in the next file Continua a busca no próximo arquivo - + Preserve Case Preserva Maiúsculas e Minúsculas - + Preserve case on replace Preserva maiúsculas e minúsculas ao substituir - + Close Search Fechar a Busca - + Show/hide the replace text box Mostrar/Ocultar a caixa substituição - + Find in current document Encontrar no documento atual - + Find and replace in current document Encontrar e substituir no documento atual - + Close the search box [{0}] Fechar a caixa de busca [{0}] - + Search using regular expressions Busca usando expressões regulares @@ -942,100 +942,105 @@ GuiDocEditor - + Spell check complete Verificação ortográfica completa - + No Suggestions Sem Sugestões - + The document you are trying to open is too big. The document size is {0} MB. The maximum size allowed is {1} MB. O documento que você está tentando abrir é muito grande. O tamanho do documento é {0} MB. O tamanho máximo permitido é {1} MB. - + The text you are trying to add is too big. The text size is {0} MB. The maximum size allowed is {1} MB. O texto que você está tentando adicionar é muito grande. O tamanho do texto é {0} MB. O tamanho máximo permitido é {1} MB. - + File Location Localização do Arquivo - + Follow Tag Seguir Etiqueta - + Cut Recortar - + Copy Copiar - + Paste Colar - + Select All Selecionar Tudo - + Select Word Selecionar Palavra - + Select Paragraph Selecionar Parágrafo - + Spelling Suggestion(s) Sugestão de Ortografia - + Add Word to Dictionary Adicionar Palavra ao Dicionário - + Please select some text before calling replace quotes. Por favor, selecione algum texto antes de invocar a substituição de aspas. - + The currently open file is saved in: O arquivo aberto atualmente está salvo em: - + The document has grown too big and you cannot add more text to it. The maximum size of a single novelWriter document is {0} MB. O tamanho do documento aumentou muito e você não pode adicionar mais texto nele. O tamanho máximo de um único documento do novelWriter é {0} MB. - + Opened Document: {0} Documento Aberto: {0} - + Saved Document: {0} Documento Salvo: {0} + + + Could not save document. + Não foi possível salvar o documento. + GuiDocMerge @@ -1060,20 +1065,30 @@ Nenhum documento-fonte foi encontrado. Nada para fazer. - + No source document selected. Nothing to do. Nenhum documento de origem selecionado. Nada a ser feito. - + Could not parse source document. Não foi possível interpretar o documento. - + Element selected in the project tree must be a folder. O elemento selecionado na árvore do projeto deve ser um diretório. + + + Failed to open document file. + Houve uma falha ao abrir o arquivo do documento. + + + + Could not save document. + Não foi possível salvar o documento. + GuiDocSplit @@ -1108,7 +1123,7 @@ Dividir até os cabeçalhos de nível 4 (Seção) - + Split Document Divisão de Documento @@ -1123,30 +1138,40 @@ Não foi possível interpretar o documento. - + No headers found. Nothing to do. Nenhum cabeçalho foi encontrado. Nada para fazer. - + Cannot add new folder for the document split. Maximum folder depth has been reached. Please move the file to another level in the project tree. Não é possível adicionar um novo diretório para a divisão do documento. A profundidade máxima dos diretórios foi alcançada. Por favor mova o arquivo para outro nível na árvore do projeto. - + Continue with the splitting process? Continuar com o processo de divisão? - + Element selected in the project tree must be a file. O elemento selecionado na árvore do projeto deve ser um arquivo. - + The document will be split into {0} file(s) in a new folder. The original document will remain intact. O documento será dividio em {0} arquivo(s) em um novo diretório. O documento original será mantido intacto. + + + Failed to open document file. + Houve uma falha ao abrir o arquivo do documento. + + + + Could not save document. + Não foi possível salvar o documento. + GuiDocViewFooter @@ -3910,12 +3935,12 @@ Esvaziar a Lixeira - + Delete File Remover Arquivo - + The item cannot be moved to that location. O item não pode ser movido para este local. @@ -3980,17 +4005,17 @@ Permanentemente remover o arquivo '{0}'? - + Move file '{0}' to Trash? Mover o arquivo '{0}' para a Lixeira? - + Cannot delete folder. It is not empty. Recursive deletion is not supported. Please delete the content first. Não foi possível remover o diretório. O diretório não está vazio. Exclusão recursiva não é suportada. Por favor remova todo o conteúdo primeiro. - + Cannot delete root folder. It is not empty. Recursive deletion is not supported. Please delete the content first. Não foi possível remover o diretório-raiz. O diretório não está vazio. Exclusão recursiva não é suportada. Por favor remova todo o conteúdo primeiro. @@ -4000,60 +4025,65 @@ Não foi possível adicionar novos arquivos ou diretórios à Lixeira. - + There is nowhere to add item with name '{0}'. Não há lugar para adicionar o item com o nome '{0}'. + + + Could not delete document file. + Não foi possível remover o arquivo do documento. + GuiProjectTreeMenu - + Edit Project Item Editar Item do Projeto - + Open Document Abrir Documento - + View Document Ver Documento - + Toggle Included Flag Alternar Opção de Inclusão - + New File Novo Arquivo - + New Folder Novo Diretório - + Delete Item Remover Item - + Empty Trash Esvaziar a Lixeira - + Move Item Up Mover Item Acima - + Move Item Down Mover Item Abaixo @@ -4242,24 +4272,6 @@ Salvar Dados Como - - NWDoc - - - Failed to open document file. - Houve uma falha ao abrir o arquivo do documento. - - - - Could not save document. - Não foi possível salvar o documento. - - - - Could not delete document file. - Não foi possível remover o arquivo do documento. - - NWProject @@ -4308,232 +4320,232 @@ Novo Projeto - + Novel Livro - + Plot Enredo - + Characters Personagens - + World Mundo - + Title Page Página de Título - + New Chapter Novo Capítulo - + New Scene Nova Cena - + Failed to parse project xml. Houve uma falha ao interpretar o conteúdo XML do projeto. - + Attempting to open backup project file instead. Tentando abrir a cópia de segurança do projeto. - + Unknown Desconhecido - + Project file does not appear to be a novelWriterXML file. O arquivo do projeto não parece ser um arquivo XML do novelWriter. - + Version Conflict Conflito de Versão - + Opened Project: {0} Projeto Aberto: {0} - + Project path not set, cannot save project. O caminho do projeto não foi definido, não é possível salvar o projeto. - + Failed to save project. Houve uma falha ao salvar o projeto. - + Saved Project: {0} Projeto Salvo: {0} - + Backing up project ... Realizando uma cópia de segurança do projeto... - + Cannot backup project because no backup path is set. Please set a valid backup location in Tools > Preferences. Não foi possível realizar uma cópia de segurança do projeto porquê o caminho das cópias de segurança não foi definido. Por favor, defina um caminho válido para as cópias de segurança em Ferramentas > Preferências. - + Cannot backup project because no project name is set. Please set a Working Title in Project > Project Settings. Não foi possível realizar a cópia de segurança do projeto porque o nome do projeto não está definido. Por favor defina o Nome do Projeto em Projeto > Configurações do Projeto. - + Cannot backup project because the backup path does not exist. Please set a valid backup location in Tools > Preferences. Não foi possível realizar a cópia de segurança do projeto porque o caminho das cópias de segurança não exite. Por favor, defina um cainho válido para as cópias de segurança em Ferramentas > Preferências. - + Could not create backup folder. Não foi possível ler o diretório de cópias de segurança. - + Cannot backup project because the backup path is within the project folder to be backed up. Please choose a different backup path in Tools > Preferences. Não foi possível realizar a cópia de segurança do projeto porque o caminho das cópias de segurança está em um caminho dentro do diretório do projeto. Por favor, escolha um caminho diferente para as cópias de segurança em Ferramentas> Preferências. - + Could not write backup archive. Não foi possível escrever o arquivo da cópia de segurança. - + Failed to create a new example project. Houve uma falha ao criar um novo projeto de exemplo. - + Failed to create a new example project. Could not find the necessary files. They seem to be missing from this installation. Houve uma falha ao criar um novo projeto de exemplo. Não foi possível encontrar os arquivos necessários. Eles parecem estar faltando nesta instalação. - + Could not create new project folder. Não foi possível criar o diretório do novo projeto. - + New project folder is not empty. Each project requires a dedicated project folder. O diretório do novo projeto não está vazio. Cada projeto requer um diretório dedicado. - + You must set a valid backup path in Preferences to use the automatic project backup feature. Deve ser definido um caminho válido para as cópias de segurança nas preferências para usar a funcionalidade de cópias de segurança automáticas. - + You must set a valid project name in Project Settings to use the automatic project backup feature. Deve ser definido um nome de projeto válido nas preferências do projeto para usar a funcionalidade de cópias de segurança automáticas. - + Recovered Recuperado - + One or more orphaned files could not be added back into the project. Make sure at least a Novel root folder exists. Um ou mais arquivos-órfãos não puderam ser readicionados ao projeto. Verifique que pelo menos um diretório-raiz de Livro exista. - + Could not move: {0} Não foi possível mover: {0} - + Could not delete: {0} Não foi possível remover: {0} - + Could not make folder: {0} Não foi possível criar o diretório: {0} - + Chapter {0} Capítulo {0} - + Scene {0} Cena {0} - + File not found: {0} Arquivo não encontrado: {0} - + Backup from {0} Cópia de segurança de {0} - + Backup archive file written to: {0} Arquivo da cópia de segurança escrito em: {0} - + Project backed up to '{0}' Cópia de segurança realizada para '{0}' - + Found {0} orphaned file(s) in project folder. Foram encontrados {0} arquivos-órfãos no diretório do projeto. - + Recovered File {0} Arquivo Recuperado {0} - + Not a folder: {0} Não é um diretório: {0} - + Unknown or unsupported novelWriter project file format. The project cannot be opened by this version of novelWriter. The file was saved with novelWriter version {0}. Format de arquivo de projeto do novelWriter desconhecido ou não-suportado. O projeto não pode ser aberto por essa versão do novelWriter. O arquivo foi salvo com a versão {0} do novelWriter. - + [{0}] {1} - + Could not move item {0} to {1}. Não foi possível mover o item {0} para {1}. @@ -4543,7 +4555,7 @@ Por - + and e @@ -4553,7 +4565,7 @@ Capítulo - + This project was saved by a newer version of novelWriter, version {0}. This is version {1}. If you continue to open the project, some attributes and settings may not be preserved, but the overall project should be fine. Continue opening the project? O projeto foi salvo por uma versão mais nova do novelWriter, versão {0}. Esta é a versão {1}. Caso deseje continuar a abrir o projeto, alguns atributos e configurações podem não ser preservados, mas o projeto deve funcionar corretamente. Continuar a abrir o projeto? From 5ee39d7eccd3abfe52284d882fc885d69f324dfb Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 25 Apr 2021 23:46:09 +0200 Subject: [PATCH 05/12] Tighten up the use of item and nwdoc objects in editor class --- nw/core/document.py | 26 ++++--------- nw/gui/doceditor.py | 55 +++++++++++++++------------ tests/test_core/test_core_document.py | 2 +- 3 files changed, 40 insertions(+), 43 deletions(-) diff --git a/nw/core/document.py b/nw/core/document.py index 44f94203..956dee5d 100644 --- a/nw/core/document.py +++ b/nw/core/document.py @@ -40,26 +40,20 @@ class NWDoc(): # Internal Variables self._docHandle = theHandle - self._theItem = self.theProject.projTree[theHandle] + self._theItem = None self._fileLoc = None self._docMeta = {} self._docError = "" + if theHandle is not None: + self._theItem = self.theProject.projTree[theHandle] + return ## # Class Methods ## - def clearDocument(self): - """Clear the document contents. - """ - self._theItem = None - self._docHandle = None - self._fileLoc = None - self._docMeta = {} - return - def readDocument(self, isOrphan=False): """Read a document from set handle, capturing potential file system errors and parse meta data. If the document doesn't exist @@ -68,11 +62,11 @@ class NWDoc(): """ self._docError = "" if not isHandle(self._docHandle): - self._docError = "No document handle set." + logger.error("No document handle set") return None if self._theItem is None and not isOrphan: - self._docError = "Unknown novelWriter document." + logger.error("Unknown novelWriter document") return None docFile = self._docHandle+".nwd" @@ -101,10 +95,6 @@ class NWDoc(): except Exception as e: self._docError = str(e) - # Note: Document must be cleared in case of an io error, - # or else the auto-save or save will try to overwrite it - # with an empty file. Return None to alert the caller. - self.clearDocument() return None else: @@ -121,7 +111,7 @@ class NWDoc(): """ self._docError = "" if not isHandle(self._docHandle): - self._docError = "No document handle set." + logger.error("No document handle set") return False self.theProject.ensureFolderStructure() @@ -164,7 +154,7 @@ class NWDoc(): """ self._docError = "" if not isHandle(self._docHandle): - self._docError = "No document handle set." + logger.error("No document handle set") return False docFile = self._docHandle+".nwd" diff --git a/nw/gui/doceditor.py b/nw/gui/doceditor.py index 3a9fe5c4..ebcd16f1 100644 --- a/nw/gui/doceditor.py +++ b/nw/gui/doceditor.py @@ -75,7 +75,9 @@ class GuiDocEditor(QTextEdit): self.theTheme = theParent.theTheme self.theIndex = theParent.theIndex self.theProject = theParent.theProject - self.nwDocument = NWDoc(self.theProject, None) + + self.nwDocument = None + self.nwItem = None self.docChanged = False # Flag for changed status of document self.spellCheck = False # Flag for spell checking enabled @@ -165,7 +167,7 @@ class GuiDocEditor(QTextEdit): """Clear the current document and reset all document related flags and counters. """ - self.nwDocument = NWDoc(self.theProject, None) + self.nwDocument = None self.setReadOnly(True) self.clear() self.wcTimer.stop() @@ -298,6 +300,7 @@ class GuiDocEditor(QTextEdit): the file. """ self.nwDocument = NWDoc(self.theProject, tHandle) + self.nwItem = self.nwDocument.getCurrentItem() theDoc = self.nwDocument.readDocument() if theDoc is None: @@ -352,16 +355,15 @@ class GuiDocEditor(QTextEdit): self.updateDocMargins() self.hLight.spellCheck = spTemp - theItem = self.nwDocument.getCurrentItem() - if tLine is None and theItem is not None: + if tLine is None and self.nwItem is not None: # For large documents we queue the repositioning until the # document layout has grown past the point we want to move # the cursor to. This makes the loading significantly # faster. if docSize > 50000: - self.queuePos = theItem.cursorPos + self.queuePos = self.nwItem.cursorPos else: - self.setCursorPosition(theItem.cursorPos) + self.setCursorPosition(self.nwItem.cursorPos) else: self.setCursorLine(tLine) @@ -380,9 +382,9 @@ class GuiDocEditor(QTextEdit): self.setCursorPosition(0) # Update the status bar - if theItem is not None: + if self.nwItem is not None: self.theParent.setStatus( - self.tr("Opened Document: {0}").format(theItem.itemName) + self.tr("Opened Document: {0}").format(self.nwItem.itemName) ) return True @@ -431,19 +433,25 @@ class GuiDocEditor(QTextEdit): """Save the text currently in the editor to the NWDoc object, and update the NWItem meta data. """ - theItem = self.nwDocument.getCurrentItem() - if theItem is None: + if self.nwItem is None or self.nwDocument is None: + logger.error("Cannot save text as no document is open") + return False + + tHandle = self.nwItem.itemHandle + if self.theHandle != tHandle: + logger.error("Editor handle %s and item handle %s do not match" % ( + self.theHandle, tHandle + )) return False docText = self.getText() - tHandle = theItem.itemHandle cC, wC, pC = countWords(docText) self._updateCounts(cC, wC, pC) - theItem.setCharCount(self.charCount) - theItem.setWordCount(self.wordCount) - theItem.setParaCount(self.paraCount) + self.nwItem.setCharCount(self.charCount) + self.nwItem.setWordCount(self.wordCount) + self.nwItem.setParaCount(self.paraCount) self.saveCursorPosition() if not self.nwDocument.writeDocument(docText): @@ -472,7 +480,7 @@ class GuiDocEditor(QTextEdit): # Update the status bar self.theParent.setStatus( - self.tr("Saved Document: {0}").format(theItem.itemName) + self.tr("Saved Document: {0}").format(self.nwItem.itemName) ) return True @@ -599,10 +607,9 @@ class GuiDocEditor(QTextEdit): def saveCursorPosition(self): """Save the cursor position to the current project item object. """ - theItem = self.nwDocument.getCurrentItem() - if theItem is not None: + if self.nwItem is not None: cursPos = self.getCursorPosition() - theItem.setCursorPos(cursPos) + self.nwItem.setCursorPos(cursPos) return def setCursorLine(self, theLine): @@ -773,7 +780,7 @@ class GuiDocEditor(QTextEdit): """Tell the user where on the file system the file in the editor is saved. """ - if self.theHandle is None: + if self.nwDocument is None: logger.error("No document open") return False @@ -1140,8 +1147,7 @@ class GuiDocEditor(QTextEdit): def _updateCounts(self, cCount, wCount, pCount): """Slot for the word counter's finished signal """ - theItem = self.nwDocument.getCurrentItem() - if self.theHandle is None or theItem is None: + if self.theHandle is None or self.nwItem is None: return logger.verbose("Updating word count") @@ -1149,9 +1155,10 @@ class GuiDocEditor(QTextEdit): self.charCount = cCount self.wordCount = wCount self.paraCount = pCount - theItem.setCharCount(cCount) - theItem.setWordCount(wCount) - theItem.setParaCount(pCount) + + self.nwItem.setCharCount(cCount) + self.nwItem.setWordCount(wCount) + self.nwItem.setParaCount(pCount) self.theParent.treeView.propagateCount(self.theHandle, wCount) self.theParent.treeView.projectWordCount() diff --git a/tests/test_core/test_core_document.py b/tests/test_core/test_core_document.py index d44b3a08..82028d61 100644 --- a/tests/test_core/test_core_document.py +++ b/tests/test_core/test_core_document.py @@ -98,7 +98,7 @@ def testCoreDocument_LoadSave(monkeypatch, dummyGUI, nwMinimal): assert theDoc.getError() == "OSError" # Saving with no handle - theDoc.clearDocument() + theDoc._docHandle = None assert not theDoc.writeDocument(theText) # Delete the last document From 88d198403e59a5c072ece82e12c0b91edefee047 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 25 Apr 2021 23:47:42 +0200 Subject: [PATCH 06/12] Update translations --- i18n/nw_en_US.ts | 94 ++++++++++++++++++++++++------------------------ i18n/nw_fr.ts | 94 ++++++++++++++++++++++++------------------------ i18n/nw_nb_NO.ts | 94 ++++++++++++++++++++++++------------------------ i18n/nw_pt.ts | 94 ++++++++++++++++++++++++------------------------ novelWriter.pro | 1 - 5 files changed, 188 insertions(+), 189 deletions(-) diff --git a/i18n/nw_en_US.ts b/i18n/nw_en_US.ts index 6dff7f40..a756fc7f 100644 --- a/i18n/nw_en_US.ts +++ b/i18n/nw_en_US.ts @@ -798,22 +798,22 @@ GuiDocEditFooter - + Status - + Line: {0} ({1}) - + Words: {0} ({1}) - + Document size is {0} bytes @@ -821,22 +821,22 @@ GuiDocEditHeader - + Edit document meta - + Search document - + Toggle Focus Mode - + Close the document @@ -844,97 +844,97 @@ GuiDocEditSearch - + Search - + Replace - + Case Sensitive - + Match case - + Whole Words Only - + Match whole words - + RegEx Mode - + Search using regular expressions - + Loop Search - + Loop the search when reaching the end - + Search Next File - + Continue searching in the next file - + Preserve Case - + Preserve case on replace - + Close Search - + Close the search box [{0}] - + Show/hide the replace text box - + Find in current document - + Find and replace in current document @@ -942,102 +942,102 @@ GuiDocEditor - + The document you are trying to open is too big. The document size is {0} MB. The maximum size allowed is {1} MB. - + The text you are trying to add is too big. The text size is {0} MB. The maximum size allowed is {1} MB. - + Spell check complete - + File Location - + The currently open file is saved in: - + The document has grown too big and you cannot add more text to it. The maximum size of a single novelWriter document is {0} MB. - + Follow Tag - + Cut - + Copy - + Paste - + Select All - + Select Word - + Select Paragraph - + Spelling Suggestion(s) - + No Suggestions - + Add Word to Dictionary - + Please select some text before calling replace quotes. - + Opened Document: {0} - + Saved Document: {0} - + Could not save document. diff --git a/i18n/nw_fr.ts b/i18n/nw_fr.ts index 09bac02b..883f54ac 100644 --- a/i18n/nw_fr.ts +++ b/i18n/nw_fr.ts @@ -798,22 +798,22 @@ GuiDocEditFooter - + Status État - + Line: {0} ({1}) Ligne: {0} ({1}) - + Words: {0} ({1}) Mots: {0} ({1}) - + Document size is {0} bytes La taille du document est de {0} octets @@ -821,22 +821,22 @@ GuiDocEditHeader - + Edit document meta Modifier les métadonnées du document - + Search document Chercher dans le document - + Toggle Focus Mode Basculer le mode focus - + Close the document Fermer le document @@ -844,97 +844,97 @@ GuiDocEditSearch - + Search Chercher - + Replace Remplacer - + Case Sensitive Sensible à la casse - + Match case Respecter la casse - + Whole Words Only Mots entiers uniquement - + Match whole words Ne vérifier la correspondance que sur des mots entiers - + RegEx Mode Expressions régulières - + Search using regular expressions Chercher en utilisant des expressions régulières - + Loop Search Recherche en boucle - + Loop the search when reaching the end Reprendre la recherche au début du texte lorsque la fin est atteinte - + Search Next File Chercher dans le fichier suivant - + Continue searching in the next file Continuer la recherche dans le fichier suivant - + Preserve Case Conserver la casse - + Preserve case on replace Conserver la casse lors d'un remplacement - + Close Search Terminer la recherche - + Close the search box [{0}] Fermer la boîte de recherche [{0}] - + Show/hide the replace text box Montrer/cacher le texte de remplacement - + Find in current document Chercher dans le document actuel - + Find and replace in current document Chercher et remplacer dans le document actuel @@ -942,102 +942,102 @@ GuiDocEditor - + The document you are trying to open is too big. The document size is {0} MB. The maximum size allowed is {1} MB. Le document que vous essayez d'ouvrir est trop grand. La taille du document est de {0} MB alors que la taille maximale est de {1} MB. - + The text you are trying to add is too big. The text size is {0} MB. The maximum size allowed is {1} MB. Le texte que vous voulez ajouter est trop grand. La taille du texte est de {0} MB alors que la taille maximale est de {1} MB. - + Spell check complete La vérification orthographique est terminée - + File Location Emplacement du fichier - + The currently open file is saved in: Le fichier actuellement ouvert est enregistré dans : - + The document has grown too big and you cannot add more text to it. The maximum size of a single novelWriter document is {0} MB. Le document est devenu trop grand et vous ne pouvez plus lui ajouter de texte. La taille maximale d'un fichier novelWriter est de {0} MB. - + Follow Tag Suivre cette étiquette - + Cut Couper - + Copy Copier - + Paste Coller - + Select All Sélectionner tout - + Select Word Sélectionner le mot - + Select Paragraph Sélectionner le paragraphe - + Spelling Suggestion(s) Orthographe suggérée - + No Suggestions Pas de suggestion - + Add Word to Dictionary Ajouter ce mot au dictionnaire - + Please select some text before calling replace quotes. Veuillez sélectionner du texte avant de demander le remplacement des guillemets. - + Opened Document: {0} Document ouvert : {0} - + Saved Document: {0} Document enregistré : {0} - + Could not save document. Impossible d'enregistrer le document. diff --git a/i18n/nw_nb_NO.ts b/i18n/nw_nb_NO.ts index db8a69a7..362bb805 100644 --- a/i18n/nw_nb_NO.ts +++ b/i18n/nw_nb_NO.ts @@ -798,22 +798,22 @@ GuiDocEditFooter - + Status Status - + Line: {0} ({1}) Linje: {0} ({1}) - + Words: {0} ({1}) Ord: {0} ({1}) - + Document size is {0} bytes Dokumentet er {0} byte @@ -821,22 +821,22 @@ GuiDocEditHeader - + Edit document meta Rediger dokumentinstillinger - + Search document Søk i dokumentet - + Toggle Focus Mode Slå av/på "Fokus-modus" - + Close the document Lukk dokumentet @@ -844,97 +844,97 @@ GuiDocEditSearch - + Search Søk - + Replace Erstatt - + Case Sensitive Skill store/små bokstaver - + Match case Søket skiller mellom store og små bokstaver - + Whole Words Only Kun hele ord - + Match whole words Søk kun etter hele ord - + RegEx Mode RegEx-modus - + Search using regular expressions Søk ved hjelp av "regular expressions" - + Loop Search Søk rundt - + Loop the search when reaching the end Begynn søket på nytt når enden er nådd - + Search Next File Søk i neste file - + Continue searching in the next file Fortsett søket i neste fil - + Preserve Case Behold store/små bokstaver - + Preserve case on replace Behold store og små bokstaver på samme sted ved erstatt - + Close Search Lukk søk - + Close the search box [{0}] Lukk søkeboksen [{0}] - + Show/hide the replace text box Vis/skjul erstatt-boksen - + Find in current document Søk i det åpne dokumentet - + Find and replace in current document Søk og erstatt i det åpne dokumentet @@ -942,102 +942,102 @@ GuiDocEditor - + The document you are trying to open is too big. The document size is {0} MB. The maximum size allowed is {1} MB. Dokumentet du prøver å åpne er for stort. Dokumenter er på {0} MB. Den maksimale størrelsen tillat er {1} MB. - + The text you are trying to add is too big. The text size is {0} MB. The maximum size allowed is {1} MB. Teksten du forsøker å legge til er for stor. Teksten er {0} MB. Den maksimale tillatte størrelsen er {1} MB. - + Spell check complete Stavekontrollen er ferdig - + File Location Filens plassering - + The currently open file is saved in: Det åpne dokumentet er lagret på følgende sted: - + The document has grown too big and you cannot add more text to it. The maximum size of a single novelWriter document is {0} MB. Dokumentet har blitt for stort og du kan ikke legge til mer tekst. Den maksimale tillatte størrelsen for et novelWriter-dokument er {0} MB. - + Follow Tag Følg knagg - + Cut Klipp - + Copy Kopier - + Paste Lim inn - + Select All Velg hele teksten - + Select Word Velg hele ordet - + Select Paragraph Velg hele avsnittet - + Spelling Suggestion(s) Forslag fra stavekontrollen - + No Suggestions Ingen forslag - + Add Word to Dictionary Legg til ord i ordbok - + Please select some text before calling replace quotes. Venligst velg en del av teksten før du velger å erstatte sitattegn. - + Opened Document: {0} Åpnet dokument: {0} - + Saved Document: {0} Lagret dokument: {0} - + Could not save document. Kunne ikke lagre dokumentet. diff --git a/i18n/nw_pt.ts b/i18n/nw_pt.ts index bf9bb715..cb0bfec6 100644 --- a/i18n/nw_pt.ts +++ b/i18n/nw_pt.ts @@ -798,22 +798,22 @@ GuiDocEditFooter - + Line: {0} ({1}) Linha: {0} ({1}) - + Words: {0} ({1}) Palavras: {0} ({1}) - + Status Estado - + Document size is {0} bytes O tamanho do documento é {0} bytes @@ -821,22 +821,22 @@ GuiDocEditHeader - + Edit document meta Editar os meta-dados do documento - + Search document Procurar no documento - + Toggle Focus Mode Alternar o "Modo Foco" - + Close the document Fechar o documento @@ -844,97 +844,97 @@ GuiDocEditSearch - + Search Pesquisa - + Replace Substituir - + Case Sensitive Diferenciar Maiúsculas e Minúsculas - + Match case Diferencia Maiúsculas e Minúsculas - + Whole Words Only Apenas Palavras Inteiras - + Match whole words Encontra apenas palavras inteiras - + RegEx Mode Expressão Regular - + Loop Search Pesquisa do Início - + Loop the search when reaching the end Pesquisa do início quando chega no final do documento - + Search Next File Busca no Próximo Arquivo - + Continue searching in the next file Continua a busca no próximo arquivo - + Preserve Case Preserva Maiúsculas e Minúsculas - + Preserve case on replace Preserva maiúsculas e minúsculas ao substituir - + Close Search Fechar a Busca - + Show/hide the replace text box Mostrar/Ocultar a caixa substituição - + Find in current document Encontrar no documento atual - + Find and replace in current document Encontrar e substituir no documento atual - + Close the search box [{0}] Fechar a caixa de busca [{0}] - + Search using regular expressions Busca usando expressões regulares @@ -942,102 +942,102 @@ GuiDocEditor - + Spell check complete Verificação ortográfica completa - + No Suggestions Sem Sugestões - + The document you are trying to open is too big. The document size is {0} MB. The maximum size allowed is {1} MB. O documento que você está tentando abrir é muito grande. O tamanho do documento é {0} MB. O tamanho máximo permitido é {1} MB. - + The text you are trying to add is too big. The text size is {0} MB. The maximum size allowed is {1} MB. O texto que você está tentando adicionar é muito grande. O tamanho do texto é {0} MB. O tamanho máximo permitido é {1} MB. - + File Location Localização do Arquivo - + Follow Tag Seguir Etiqueta - + Cut Recortar - + Copy Copiar - + Paste Colar - + Select All Selecionar Tudo - + Select Word Selecionar Palavra - + Select Paragraph Selecionar Parágrafo - + Spelling Suggestion(s) Sugestão de Ortografia - + Add Word to Dictionary Adicionar Palavra ao Dicionário - + Please select some text before calling replace quotes. Por favor, selecione algum texto antes de invocar a substituição de aspas. - + The currently open file is saved in: O arquivo aberto atualmente está salvo em: - + The document has grown too big and you cannot add more text to it. The maximum size of a single novelWriter document is {0} MB. O tamanho do documento aumentou muito e você não pode adicionar mais texto nele. O tamanho máximo de um único documento do novelWriter é {0} MB. - + Opened Document: {0} Documento Aberto: {0} - + Saved Document: {0} Documento Salvo: {0} - + Could not save document. Não foi possível salvar o documento. diff --git a/novelWriter.pro b/novelWriter.pro index de214cd1..9452d5e7 100644 --- a/novelWriter.pro +++ b/novelWriter.pro @@ -1,6 +1,5 @@ SOURCES += \ i18n/dummy_qtbase.py \ - nw/core/document.py \ nw/core/project.py \ nw/core/tokenizer.py \ nw/dialogs/about.py \ From 6b119cf4b85811b058c86d0b6a16994af698c936 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 25 Apr 2021 23:58:11 +0200 Subject: [PATCH 07/12] Remove the return false on error in doc viewer --- nw/gui/docviewer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nw/gui/docviewer.py b/nw/gui/docviewer.py index 8ba3fbef..22c0439a 100644 --- a/nw/gui/docviewer.py +++ b/nw/gui/docviewer.py @@ -185,7 +185,6 @@ class GuiDocViewer(QTextBrowser): logger.error("Failed to generate preview for document with handle '%s'" % tHandle) nw.logException() self.setText(self.tr("An error occurred while generating the preview.")) - return False # Refresh the tab stops if self.mainConf.verQtValue >= 51000: From 7867965989c6fbba670d57e76404018ac7e6bb17 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 2 May 2021 17:19:50 +0200 Subject: [PATCH 08/12] Alter the init logic of handles in NWDoc --- nw/core/document.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/nw/core/document.py b/nw/core/document.py index 956dee5d..7088f61a 100644 --- a/nw/core/document.py +++ b/nw/core/document.py @@ -39,13 +39,16 @@ class NWDoc(): self.theProject = theProject # Internal Variables - self._docHandle = theHandle - self._theItem = None - self._fileLoc = None - self._docMeta = {} - self._docError = "" + self._theItem = None # The currently open item + self._docHandle = None # The handle of the currently open item + self._fileLoc = None # The file location of the currently open item + self._docMeta = {} # The meta data of the currently open item + self._docError = "" # The latest encountered IO error - if theHandle is not None: + if isHandle(theHandle): + self._docHandle = theHandle + + if self._docHandle is not None: self._theItem = self.theProject.projTree[theHandle] return @@ -61,7 +64,7 @@ class NWDoc(): None. """ self._docError = "" - if not isHandle(self._docHandle): + if self._docHandle is None: logger.error("No document handle set") return None @@ -110,7 +113,7 @@ class NWDoc(): of save failure. Returns True if successful, False if not. """ self._docError = "" - if not isHandle(self._docHandle): + if self._docHandle is None: logger.error("No document handle set") return False @@ -153,7 +156,7 @@ class NWDoc(): from the project data folder. """ self._docError = "" - if not isHandle(self._docHandle): + if self._docHandle is None: logger.error("No document handle set") return False From 6c79a1daba15931adfb715d5f686cba4edc4d2ff Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 2 May 2021 17:48:28 +0200 Subject: [PATCH 09/12] Test terminology update --- nw/core/index.py | 2 +- nw/core/spellcheck.py | 12 +++---- nw/core/toodt.py | 2 +- nw/tools/build.py | 4 +-- tests/conftest.py | 16 ++++----- tests/{dummy.py => mock.py} | 20 +++++------ .../guiEditor_Main_Final_0e17daca5f3e1.nwd | 4 +-- .../guiEditor_Main_Final_nwProject.nwx | 4 +-- tests/test_base/test_base_config.py | 12 +++---- tests/test_base/test_base_error.py | 2 +- tests/test_base/test_base_init.py | 12 +++---- tests/test_core/test_core_document.py | 6 ++-- tests/test_core/test_core_index.py | 2 +- tests/test_core/test_core_options.py | 2 +- tests/test_core/test_core_project.py | 36 +++++++++---------- tests/test_core/test_core_spell.py | 8 ++--- tests/test_core/test_core_status.py | 2 +- tests/test_core/test_core_tokenizer.py | 4 +-- tests/test_core/test_core_tree.py | 22 ++++++------ tests/test_dialogs/test_dlg_wordlist.py | 2 +- tests/test_gui/test_gui_doceditor.py | 6 ++-- tests/test_gui/test_gui_theme.py | 2 +- tests/test_tools/test_tools_writingstats.py | 2 +- 23 files changed, 92 insertions(+), 92 deletions(-) rename tests/{dummy.py => mock.py} (89%) diff --git a/nw/core/index.py b/nw/core/index.py index 16b5f1b8..9565325e 100644 --- a/nw/core/index.py +++ b/nw/core/index.py @@ -269,7 +269,7 @@ class NWIndex(): logger.debug("Indexing item with handle %s" % tHandle) # Check file type, and reset its old index - # Also add a dummy entry T000000 in case the file has no title + # Also add a default entry T000000 in case the file has no title self._refIndex[tHandle] = {} self._refIndex[tHandle]["T000000"] = { "tags" : [], diff --git a/nw/core/spellcheck.py b/nw/core/spellcheck.py index 0595db47..6ea8bb92 100644 --- a/nw/core/spellcheck.py +++ b/nw/core/spellcheck.py @@ -47,17 +47,17 @@ class NWSpellCheck(): return def setLanguage(self, theLang, projectDict=None): - """Dummy function. + """Default function. """ return def checkWord(self, theWord): - """Dummy function. + """Default function. """ return True def suggestWords(self, theWord): - """Dummy function. + """Default function. """ return [] @@ -78,12 +78,12 @@ class NWSpellCheck(): return False def listDictionaries(self): - """Dummy function. + """Default function. """ return [] def describeDict(self): - """Dummy function. + """Default function. """ return "", "" @@ -136,7 +136,7 @@ class NWSpellEnchant(NWSpellCheck): def setLanguage(self, theLang, projectDict=None): """Load a dictionary for the language specified in the config. - If that fails, we load a dummy dictionary so that lookups don't + If that fails, we load a mock dictionary so that lookups don't crash. """ try: diff --git a/nw/core/toodt.py b/nw/core/toodt.py index 0085ff64..ce67e8c0 100644 --- a/nw/core/toodt.py +++ b/nw/core/toodt.py @@ -563,7 +563,7 @@ class ToOdt(Tokenizer): ## if len(theText) != len(theFmt): - # Generate dummy format if there isn't any or it doesn't match + # Generate an empty format if there isn't any or it doesn't match theFmt = " "*len(theText) # XML functions diff --git a/nw/tools/build.py b/nw/tools/build.py index b4d5f36c..ac9ea364 100644 --- a/nw/tools/build.py +++ b/nw/tools/build.py @@ -173,7 +173,7 @@ class GuiBuildNovel(QDialog): if langIdx != -1: self.buildLang.setCurrentIndex(langIdx) - # Dummy boxes due to QGridView and QLineEdit expand bug + # Wrapper boxes due to QGridView and QLineEdit expand bug self.boxTitle = QHBoxLayout() self.boxTitle.addWidget(self.fmtTitle) self.boxChapter = QHBoxLayout() @@ -245,7 +245,7 @@ class GuiBuildNovel(QDialog): self.optState.getFloat("GuiBuildNovel", "lineHeight", 1.15) ) - # Dummy box due to QGridView and QLineEdit expand bug + # Wrapper box due to QGridView and QLineEdit expand bug self.boxFont = QHBoxLayout() self.boxFont.addWidget(self.textFont) diff --git a/tests/conftest.py b/tests/conftest.py index 36bf44d3..7c9925a5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -25,7 +25,7 @@ import pytest import shutil import os -from dummy import DummyMain +from mock import MockGuiMain from tools import cleanProject sys.path.insert(1, os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))) @@ -88,8 +88,8 @@ def fncDir(tmpDir): if not os.path.isdir(fncDir): os.mkdir(fncDir) yield fncDir - if os.path.isdir(fncDir): - shutil.rmtree(fncDir) + # if os.path.isdir(fncDir): + # shutil.rmtree(fncDir) return @pytest.fixture(scope="function") @@ -136,12 +136,12 @@ def fncConf(fncDir): @pytest.fixture(scope="function") def dummyGUI(monkeypatch, tmpConf): - """Create a dummy instance of novelWriter's main GUI class. + """Create a mock instance of novelWriter's main GUI class. """ monkeypatch.setattr("nw.CONFIG", tmpConf) - theDummy = DummyMain() - theDummy.mainConf = tmpConf - return theDummy + theGui = MockGuiMain() + theGui.mainConf = tmpConf + return theGui @pytest.fixture(scope="function") def nwGUI(qtbot, monkeypatch, fncDir, fncConf): @@ -191,7 +191,7 @@ def nwMinimal(tmpDir): @pytest.fixture(scope="function") def nwLipsum(tmpDir): """A medium sized novelWriter example project with a lot of Lorem - Ipsum dummy text. + Ipsum text. """ tstDir = os.path.dirname(__file__) srcDir = os.path.join(tstDir, "lipsum") diff --git a/tests/dummy.py b/tests/mock.py similarity index 89% rename from tests/dummy.py rename to tests/mock.py index 14f2ef91..410d95ed 100644 --- a/tests/dummy.py +++ b/tests/mock.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ -novelWriter – Test Suite Dummy Classes -====================================== +novelWriter – Test Suite Mocked Classes +======================================= This file is a part of novelWriter Copyright 2018–2021, Veronica Berglyd Olsen @@ -24,14 +24,14 @@ along with this program. If not, see . # Mock GUI # =========================================================================== # -class DummyMain(): +class MockGuiMain(): def __init__(self): self.mainConf = None self.hasProject = True self.theIndex = None self.theProject = None - self.statusBar = DummyStatusBar() + self.statusBar = MockStatusBar() # Test Variables self.askResponse = True @@ -79,9 +79,9 @@ class DummyMain(): self.lastAlert = "" return -# END Class DummyMain +# END Class MockGuiMain -class DummyStatusBar(): +class MockStatusBar(): def __init__(self): return @@ -89,9 +89,9 @@ class DummyStatusBar(): def setStatus(self, theText): return -# END Class DummyStatusBar +# END Class MockStatusBar -class DummyApp: +class MockApp: def __init__(self): return @@ -99,11 +99,11 @@ class DummyApp: def installTranslator(self, theLang): return -# END Class DummyApp +# END Class MockApp # =========================================================================== # # Error Functions -# Dummy functions that will raise errors instead. +# Mock functions that will raise errors instead. # =========================================================================== # def causeOSError(*args, **kwargs): diff --git a/tests/reference/guiEditor_Main_Final_0e17daca5f3e1.nwd b/tests/reference/guiEditor_Main_Final_0e17daca5f3e1.nwd index c77c3cd6..65bcb039 100644 --- a/tests/reference/guiEditor_Main_Final_0e17daca5f3e1.nwd +++ b/tests/reference/guiEditor_Main_Final_0e17daca5f3e1.nwd @@ -19,9 +19,9 @@ @char: Jane -This is a paragraph of dummy text. +This is a paragraph of nonsense text. -This is another paragraph of much longer dummy text. It is in fact 1 very very DUMB dummy text! We can also try replacing “quotes”, even single ‘quotes’ are replaced. Isn’t that nice? We can hyphen-ate, make dashes – and even longer dashes — if we want. Ellipsis? Not a problem either … How about three hyphens — for long dash? It works too. +This is another paragraph of much longer nonsense text. It is in fact 1 very very NONSENSICAL nonsense text! We can also try replacing “quotes”, even single ‘quotes’ are replaced. Isn’t that nice? We can hyphen-ate, make dashes – and even longer dashes — if we want. Ellipsis? Not a problem either … How about three hyphens — for long dash? It works too. “Full line double quoted text.” diff --git a/tests/reference/guiEditor_Main_Final_nwProject.nwx b/tests/reference/guiEditor_Main_Final_nwProject.nwx index 6e511bca..861888fa 100644 --- a/tests/reference/guiEditor_Main_Final_nwProject.nwx +++ b/tests/reference/guiEditor_Main_Final_nwProject.nwx @@ -85,10 +85,10 @@ New True BOOK - 466 + 482 83 4 - 604 + 620 Plot diff --git a/tests/test_base/test_base_config.py b/tests/test_base/test_base_config.py index c755b6a0..aaedc4af 100644 --- a/tests/test_base/test_base_config.py +++ b/tests/test_base/test_base_config.py @@ -27,7 +27,7 @@ import configparser from shutil import copyfile -from dummy import causeOSError, DummyApp +from mock import causeOSError, MockApp from tools import cmpFiles, writeFile from nw.config import Config @@ -195,7 +195,7 @@ def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir, filesDir): writeFile(os.path.join(i18nDir, "nw_en_GB.ts"), "") writeFile(os.path.join(i18nDir, "nw_abcd.qm"), "") - tstApp = DummyApp() + tstApp = MockApp() tstConf.initLocalisation(tstApp) theList = tstConf.listLanguages(tstConf.LANG_NW) assert theList == [("en_GB", "British English")] @@ -252,7 +252,7 @@ def testBaseConfig_RecentCache(monkeypatch, tmpConf, tmpDir, fncDir): } # Remove Non-Existent Entry - assert not tmpConf.removeFromRecentCache("dummy") + assert not tmpConf.removeFromRecentCache("stuff") assert tmpConf.recentProj == { pathOne: {"time": 1600002000, "title": "Proj One", "words": 100}, pathTwo: {"time": 1600005600, "title": "Proj Two", "words": 200}, @@ -490,7 +490,7 @@ def testBaseConfig_Internal(monkeypatch, tmpConf): cnfParse = configparser.ConfigParser() cnfParse.read_string( "[Main]\n" - "val_string = dummy\n" + "val_string = stuff\n" "val_int = 123\n" "val_bool = True\n" "val_list_string = A, B, C\n" @@ -499,7 +499,7 @@ def testBaseConfig_Internal(monkeypatch, tmpConf): assert tmpConf._parseLine( cnfParse, "Main", "val_string", tmpConf.CNF_STR, "default" - ) == "dummy" + ) == "stuff" assert tmpConf._parseLine( cnfParse, "Main", "nope", tmpConf.CNF_STR, "default" ) == "default" @@ -554,7 +554,7 @@ def testBaseConfig_Internal(monkeypatch, tmpConf): assert tmpConf.hasEnchant is False with monkeypatch.context() as mp: - mp.setattr("shutil.which", lambda *args: "dummy") + mp.setattr("shutil.which", lambda *args: "stuff") tmpConf._checkOptionalPackages() assert tmpConf.hasAssistant is True diff --git a/tests/test_base/test_base_error.py b/tests/test_base/test_base_error.py index 9976fae2..29bec978 100644 --- a/tests/test_base/test_base_error.py +++ b/tests/test_base/test_base_error.py @@ -25,7 +25,7 @@ import pytest from PyQt5.QtWidgets import qApp -from dummy import causeException +from mock import causeException from nw.error import NWErrorMessage, exceptionHandler diff --git a/tests/test_base/test_base_init.py b/tests/test_base/test_base_init.py index fb906786..2bcf9a61 100644 --- a/tests/test_base/test_base_init.py +++ b/tests/test_base/test_base_init.py @@ -25,19 +25,19 @@ import pytest import logging import sys -from dummy import DummyMain +from mock import MockGuiMain @pytest.mark.base def testBaseInit_Launch(caplog, monkeypatch, tmpDir): """Check launching the main GUI. """ - monkeypatch.setattr("nw.guimain.GuiMain", DummyMain) + monkeypatch.setattr("nw.guimain.GuiMain", MockGuiMain) # Testmode launch nwGUI = nw.main( ["--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir] ) - assert isinstance(nwGUI, DummyMain) + assert isinstance(nwGUI, MockGuiMain) # Darwin launch monkeypatch.setitem(sys.modules, "Foundation", None) @@ -46,7 +46,7 @@ def testBaseInit_Launch(caplog, monkeypatch, tmpDir): nwGUI = nw.main( ["--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir] ) - assert isinstance(nwGUI, DummyMain) + assert isinstance(nwGUI, MockGuiMain) assert "Foundation" in caplog.messages[1] nw.CONFIG.osDarwin = osDarwin @@ -68,7 +68,7 @@ def testBaseInit_Launch(caplog, monkeypatch, tmpDir): def testBaseInit_Options(monkeypatch, tmpDir): """Test command line options for logging level. """ - monkeypatch.setattr("nw.guimain.GuiMain", DummyMain) + monkeypatch.setattr("nw.guimain.GuiMain", MockGuiMain) monkeypatch.setattr(sys, "argv", [ "novelWriter.py", "--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir ]) @@ -140,7 +140,7 @@ def testBaseInit_Options(monkeypatch, tmpDir): def testBaseInit_Imports(caplog, monkeypatch, tmpDir): """Check import error handling. """ - monkeypatch.setattr("nw.guimain.GuiMain", DummyMain) + monkeypatch.setattr("nw.guimain.GuiMain", MockGuiMain) monkeypatch.setattr("PyQt5.QtWidgets.QApplication.__init__", lambda *args: None) monkeypatch.setattr("PyQt5.QtWidgets.QApplication.exec_", lambda *args: 0) monkeypatch.setattr("PyQt5.QtWidgets.QErrorMessage.__init__", lambda *args: None) diff --git a/tests/test_core/test_core_document.py b/tests/test_core/test_core_document.py index 82028d61..42df9d1c 100644 --- a/tests/test_core/test_core_document.py +++ b/tests/test_core/test_core_document.py @@ -23,7 +23,7 @@ along with this program. If not, see . import os import pytest -from dummy import causeOSError +from mock import causeOSError from nw.core import NWProject, NWDoc from nw.enum import nwItemClass, nwItemLayout @@ -39,7 +39,7 @@ def testCoreDocument_LoadSave(monkeypatch, dummyGUI, nwMinimal): sHandle = "8c659a11cd429" # Not a valid handle - theDoc = NWDoc(theProject, "dummy") + theDoc = NWDoc(theProject, "stuff") assert theDoc.readDocument() is None # Non-existent handle @@ -102,7 +102,7 @@ def testCoreDocument_LoadSave(monkeypatch, dummyGUI, nwMinimal): assert not theDoc.writeDocument(theText) # Delete the last document - theDoc = NWDoc(theProject, "dummy") + theDoc = NWDoc(theProject, "stuff") assert not theDoc.deleteDocument() assert os.path.isfile(docPath) diff --git a/tests/test_core/test_core_index.py b/tests/test_core/test_core_index.py index 7dc5c9f8..87ce2b02 100644 --- a/tests/test_core/test_core_index.py +++ b/tests/test_core/test_core_index.py @@ -26,7 +26,7 @@ import json from shutil import copyfile -from dummy import causeException +from mock import causeException from tools import cmpFiles from nw.core.project import NWProject diff --git a/tests/test_core/test_core_options.py b/tests/test_core/test_core_options.py index 6bd26b29..c1ef5209 100644 --- a/tests/test_core/test_core_options.py +++ b/tests/test_core/test_core_options.py @@ -24,7 +24,7 @@ import os import json import pytest -from dummy import causeOSError +from mock import causeOSError from nw.core import NWProject from nw.core.options import OptionState diff --git a/tests/test_core/test_core_project.py b/tests/test_core/test_core_project.py index 8eb918ec..2f016b38 100644 --- a/tests/test_core/test_core_project.py +++ b/tests/test_core/test_core_project.py @@ -28,7 +28,7 @@ from zipfile import ZipFile from lxml import etree from tools import cmpFiles, writeFile, readFile -from dummy import causeOSError +from mock import causeOSError from nw.core.project import NWProject from nw.enum import nwItemClass, nwItemType, nwItemLayout @@ -354,11 +354,11 @@ def testCoreProject_Open(monkeypatch, nwMinimal, dummyGUI): 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") + writeFile(rName, "stuff") assert theProject.openProject(nwMinimal) is False # Also write a jun XML backup file - writeFile(bName, "dummy") + writeFile(bName, "stuff") assert theProject.openProject(nwMinimal) is False # Wrong root item @@ -426,9 +426,9 @@ def testCoreProject_Open(monkeypatch, nwMinimal, dummyGUI): os.rename(oName, rName) # Add some legacy stuff that cannot be removed - writeFile(os.path.join(nwMinimal, "junk"), "dummy") + writeFile(os.path.join(nwMinimal, "junk"), "stuff") os.mkdir(os.path.join(nwMinimal, "data_0")) - writeFile(os.path.join(nwMinimal, "data_0", "junk"), "dummy") + writeFile(os.path.join(nwMinimal, "data_0", "junk"), "stuff") dummyGUI.clear() assert theProject.openProject(nwMinimal) is True assert "data_0" in dummyGUI.lastAlert @@ -559,19 +559,19 @@ def testCoreProject_Helpers(monkeypatch, fncDir, dummyGUI): # Create a file to block meta folder metaDir = os.path.join(fncDir, "meta") - writeFile(metaDir, "dummy") + writeFile(metaDir, "stuff") assert theProject.ensureFolderStructure() is False os.unlink(metaDir) # Create a file to block cache folder cacheDir = os.path.join(fncDir, "cache") - writeFile(cacheDir, "dummy") + writeFile(cacheDir, "stuff") assert theProject.ensureFolderStructure() is False os.unlink(cacheDir) # Create a file to block content folder contentDir = os.path.join(fncDir, "content") - writeFile(contentDir, "dummy") + writeFile(contentDir, "stuff") assert theProject.ensureFolderStructure() is False os.unlink(contentDir) @@ -977,7 +977,7 @@ def testCoreProject_OldFormat(dummyGUI, nwOldProj): """ theProject = NWProject(dummyGUI) - # Create dummy files for known legacy files + # Create mock files for known legacy files deleteFiles = [ os.path.join(nwOldProj, "cache", "nwProject.nwx.0"), os.path.join(nwOldProj, "cache", "nwProject.nwx.1"), @@ -1005,7 +1005,7 @@ def testCoreProject_OldFormat(dummyGUI, nwOldProj): os.mkdir(os.path.join(nwOldProj, "stuff")) os.mkdir(os.path.join(nwOldProj, "data_1", "stuff")) - # Create dummy files + # Create mock files os.mkdir(os.path.join(nwOldProj, "cache")) for aFile in deleteFiles: writeFile(aFile, "Hi") @@ -1071,7 +1071,7 @@ def testCoreProject_LegacyData(monkeypatch, dummyGUI, fncDir): # Check behaviour of deprecated files function on OSError tstFile = os.path.join(fncDir, "ToC.json") - writeFile(tstFile, "dummy") + writeFile(tstFile, "stuff") assert os.path.isfile(tstFile) with monkeypatch.context() as mp: @@ -1083,7 +1083,7 @@ def testCoreProject_LegacyData(monkeypatch, dummyGUI, fncDir): # Check processing non-folders tstFile = os.path.join(fncDir, "data_0") - writeFile(tstFile, "dummy") + writeFile(tstFile, "stuff") assert os.path.isfile(tstFile) errList = [] @@ -1128,12 +1128,12 @@ def testCoreProject_LegacyData(monkeypatch, dummyGUI, fncDir): 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") + writeFile(tstDoc1m, "stuff") + writeFile(tstDoc1b, "stuff") + writeFile(tstDoc2m, "stuff") + writeFile(tstDoc2b, "stuff") + writeFile(tstDoc3m, "stuff") + writeFile(tstDoc3b, "stuff") # Make the above fail with monkeypatch.context() as mp: diff --git a/tests/test_core/test_core_spell.py b/tests/test_core/test_core_spell.py index c1d8ae3d..4c3f3527 100644 --- a/tests/test_core/test_core_spell.py +++ b/tests/test_core/test_core_spell.py @@ -24,7 +24,7 @@ import os import sys import pytest -from dummy import causeOSError +from mock import causeOSError from tools import readFile, writeFile from nw.core.spellcheck import NWSpellCheck, NWSpellEnchant, NWSpellSimple @@ -38,7 +38,7 @@ def testCoreSpell_Super(monkeypatch, tmpDir): spChk = NWSpellCheck() - # Check that dummy functions return results that reflects that spell + # Check that default functions return results that reflects that spell # checking is effectively disabled assert spChk.setLanguage("", "") is None assert spChk.checkWord("") @@ -47,7 +47,7 @@ def testCoreSpell_Super(monkeypatch, tmpDir): assert spChk.describeDict() == ("", "") # Add a word to the user's dictionary - assert spChk._readProjectDictionary("dummy") is False + assert spChk._readProjectDictionary("stuff") is False with monkeypatch.context() as mp: mp.setattr("builtins.open", causeOSError) assert spChk._readProjectDictionary(wList) is False @@ -77,7 +77,7 @@ def testCoreSpell_Enchant(monkeypatch, tmpDir): wList = os.path.join(tmpDir, "wordlist.txt") writeFile(wList, "a_word\nb_word\nc_word\n") - # Block the enchant package (and trigger the dummy class) + # Block the enchant package (and trigger the default class) with monkeypatch.context() as mp: mp.setitem(sys.modules, "enchant", None) spChk = NWSpellEnchant() diff --git a/tests/test_core/test_core_status.py b/tests/test_core/test_core_status.py index ee2ea24e..d3cd7f86 100644 --- a/tests/test_core/test_core_status.py +++ b/tests/test_core/test_core_status.py @@ -49,7 +49,7 @@ def testCoreStatus_Entries(): # Lookups assert theStatus.lookupEntry(None) is None - assert theStatus.lookupEntry("dummy") is None + assert theStatus.lookupEntry("stuff") is None assert theStatus.lookupEntry("Main") == 3 # Checks diff --git a/tests/test_core/test_core_tokenizer.py b/tests/test_core/test_core_tokenizer.py index e766450b..0f4d9f85 100644 --- a/tests/test_core/test_core_tokenizer.py +++ b/tests/test_core/test_core_tokenizer.py @@ -145,13 +145,13 @@ def testCoreToken_TextOps(monkeypatch, nwMinimal, dummyGUI): assert theProject.saveProject() # Root heading - assert theToken.addRootHeading("dummy") is False + assert theToken.addRootHeading("stuff") is False assert theToken.addRootHeading(sHandle) is False assert theToken.addRootHeading("7695ce551d265") is True assert theToken.theMarkdown[-1] == "# Notes: Plot\n\n" # Set text - assert theToken.setText("dummy") is False + assert theToken.setText("stuff") is False assert theToken.setText(sHandle) is True assert theToken.theText == docText diff --git a/tests/test_core/test_core_tree.py b/tests/test_core/test_core_tree.py index 803e88c4..8f51b906 100644 --- a/tests/test_core/test_core_tree.py +++ b/tests/test_core/test_core_tree.py @@ -31,7 +31,7 @@ from nw.constants import nwFiles @pytest.fixture(scope="function") def dummyItems(dummyGUI): - """Create a list of dummy items. + """Create a list of mock items. """ theProject = NWProject(dummyGUI) @@ -176,7 +176,7 @@ def testCoreTree_BuildTree(dummyGUI, dummyItems): assert len(theTree) == len(dummyItems) + 1 # Delete a non-existing item - del theTree["dummy"] + del theTree["stuff"] assert len(theTree) == len(dummyItems) + 1 # Delete the last item @@ -214,7 +214,7 @@ def testCoreTree_Methods(dummyGUI, dummyItems): assert len(theTree) == len(dummyItems) # Root item lookup - theTree._treeRoots.append("dummy") + theTree._treeRoots.append("stuff") assert theTree.findRoot(nwItemClass.WORLD) is None assert theTree.findRoot(nwItemClass.NOVEL) == "a000000000001" assert theTree.findRoot(nwItemClass.CHARACTER) == "a000000000004" @@ -229,16 +229,16 @@ def testCoreTree_Methods(dummyGUI, dummyItems): assert theTree.getRootItem("b000000000001").itemHandle == "a000000000001" assert theTree.getRootItem("c000000000001").itemHandle == "a000000000001" assert theTree.getRootItem("c000000000002").itemHandle == "a000000000001" - assert theTree.getRootItem("dummy") is None + assert theTree.getRootItem("stuff") is None # Get item path - assert theTree.getItemPath("dummy") == [] + assert theTree.getItemPath("stuff") == [] assert theTree.getItemPath("c000000000001") == [ "c000000000001", "b000000000001", "a000000000001" ] # Break the folder parent handle - theTree["b000000000001"].itemParent = "dummy" + theTree["b000000000001"].itemParent = "stuff" assert theTree.getItemPath("c000000000001") == [ "c000000000001", "b000000000001" ] @@ -249,7 +249,7 @@ def testCoreTree_Methods(dummyGUI, dummyItems): ] # Change file layout - assert not theTree.setFileItemLayout("dummy", nwItemLayout.UNNUMBERED) + assert not theTree.setFileItemLayout("stuff", nwItemLayout.UNNUMBERED) assert not theTree.setFileItemLayout("b000000000001", nwItemLayout.UNNUMBERED) assert not theTree.setFileItemLayout("c000000000001", "stuff") assert theTree.setFileItemLayout("c000000000001", nwItemLayout.UNNUMBERED) @@ -424,7 +424,7 @@ def testCoreTree_Stats(dummyGUI, dummyItems): theTree.append(tHandle, pHandle, nwItem) assert len(theTree) == len(dummyItems) - theTree._treeOrder.append("dummy") + theTree._treeOrder.append("stuff") # Count Words novelWords, noteWords = theTree.sumWords() @@ -461,10 +461,10 @@ def testCoreTree_Reorder(dummyGUI, dummyItems): theTree.setOrder(bHandle) assert theTree.handles() == bHandle - theTree.setOrder(bHandle + ["dummy"]) + theTree.setOrder(bHandle + ["stuff"]) assert theTree.handles() == bHandle - theTree._treeOrder.append("dummy") + theTree._treeOrder.append("stuff") theTree.setOrder(bHandle) assert theTree.handles() == bHandle @@ -536,7 +536,7 @@ def testCoreTree_ToCFile(monkeypatch, dummyGUI, dummyItems, tmpDir): theTree.append(tHandle, pHandle, nwItem) assert len(theTree) == len(dummyItems) - theTree._treeOrder.append("dummy") + theTree._treeOrder.append("stuff") def dummyIsFile(fileName): """Return True for items that are files in novelWriter and diff --git a/tests/test_dialogs/test_dlg_wordlist.py b/tests/test_dialogs/test_dlg_wordlist.py index 6cd7b4ee..31cfb9e0 100644 --- a/tests/test_dialogs/test_dlg_wordlist.py +++ b/tests/test_dialogs/test_dlg_wordlist.py @@ -26,7 +26,7 @@ from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QDialog, QMessageBox, QAction from tools import writeFile, readFile, getGuiItem -from dummy import causeOSError +from mock import causeOSError from nw.dialogs import GuiWordList from nw.constants import nwFiles diff --git a/tests/test_gui/test_gui_doceditor.py b/tests/test_gui/test_gui_doceditor.py index 12ac5949..451f1f47 100644 --- a/tests/test_gui/test_gui_doceditor.py +++ b/tests/test_gui/test_gui_doceditor.py @@ -249,14 +249,14 @@ def testGuiEditor_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj, refDir, outDi qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) - for c in "This is a paragraph of dummy text.": + for c in "This is a paragraph of nonsense text.": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in ( - "This is another paragraph of much longer dummy text. " - "It is in fact 1 very very DUMB dummy text! " + "This is another paragraph of much longer nonsense text. " + "It is in fact 1 very very NONSENSICAL nonsense text! " ): qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) for c in "We can also try replacing \"quotes\", even single 'quotes' are replaced. ": diff --git a/tests/test_gui/test_gui_theme.py b/tests/test_gui/test_gui_theme.py index ce719ea2..0e6b1e34 100644 --- a/tests/test_gui/test_gui_theme.py +++ b/tests/test_gui/test_gui_theme.py @@ -165,7 +165,7 @@ def testGuiTheme_Main(qtbot, monkeypatch, nwMinimal, tmpDir): assert isinstance(anIcon, QIcon) assert not anIcon.isNull() - # Add dummy icons and test alternative load paths + # Add test icons and test alternative load paths theIcons.ICON_MAP["testicon1"] = (QStyle.SP_DriveHDIcon, None) anIcon = theIcons.getIcon("testicon1") assert isinstance(anIcon, QIcon) diff --git a/tests/test_tools/test_tools_writingstats.py b/tests/test_tools/test_tools_writingstats.py index c72de22c..10f4fddc 100644 --- a/tests/test_tools/test_tools_writingstats.py +++ b/tests/test_tools/test_tools_writingstats.py @@ -25,7 +25,7 @@ import json import os from tools import getGuiItem, writeFile -from dummy import causeOSError +from mock import causeOSError from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QAction, QFileDialog, QMessageBox From c6cbc8a8b18384bce03863e5471fa07b5b929e19 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 2 May 2021 18:52:36 +0200 Subject: [PATCH 10/12] New merge tool test --- nw/dialogs/docmerge.py | 30 +-- tests/test_dialogs/test_dlg_merge.py | 182 ++++++++++++++++++ ...st_dlg_mergesplit.py => test_dlg_split.py} | 0 3 files changed, 197 insertions(+), 15 deletions(-) create mode 100644 tests/test_dialogs/test_dlg_merge.py rename tests/test_dialogs/{test_dlg_mergesplit.py => test_dlg_split.py} (100%) diff --git a/nw/dialogs/docmerge.py b/nw/dialogs/docmerge.py index b873575a..fe5b5511 100644 --- a/nw/dialogs/docmerge.py +++ b/nw/dialogs/docmerge.py @@ -105,32 +105,30 @@ class GuiDocMerge(QDialog): self.theParent.makeAlert( self.tr("No source documents found. Nothing to do."), nwAlert.ERROR ) - return + return False theText = "" for tHandle in finalOrder: inDoc = NWDoc(self.theProject, tHandle) - docText = inDoc.readDocument().rstrip("\n") + docText = inDoc.readDocument() docErr = inDoc.getError() if docText is None and docErr: - self.makeAlert( + self.theParent.makeAlert( [self.tr("Failed to open document file."), docErr], nwAlert.ERROR ) if docText: - theText += docText+"\n\n" + theText += docText.rstrip("\n")+"\n\n" if self.sourceItem is None: self.theParent.makeAlert( - self.tr("No source document selected. Nothing to do."), nwAlert.ERROR + self.tr("No source folder selected. Nothing to do."), nwAlert.ERROR ) - return + return False srcItem = self.theProject.projTree[self.sourceItem] if srcItem is None: - self.theParent.makeAlert( - self.tr("Could not parse source document."), nwAlert.ERROR - ) - return + self.theParent.makeAlert(self.tr("Internal error."), nwAlert.ERROR) + return False nHandle = self.theProject.newFile(srcItem.itemName, srcItem.itemClass, srcItem.itemParent) newItem = self.theProject.projTree[nHandle] @@ -141,13 +139,14 @@ class GuiDocMerge(QDialog): self.theParent.makeAlert( [self.tr("Could not save document."), outDoc.getError()], nwAlert.ERROR ) + return False self.theParent.treeView.revealNewTreeItem(nHandle) self.theParent.openDocument(nHandle, doScroll=True) self._doClose() - return + return True def _doClose(self): """Close the dialog window without doing anything. @@ -168,16 +167,17 @@ class GuiDocMerge(QDialog): tHandle = self.theParent.treeView.getSelectedHandle() self.sourceItem = tHandle if tHandle is None: - return + return False nwItem = self.theProject.projTree[tHandle] if nwItem is None: - return + return False + if nwItem.itemType is not nwItemType.FOLDER: self.theParent.makeAlert( self.tr("Element selected in the project tree must be a folder."), nwAlert.ERROR ) - return + return False for sHandle in self.theParent.treeView.getTreeFromHandle(tHandle): newItem = QListWidgetItem() @@ -188,6 +188,6 @@ class GuiDocMerge(QDialog): newItem.setData(Qt.UserRole, sHandle) self.listBox.addItem(newItem) - return + return True # END Class GuiDocMerge diff --git a/tests/test_dialogs/test_dlg_merge.py b/tests/test_dialogs/test_dlg_merge.py new file mode 100644 index 00000000..d4e35d7e --- /dev/null +++ b/tests/test_dialogs/test_dlg_merge.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +""" +novelWriter – Merge and Split Dialog Classes Tester +=================================================== + +This file is a part of novelWriter +Copyright 2018–2021, Veronica Berglyd Olsen + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" + +import pytest +import os + +from tools import getGuiItem, readFile, writeFile +from mock import causeOSError + +from PyQt5.QtWidgets import QAction, QMessageBox, QDialog + +from nw.dialogs import GuiDocMerge, GuiItemEditor +from nw.enum import nwItemType, nwWidget +from nw.core.tree import NWTree + +keyDelay = 2 +typeDelay = 1 +stepDelay = 20 + +@pytest.mark.gui +def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj): + """Test the merge documents tool. + """ + # Block message box + monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes) + monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Ok) + + # Create a new project + nwGUI.theProject.projTree.setSeed(42) + assert nwGUI.newProject({"projPath": fncProj}) + + # Handles for new objects + hChapterDir = "31489056e0916" + hChapterOne = "98010bd9270f9" + hSceneOne = "0e17daca5f3e1" + hSceneTwo = "1a6562590ef19" + hSceneThree = "031b4af5197ec" + hSceneFour = "41cfc0d1f2d12" + hMergedDoc = "2858dcd1057d3" + + # Add Project Content + monkeypatch.setattr(GuiItemEditor, "exec_", lambda *a: QDialog.Accepted) + nwGUI.switchFocus(nwWidget.TREE) + nwGUI.treeView.clearSelection() + nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True) + nwGUI.treeView.newTreeItem(nwItemType.FILE, None) + nwGUI.treeView.newTreeItem(nwItemType.FILE, None) + nwGUI.treeView.newTreeItem(nwItemType.FILE, None) + + assert nwGUI.saveProject() + assert nwGUI.closeProject() + + tChapterOne = "## Chapter One\n\n% Chapter one comment\n" + tSceneOne = "### Scene One\n\nThere once was a man from Nantucket" + tSceneTwo = "### Scene Two\n\nWho kept all his cash in a bucket." + tSceneThree = "### Scene Three\n\n\tBut his daughter, named Nan, \n\tRan away with a man" + tSceneFour = "### Scene Four\n\nAnd as for the bucket, Nantucket." + + contentDir = os.path.join(fncProj, "content") + writeFile(os.path.join(contentDir, hChapterOne+".nwd"), tChapterOne) + writeFile(os.path.join(contentDir, hSceneOne+".nwd"), tSceneOne) + writeFile(os.path.join(contentDir, hSceneTwo+".nwd"), tSceneTwo) + writeFile(os.path.join(contentDir, hSceneThree+".nwd"), tSceneThree) + writeFile(os.path.join(contentDir, hSceneFour+".nwd"), tSceneFour) + + assert nwGUI.openProject(fncProj) + + # Open the Merge tool + nwGUI.switchFocus(nwWidget.TREE) + nwGUI.treeView.clearSelection() + nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True) + + monkeypatch.setattr(GuiDocMerge, "exec_", lambda *a: None) + nwGUI.mainMenu.aMergeDocs.activate(QAction.Trigger) + qtbot.waitUntil(lambda: getGuiItem("GuiDocMerge") is not None, timeout=1000) + + nwMerge = getGuiItem("GuiDocMerge") + assert isinstance(nwMerge, GuiDocMerge) + nwMerge.show() + qtbot.wait(stepDelay) + + # Populate List + # ============= + + nwMerge.listBox.clear() + assert nwMerge.listBox.count() == 0 + + # No item selected + nwGUI.treeView.clearSelection() + assert not nwMerge._populateList() + assert nwMerge.listBox.count() == 0 + + # Non-existing item + with monkeypatch.context() as mp: + mp.setattr(NWTree, "__getitem__", lambda *a: None) + nwGUI.treeView.clearSelection() + nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True) + assert not nwMerge._populateList() + assert nwMerge.listBox.count() == 0 + + # Select a non-folder + nwGUI.treeView.clearSelection() + nwGUI.treeView._getTreeItem(hChapterOne).setSelected(True) + assert not nwMerge._populateList() + assert nwMerge.listBox.count() == 0 + + # Select the chapter folder + nwGUI.treeView.clearSelection() + nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True) + assert nwMerge._populateList() + assert nwMerge.listBox.count() == 5 + + # Merge Documents + # =============== + + # First, a successful merge + with monkeypatch.context() as mp: + mp.setattr(GuiDocMerge, "_doClose", lambda *a: None) + assert nwMerge._doMerge() + assert nwGUI.saveProject() + mergedFile = os.path.join(contentDir, hMergedDoc+".nwd") + assert os.path.isfile(mergedFile) + assert readFile(mergedFile) == ( + "%%%%~name: New Chapter\n" + "%%%%~path: 73475cb40a568/2858dcd1057d3\n" + "%%%%~kind: NOVEL/SCENE\n" + "%s\n\n" + "%s\n\n" + "%s\n\n" + "%s\n\n" + "%s\n\n" + ) % ( + tChapterOne.strip(), + tSceneOne.strip(), + tSceneTwo.strip(), + tSceneThree.strip(), + tSceneFour.strip(), + ) + + # OS error + with monkeypatch.context() as mp: + mp.setattr("builtins.open", causeOSError) + assert not nwMerge._doMerge() + + # Can't find the source item + with monkeypatch.context() as mp: + mp.setattr(NWTree, "__getitem__", lambda *a: None) + assert not nwMerge._doMerge() + + # No source handle set + nwMerge.sourceItem = None + assert not nwMerge._doMerge() + + # No documents to merge + nwMerge.listBox.clear() + assert not nwMerge._doMerge() + + # Close up + nwMerge._doClose() + + # qtbot.stopForInteraction() + +# END Test testDlgMerge_Main diff --git a/tests/test_dialogs/test_dlg_mergesplit.py b/tests/test_dialogs/test_dlg_split.py similarity index 100% rename from tests/test_dialogs/test_dlg_mergesplit.py rename to tests/test_dialogs/test_dlg_split.py From ce8264b8f2f682bf946cf41798aadc968b6e73be Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 2 May 2021 19:47:04 +0200 Subject: [PATCH 11/12] New split tool test --- nw/dialogs/docsplit.py | 25 ++- tests/conftest.py | 4 +- tests/test_dialogs/test_dlg_merge.py | 26 +-- tests/test_dialogs/test_dlg_split.py | 310 +++++++++++++++++---------- 4 files changed, 222 insertions(+), 143 deletions(-) diff --git a/nw/dialogs/docsplit.py b/nw/dialogs/docsplit.py index d284056f..87aaf0f4 100644 --- a/nw/dialogs/docsplit.py +++ b/nw/dialogs/docsplit.py @@ -118,14 +118,14 @@ class GuiDocSplit(QDialog): self.theParent.makeAlert( self.tr("No source document selected. Nothing to do."), nwAlert.ERROR ) - return + return False srcItem = self.theProject.projTree[self.sourceItem] if srcItem is None: self.theParent.makeAlert( self.tr("Could not parse source document."), nwAlert.ERROR ) - return + return False inDoc = NWDoc(self.theProject, self.sourceItem) theText = inDoc.readDocument() @@ -160,7 +160,7 @@ class GuiDocSplit(QDialog): self.theParent.makeAlert( self.tr("No headers found. Nothing to do."), nwAlert.ERROR ) - return + return False # Check that another folder can be created parTree = self.theProject.projTree.getItemPath(srcItem.itemParent) @@ -172,7 +172,7 @@ class GuiDocSplit(QDialog): "Please move the file to another level in the project tree." ), nwAlert.ERROR ) - return + return False msgYes = self.theParent.askQuestion( self.tr("Split Document"), @@ -186,7 +186,7 @@ class GuiDocSplit(QDialog): ) ) if not msgYes: - return + return False # Create the folder fHandle = self.theProject.newFolder( @@ -230,12 +230,13 @@ class GuiDocSplit(QDialog): self.theParent.makeAlert( [self.tr("Could not save document."), outDoc.getError()], nwAlert.ERROR ) + return False self.theParent.treeView.revealNewTreeItem(nHandle) self._doClose() - return + return True def _doClose(self): """Close the dialog window without doing anything. @@ -254,26 +255,28 @@ class GuiDocSplit(QDialog): are then added to the list view in order. The list itself can be reordered by the user. """ + self.listBox.clear() if self.sourceItem is None: self.sourceItem = self.theParent.treeView.getSelectedHandle() if self.sourceItem is None: - return + return False nwItem = self.theProject.projTree[self.sourceItem] if nwItem is None: - return + return False + if nwItem.itemType is not nwItemType.FILE: self.theParent.makeAlert( self.tr("Element selected in the project tree must be a file."), nwAlert.ERROR ) - return + return False - self.listBox.clear() inDoc = NWDoc(self.theProject, self.sourceItem) theText = inDoc.readDocument() if theText is None: theText = "" + return False spLevel = self.splitLevel.currentData() self.optState.setValue("GuiDocSplit", "spLevel", spLevel) @@ -302,6 +305,6 @@ class GuiDocSplit(QDialog): newItem.setData(Qt.UserRole, onLine) self.listBox.addItem(newItem) - return + return True # END Class GuiDocSplit diff --git a/tests/conftest.py b/tests/conftest.py index 7c9925a5..7459f21a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -88,8 +88,8 @@ def fncDir(tmpDir): if not os.path.isdir(fncDir): os.mkdir(fncDir) yield fncDir - # if os.path.isdir(fncDir): - # shutil.rmtree(fncDir) + if os.path.isdir(fncDir): + shutil.rmtree(fncDir) return @pytest.fixture(scope="function") diff --git a/tests/test_dialogs/test_dlg_merge.py b/tests/test_dialogs/test_dlg_merge.py index d4e35d7e..52e8e892 100644 --- a/tests/test_dialogs/test_dlg_merge.py +++ b/tests/test_dialogs/test_dlg_merge.py @@ -66,8 +66,8 @@ def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj): nwGUI.treeView.newTreeItem(nwItemType.FILE, None) nwGUI.treeView.newTreeItem(nwItemType.FILE, None) - assert nwGUI.saveProject() - assert nwGUI.closeProject() + assert nwGUI.saveProject() is True + assert nwGUI.closeProject() is True tChapterOne = "## Chapter One\n\n% Chapter one comment\n" tSceneOne = "### Scene One\n\nThere once was a man from Nantucket" @@ -82,7 +82,7 @@ def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj): writeFile(os.path.join(contentDir, hSceneThree+".nwd"), tSceneThree) writeFile(os.path.join(contentDir, hSceneFour+".nwd"), tSceneFour) - assert nwGUI.openProject(fncProj) + assert nwGUI.openProject(fncProj) is True # Open the Merge tool nwGUI.switchFocus(nwWidget.TREE) @@ -106,7 +106,7 @@ def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj): # No item selected nwGUI.treeView.clearSelection() - assert not nwMerge._populateList() + assert nwMerge._populateList() is False assert nwMerge.listBox.count() == 0 # Non-existing item @@ -114,19 +114,19 @@ def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj): mp.setattr(NWTree, "__getitem__", lambda *a: None) nwGUI.treeView.clearSelection() nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True) - assert not nwMerge._populateList() + assert nwMerge._populateList() is False assert nwMerge.listBox.count() == 0 # Select a non-folder nwGUI.treeView.clearSelection() nwGUI.treeView._getTreeItem(hChapterOne).setSelected(True) - assert not nwMerge._populateList() + assert nwMerge._populateList() is False assert nwMerge.listBox.count() == 0 # Select the chapter folder nwGUI.treeView.clearSelection() nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True) - assert nwMerge._populateList() + assert nwMerge._populateList() is True assert nwMerge.listBox.count() == 5 # Merge Documents @@ -135,8 +135,8 @@ def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj): # First, a successful merge with monkeypatch.context() as mp: mp.setattr(GuiDocMerge, "_doClose", lambda *a: None) - assert nwMerge._doMerge() - assert nwGUI.saveProject() + assert nwMerge._doMerge() is True + assert nwGUI.saveProject() is True mergedFile = os.path.join(contentDir, hMergedDoc+".nwd") assert os.path.isfile(mergedFile) assert readFile(mergedFile) == ( @@ -159,20 +159,20 @@ def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj): # OS error with monkeypatch.context() as mp: mp.setattr("builtins.open", causeOSError) - assert not nwMerge._doMerge() + assert nwMerge._doMerge() is False # Can't find the source item with monkeypatch.context() as mp: mp.setattr(NWTree, "__getitem__", lambda *a: None) - assert not nwMerge._doMerge() + assert nwMerge._doMerge() is False # No source handle set nwMerge.sourceItem = None - assert not nwMerge._doMerge() + assert nwMerge._doMerge() is False # No documents to merge nwMerge.listBox.clear() - assert not nwMerge._doMerge() + assert nwMerge._doMerge() is False # Close up nwMerge._doClose() diff --git a/tests/test_dialogs/test_dlg_split.py b/tests/test_dialogs/test_dlg_split.py index 8a44fa4f..87d2f837 100644 --- a/tests/test_dialogs/test_dlg_split.py +++ b/tests/test_dialogs/test_dlg_split.py @@ -23,56 +23,80 @@ along with this program. If not, see . import pytest import os -from shutil import copyfile -from tools import cmpFiles, getGuiItem +from tools import getGuiItem, readFile, writeFile +from mock import causeOSError -from PyQt5.QtWidgets import QAction, QMessageBox +from PyQt5.QtWidgets import QAction, QMessageBox, QDialog -from nw.dialogs import GuiDocMerge, GuiDocSplit +from nw.dialogs import GuiDocSplit, GuiItemEditor +from nw.enum import nwItemType, nwWidget +from nw.core.document import NWDoc +from nw.core.tree import NWTree keyDelay = 2 typeDelay = 1 stepDelay = 20 @pytest.mark.gui -def testDlgMergeSplit_Tools(qtbot, monkeypatch, nwGUI, nwLipsum, refDir, outDir): - """Test the full merge and split tools. +def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj): + """Test the split document tool. """ # Block message box - monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes) + monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes) + monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Ok) + # Create a new project nwGUI.theProject.projTree.setSeed(42) - assert nwGUI.openProject(nwLipsum) - qtbot.wait(stepDelay) + assert nwGUI.newProject({"projPath": fncProj}) is True - assert nwGUI.treeView.setSelectedHandle("45e6b01ca35c1") - qtbot.wait(stepDelay) + # Handles for new objects + hNovelRoot = "73475cb40a568" + hChapterDir = "31489056e0916" + hToSplit = "1a6562590ef19" + hPartition = "41cfc0d1f2d12" + hChapterOne = "2858dcd1057d3" + hSceneOne = "2fca346db6561" + hSceneTwo = "02d20bbd7e394" + hSceneThree = "7688b6ef52555" + hSceneFour = "c837649cce43f" + hSceneFive = "6208ef0f7750c" - monkeypatch.setattr(GuiDocMerge, "exec_", lambda *args: None) - nwGUI.mainMenu.aMergeDocs.activate(QAction.Trigger) - qtbot.waitUntil(lambda: getGuiItem("GuiDocMerge") is not None, timeout=1000) + # Add Project Content + monkeypatch.setattr(GuiItemEditor, "exec_", lambda *a: QDialog.Accepted) + nwGUI.switchFocus(nwWidget.TREE) + nwGUI.treeView.clearSelection() + nwGUI.treeView._getTreeItem(hNovelRoot).setSelected(True) + nwGUI.treeView.newTreeItem(nwItemType.FILE, None) - nwMerge = getGuiItem("GuiDocMerge") - assert isinstance(nwMerge, GuiDocMerge) - nwMerge.show() - qtbot.wait(stepDelay) + assert nwGUI.saveProject() is True + assert nwGUI.closeProject() is True - nwMerge._doMerge() - qtbot.wait(stepDelay) + tPartition = "# Nantucket" + tChapterOne = "## Chapter One\n\n% Chapter one comment" + tSceneOne = "### Scene One\n\nThere once was a man from Nantucket" + tSceneTwo = "### Scene Two\n\nWho kept all his cash in a bucket." + tSceneThree = "### Scene Three\n\n\tBut his daughter, named Nan, \n\tRan away with a man" + tSceneFour = "### Scene Four\n\nAnd as for the bucket, Nantucket." + tSceneFive = "#### The End\n\nend" - assert nwGUI.theProject.projTree["73475cb40a568"] is not None + tToSplit = ( + f"{tPartition}\n\n{tChapterOne}\n\n" + f"{tSceneOne}\n\n{tSceneTwo}\n\n" + f"{tSceneThree}\n\n{tSceneFour}\n\n" + f"{tSceneFive}\n\n" + ) - projFile = os.path.join(nwLipsum, "content", "73475cb40a568.nwd") - testFile = os.path.join(outDir, "guiMerge_73475cb40a568.nwd") - compFile = os.path.join(refDir, "guiMerge_73475cb40a568.nwd") - copyfile(projFile, testFile) - assert cmpFiles(testFile, compFile) + contentDir = os.path.join(fncProj, "content") + writeFile(os.path.join(contentDir, hToSplit+".nwd"), tToSplit) - # Split By Chapter - assert nwGUI.treeView.setSelectedHandle("73475cb40a568") - qtbot.wait(stepDelay) + assert nwGUI.openProject(fncProj) is True - monkeypatch.setattr(GuiDocSplit, "exec_", lambda *args: None) + # Open the Split tool + nwGUI.switchFocus(nwWidget.TREE) + nwGUI.treeView.clearSelection() + nwGUI.treeView._getTreeItem(hToSplit).setSelected(True) + + monkeypatch.setattr(GuiDocSplit, "exec_", lambda *a: None) nwGUI.mainMenu.aSplitDoc.activate(QAction.Trigger) qtbot.waitUntil(lambda: getGuiItem("GuiDocSplit") is not None, timeout=1000) @@ -81,105 +105,157 @@ def testDlgMergeSplit_Tools(qtbot, monkeypatch, nwGUI, nwLipsum, refDir, outDir) nwSplit.show() qtbot.wait(stepDelay) + # Populate List + # ============= + + nwSplit.listBox.clear() + assert nwSplit.listBox.count() == 0 + + # No item selected + nwSplit.sourceItem = None + nwGUI.treeView.clearSelection() + assert nwSplit._populateList() is False + assert nwSplit.listBox.count() == 0 + + # Non-existing item + with monkeypatch.context() as mp: + mp.setattr(NWTree, "__getitem__", lambda *a: None) + nwSplit.sourceItem = None + nwGUI.treeView.clearSelection() + nwGUI.treeView._getTreeItem(hToSplit).setSelected(True) + assert nwSplit._populateList() is False + assert nwSplit.listBox.count() == 0 + + # Select a non-file + nwSplit.sourceItem = None + nwGUI.treeView.clearSelection() + nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True) + assert nwSplit._populateList() is False + assert nwSplit.listBox.count() == 0 + + # Error when reading documents + with monkeypatch.context() as mp: + mp.setattr(NWDoc, "readDocument", lambda *a: None) + nwSplit.sourceItem = hToSplit + assert nwSplit._populateList() is False + assert nwSplit.listBox.count() == 0 + + # Read properly, and check split levels + + # Level 1 + nwSplit.splitLevel.setCurrentIndex(0) + nwSplit.sourceItem = hToSplit + assert nwSplit._populateList() is True + assert nwSplit.listBox.count() == 1 + + # Level 2 nwSplit.splitLevel.setCurrentIndex(1) - qtbot.wait(stepDelay) + nwSplit.sourceItem = hToSplit + assert nwSplit._populateList() is True + assert nwSplit.listBox.count() == 2 - nwSplit._doSplit() - assert nwGUI.theProject.projTree["71ee45a3c0db9"] is not None - - # This should give us back the file as it was before - projFile = os.path.join(nwLipsum, "content", "71ee45a3c0db9.nwd") - testFile = os.path.join(outDir, "guiMerge_71ee45a3c0db9.nwd") - compFile = os.path.join(refDir, "guiMerge_73475cb40a568.nwd") - copyfile(projFile, testFile) - assert cmpFiles(testFile, compFile, [1, 2, 3]) - - # Split By Scene - assert nwGUI.treeView.setSelectedHandle("73475cb40a568") - qtbot.wait(stepDelay) - nwGUI.mainMenu.aSplitDoc.activate(QAction.Trigger) - qtbot.waitUntil(lambda: getGuiItem("GuiDocSplit") is not None, timeout=1000) - - nwSplit = getGuiItem("GuiDocSplit") - assert isinstance(nwSplit, GuiDocSplit) - qtbot.wait(stepDelay) + # Level 3 nwSplit.splitLevel.setCurrentIndex(2) - qtbot.wait(stepDelay) + nwSplit.sourceItem = hToSplit + assert nwSplit._populateList() is True + assert nwSplit.listBox.count() == 6 - nwSplit._doSplit() - - assert nwGUI.theProject.projTree["25fc0e7096fc6"] is not None - assert nwGUI.theProject.projTree["31489056e0916"] is not None - assert nwGUI.theProject.projTree["98010bd9270f9"] is not None - - projFile = os.path.join(nwLipsum, "content", "25fc0e7096fc6.nwd") - testFile = os.path.join(outDir, "guiSplit_25fc0e7096fc6.nwd") - compFile = os.path.join(refDir, "guiSplit_25fc0e7096fc6.nwd") - copyfile(projFile, testFile) - assert cmpFiles(testFile, compFile) - - projFile = os.path.join(nwLipsum, "content", "31489056e0916.nwd") - testFile = os.path.join(outDir, "guiSplit_31489056e0916.nwd") - compFile = os.path.join(refDir, "guiSplit_31489056e0916.nwd") - copyfile(projFile, testFile) - assert cmpFiles(testFile, compFile) - - projFile = os.path.join(nwLipsum, "content", "98010bd9270f9.nwd") - testFile = os.path.join(outDir, "guiSplit_98010bd9270f9.nwd") - compFile = os.path.join(refDir, "guiSplit_98010bd9270f9.nwd") - copyfile(projFile, testFile) - assert cmpFiles(testFile, compFile) - - # Split By Section - assert nwGUI.treeView.setSelectedHandle("73475cb40a568") - qtbot.wait(stepDelay) - nwGUI.mainMenu.aSplitDoc.activate(QAction.Trigger) - qtbot.waitUntil(lambda: getGuiItem("GuiDocSplit") is not None, timeout=1000) - - nwSplit = getGuiItem("GuiDocSplit") - assert isinstance(nwSplit, GuiDocSplit) - qtbot.wait(stepDelay) + # Level 4 nwSplit.splitLevel.setCurrentIndex(3) - qtbot.wait(stepDelay) + nwSplit.sourceItem = hToSplit + assert nwSplit._populateList() is True + assert nwSplit.listBox.count() == 7 - nwSplit._doSplit() + # Split Document + # ============== - assert nwGUI.theProject.projTree["1a6562590ef19"] is not None - assert nwGUI.theProject.projTree["031b4af5197ec"] is not None - assert nwGUI.theProject.projTree["41cfc0d1f2d12"] is not None - assert nwGUI.theProject.projTree["2858dcd1057d3"] is not None - assert nwGUI.theProject.projTree["2fca346db6561"] is not None + # Test a proper split first + with monkeypatch.context() as mp: + mp.setattr(GuiDocSplit, "_doClose", lambda *a: None) + assert nwSplit._doSplit() is True + assert nwGUI.saveProject() - projFile = os.path.join(nwLipsum, "content", "1a6562590ef19.nwd") - testFile = os.path.join(outDir, "guiSplit_1a6562590ef19.nwd") - compFile = os.path.join(refDir, "guiSplit_25fc0e7096fc6.nwd") - copyfile(projFile, testFile) - assert cmpFiles(testFile, compFile, [1, 2, 3]) + assert readFile(os.path.join(contentDir, hPartition+".nwd")) == ( + "%%%%~name: Nantucket\n" + "%%%%~path: 031b4af5197ec/%s\n" + "%%%%~kind: NOVEL/PARTITION\n" + "%s\n\n" + ) % (hPartition, tPartition) - projFile = os.path.join(nwLipsum, "content", "031b4af5197ec.nwd") - testFile = os.path.join(outDir, "guiSplit_031b4af5197ec.nwd") - compFile = os.path.join(refDir, "guiSplit_031b4af5197ec.nwd") - copyfile(projFile, testFile) - assert cmpFiles(testFile, compFile) + assert readFile(os.path.join(contentDir, hChapterOne+".nwd")) == ( + "%%%%~name: Chapter One\n" + "%%%%~path: 031b4af5197ec/%s\n" + "%%%%~kind: NOVEL/CHAPTER\n" + "%s\n\n" + ) % (hChapterOne, tChapterOne) - projFile = os.path.join(nwLipsum, "content", "41cfc0d1f2d12.nwd") - testFile = os.path.join(outDir, "guiSplit_41cfc0d1f2d12.nwd") - compFile = os.path.join(refDir, "guiSplit_41cfc0d1f2d12.nwd") - copyfile(projFile, testFile) - assert cmpFiles(testFile, compFile) + assert readFile(os.path.join(contentDir, hSceneOne+".nwd")) == ( + "%%%%~name: Scene One\n" + "%%%%~path: 031b4af5197ec/%s\n" + "%%%%~kind: NOVEL/SCENE\n" + "%s\n\n" + ) % (hSceneOne, tSceneOne) - projFile = os.path.join(nwLipsum, "content", "2858dcd1057d3.nwd") - testFile = os.path.join(outDir, "guiSplit_2858dcd1057d3.nwd") - compFile = os.path.join(refDir, "guiSplit_2858dcd1057d3.nwd") - copyfile(projFile, testFile) - assert cmpFiles(testFile, compFile) + assert readFile(os.path.join(contentDir, hSceneTwo+".nwd")) == ( + "%%%%~name: Scene Two\n" + "%%%%~path: 031b4af5197ec/%s\n" + "%%%%~kind: NOVEL/SCENE\n" + "%s\n\n" + ) % (hSceneTwo, tSceneTwo) - projFile = os.path.join(nwLipsum, "content", "2fca346db6561.nwd") - testFile = os.path.join(outDir, "guiSplit_2fca346db6561.nwd") - compFile = os.path.join(refDir, "guiSplit_2fca346db6561.nwd") - copyfile(projFile, testFile) - assert cmpFiles(testFile, compFile) + assert readFile(os.path.join(contentDir, hSceneThree+".nwd")) == ( + "%%%%~name: Scene Three\n" + "%%%%~path: 031b4af5197ec/%s\n" + "%%%%~kind: NOVEL/SCENE\n" + "%s\n\n" + ) % (hSceneThree, tSceneThree) + + assert readFile(os.path.join(contentDir, hSceneFour+".nwd")) == ( + "%%%%~name: Scene Four\n" + "%%%%~path: 031b4af5197ec/%s\n" + "%%%%~kind: NOVEL/SCENE\n" + "%s\n\n" + ) % (hSceneFour, tSceneFour) + + assert readFile(os.path.join(contentDir, hSceneFive+".nwd")) == ( + "%%%%~name: The End\n" + "%%%%~path: 031b4af5197ec/%s\n" + "%%%%~kind: NOVEL/SCENE\n" + "%s\n\n" + ) % (hSceneFive, tSceneFive) + + # OS error + with monkeypatch.context() as mp: + mp.setattr("builtins.open", causeOSError) + assert nwSplit._doSplit() is False + + # Select to not split + with monkeypatch.context() as mp: + mp.setattr(QMessageBox, "question", lambda *a: QMessageBox.No) + assert nwSplit._doSplit() is False + + # Block folder creation by returning that the folder has a depth + # of 50 items in the tree + with monkeypatch.context() as mp: + mp.setattr(NWTree, "getItemPath", lambda *a: [""]*50) + assert nwSplit._doSplit() is False + + # Clear the list + nwSplit.listBox.clear() + assert nwSplit._doSplit() is False + + # Can't find sourcv item + with monkeypatch.context() as mp: + mp.setattr(NWTree, "__getitem__", lambda *a: None) + assert nwSplit._doSplit() is False + + # No source item set + nwSplit.sourceItem = None + assert nwSplit._doSplit() is False + + # Close up + nwSplit._doClose() # qtbot.stopForInteraction() -# END Test testDlgMergeSplit_Tools +# END Test testDlgSplit_Main From d795eb6f5fad329501cdb73ad279d60515301818 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 2 May 2021 19:47:39 +0200 Subject: [PATCH 12/12] Delete no longer needed test reference files --- tests/reference/guiMerge_73475cb40a568.nwd | 53 ---------------------- tests/reference/guiSplit_031b4af5197ec.nwd | 15 ------ tests/reference/guiSplit_25fc0e7096fc6.nwd | 13 ------ tests/reference/guiSplit_2858dcd1057d3.nwd | 17 ------- tests/reference/guiSplit_2fca346db6561.nwd | 11 ----- tests/reference/guiSplit_31489056e0916.nwd | 21 --------- tests/reference/guiSplit_41cfc0d1f2d12.nwd | 9 ---- tests/reference/guiSplit_98010bd9270f9.nwd | 25 ---------- 8 files changed, 164 deletions(-) delete mode 100644 tests/reference/guiMerge_73475cb40a568.nwd delete mode 100644 tests/reference/guiSplit_031b4af5197ec.nwd delete mode 100644 tests/reference/guiSplit_25fc0e7096fc6.nwd delete mode 100644 tests/reference/guiSplit_2858dcd1057d3.nwd delete mode 100644 tests/reference/guiSplit_2fca346db6561.nwd delete mode 100644 tests/reference/guiSplit_31489056e0916.nwd delete mode 100644 tests/reference/guiSplit_41cfc0d1f2d12.nwd delete mode 100644 tests/reference/guiSplit_98010bd9270f9.nwd diff --git a/tests/reference/guiMerge_73475cb40a568.nwd b/tests/reference/guiMerge_73475cb40a568.nwd deleted file mode 100644 index 5a903143..00000000 --- a/tests/reference/guiMerge_73475cb40a568.nwd +++ /dev/null @@ -1,53 +0,0 @@ -%%~name: Chapter One -%%~path: b3643d0f92e32/73475cb40a568 -%%~kind: NOVEL/SCENE -## Chapter One - -@pov: Bod -@plot: Main -@location: Europe - -% Synopsis: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque at aliquam quam. - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque at aliquam quam. Praesent magna nunc, lacinia sit amet quam eget, aliquet ultrices justo. Morbi ornare enim et lorem rutrum finibus ut eu dolor. Aliquam a orci odio. Ut ultrices sem quis massa placerat, eget mollis nisl cursus. Cras vel sagittis justo. Ut non ultricies leo. Maecenas rutrum velit in est varius, et egestas massa pulvinar. - -### Scene One - -@pov: Bod -@plot: Main -@location: Europe - -% Synopsis: Aenean ut placerat velit. Etiam laoreet ullamcorper risus, eget lobortis enim scelerisque non. Suspendisse id maximus nunc, et mollis sapien. Curabitur vel semper sapien, non pulvinar dolor. Etiam finibus nisi vel mi molestie consectetur. - -Aenean ut placerat velit. Etiam laoreet ullamcorper risus, eget lobortis enim scelerisque non. Suspendisse id maximus nunc, et mollis sapien. Curabitur vel semper sapien, non pulvinar dolor. Etiam finibus nisi vel mi molestie consectetur. Donec quis ante nunc. Mauris ut leo ipsum. Vestibulum est neque, hendrerit nec neque a, ullamcorper lobortis tellus. Fusce sollicitudin purus quis congue bibendum. Aliquam condimentum ipsum tristique blandit tristique. Donec pulvinar neque ac suscipit malesuada. - -Aliquam ut nisl arcu. Ut ultricies, lorem dignissim rutrum convallis, risus orci tempus lectus, congue feugiat sem lectus vitae odio. Duis sit amet justo finibus, hendrerit nulla at, ullamcorper enim. Praesent vel tellus sit amet tellus vulputate bibendum. Morbi eleifend sagittis sem, ac volutpat ante congue non. In hac habitasse platea dictumst. Morbi lobortis fermentum elit, dignissim sagittis ligula volutpat lacinia. Vestibulum eu interdum odio. Integer ac purus commodo metus congue tempor non at urna. Sed eget tortor vel quam viverra egestas. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec non convallis mauris, ac feugiat ex. - -#### Scene One, Section Two - -Integer vel libero ipsum. Donec varius aliquam libero, sit amet commodo urna hendrerit non. Nullam quis erat mollis nunc viverra volutpat tincidunt in odio. Nam vitae quam sem. Aliquam suscipit nulla non lorem pharetra semper. Ut suscipit erat eu ligula accumsan ultrices. Phasellus nisl tellus, placerat sed laoreet id, consectetur nec dolor. Sed fringilla ipsum id dapibus posuere. Aenean finibus pharetra tincidunt. Ut molestie malesuada nulla, id posuere lorem tincidunt eu. Aliquam tempor eros a est vulputate, scelerisque pulvinar ipsum fermentum. In hac habitasse platea dictumst. - -Curabitur congue, justo quis interdum fermentum, tellus nulla imperdiet sapien, eu interdum enim tellus condimentum metus. Vivamus nunc velit, dignissim ut ultrices sit amet, ultricies quis enim. Donec ut vestibulum neque. Vivamus semper neque id ex ullamcorper varius. Fusce mattis nibh viverra lorem sagittis, et tempor arcu congue. Suspendisse sit amet felis sed urna facilisis mattis eget vitae arcu. Proin eu magna hendrerit, tristique sem maximus, placerat diam. Nulla tristique sed velit sit amet varius. Etiam vel ornare magna, in vulputate arcu. Cras velit orci, tincidunt sed volutpat cursus, bibendum vel sem. Nunc vulputate pharetra tortor, ac consectetur neque tincidunt sit amet. Nulla ornare mi sed mi dignissim ultricies. Ut tincidunt bibendum mauris, sed elementum ex vulputate vel. Mauris fermentum, felis nec vehicula congue, felis lorem facilisis erat, a dictum dolor augue vitae quam. Maecenas rutrum tortor nec consequat eleifend. - -### Scene Two - -@pov: Bod -@plot: Main -@location: Europe - -% Synopsis: Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Integer sapien nulla, dictum at lacus a, dignissim consectetur dolor. Nunc vel eleifend lacus, eu dapibus orci. - -Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Integer sapien nulla, dictum at lacus a, dignissim consectetur dolor. Nunc vel eleifend lacus, eu dapibus orci. Vestibulum facilisis bibendum aliquam. Aliquam posuere, turpis ac bibendum varius, sem tellus venenatis risus, in elementum massa enim ac lorem. Integer in sem ac diam blandit ultricies ut in nulla. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sit amet erat est. Curabitur vitae cursus justo, sit amet placerat dolor. Vivamus eu felis hendrerit, tincidunt massa rutrum, maximus arcu. Pellentesque commodo justo odio, vel rutrum nulla tincidunt eu. Integer non neque condimentum, convallis diam non, varius ligula. Aliquam eget sapien mauris. Aenean pharetra nunc nisi, vel maximus ante tristique sit amet. Aliquam risus metus, interdum non odio eu, consectetur lacinia sapien. - -Proin vitae gravida nisl. Integer viverra orci turpis, sit amet pretium ligula facilisis consequat. Nulla interdum commodo metus, mollis consequat dui tincidunt et. Proin consequat bibendum justo id commodo. Fusce fermentum nunc turpis, eu vestibulum risus feugiat ut. Sed scelerisque vel ligula ut interdum. Suspendisse ac blandit ligula, sagittis fringilla dolor. In tincidunt convallis diam et ornare. Aenean id dignissim est, ut rhoncus quam. Donec vitae nisl velit. In convallis nibh ut augue dignissim, eu elementum quam cursus. Phasellus in lectus lorem. Curabitur in pellentesque nisi, at gravida sapien. Sed cursus justo volutpat lacus placerat, sit amet dignissim turpis commodo. Aliquam vitae orci eget nulla posuere condimentum in ut felis. - -Nulla accumsan ante in pulvinar efficitur. Nulla non velit quis urna hendrerit bibendum. Suspendisse ultrices ante eu justo malesuada, sed fermentum enim rutrum. Nunc fermentum pharetra felis, vitae sollicitudin quam rutrum porta. Aliquam fringilla velit a mi laoreet, et luctus est rutrum. In gravida non ipsum sit amet tempus. Curabitur et eleifend purus. Nulla facilisi. - -#### Scene Two, Section Two - -Suspendisse potenti. Fusce tempus lorem nec laoreet suscipit. Fusce vulputate nisl ac diam tincidunt, nec malesuada quam pellentesque. Maecenas congue, tellus quis commodo rutrum, magna leo egestas arcu, quis suscipit ex risus id ligula. Suspendisse potenti. Morbi blandit lacus vitae laoreet vulputate. Donec vitae tellus eleifend, lobortis eros eu, tincidunt enim. Nullam et ullamcorper nisi. Vivamus tellus ex, lobortis quis rutrum ut, dapibus sit amet turpis. Phasellus pellentesque metus diam, commodo tristique ante commodo ac. Ut mollis ipsum nec diam blandit sollicitudin. Duis bibendum lacus nec commodo dapibus. Sed condimentum luctus ante, id ultricies urna varius nec. Nam convallis magna nec bibendum ultrices. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed auctor pharetra quam, vitae porta ex bibendum eu. - -Vivamus ut venenatis lectus. Phasellus nec elit id sem dictum ornare. Quisque feugiat, diam eget sagittis ultricies, orci turpis efficitur nisi, et fringilla justo odio nec nibh. In hac habitasse platea dictumst. Sed tempus bibendum feugiat. Etiam luctus mauris arcu, non interdum ipsum ultrices id. Vivamus blandit urna sit amet scelerisque vulputate. Quisque in metus eget massa rutrum dictum sit amet sed nulla. Vivamus vel efficitur dolor. - -Ut et consequat enim, quis ornare nibh. In lectus neque, mollis et suscipit et, vestibulum vitae augue. Praesent id ante sit amet odio venenatis placerat a at erat. Sed sed metus sed nisi dictum varius. Integer tincidunt fermentum purus ac porta. Fusce porttitor non risus eget tristique. Donec augue nunc, maximus at fermentum vel, varius et neque. Ut sed consectetur mauris. Quisque ipsum enim, porttitor vitae imperdiet sit amet, tempor et mauris. Aliquam malesuada tincidunt lectus quis blandit. Sed commodo orci felis, quis ultrices tellus facilisis sed. Nunc vel varius est. Duis ullamcorper eu metus in pulvinar. Morbi at sapien dictum, rutrum mauris eget, interdum tellus. - diff --git a/tests/reference/guiSplit_031b4af5197ec.nwd b/tests/reference/guiSplit_031b4af5197ec.nwd deleted file mode 100644 index cbaf3205..00000000 --- a/tests/reference/guiSplit_031b4af5197ec.nwd +++ /dev/null @@ -1,15 +0,0 @@ -%%~name: Scene One -%%~path: 0e17daca5f3e1/031b4af5197ec -%%~kind: NOVEL/SCENE -### Scene One - -@pov: Bod -@plot: Main -@location: Europe - -% Synopsis: Aenean ut placerat velit. Etiam laoreet ullamcorper risus, eget lobortis enim scelerisque non. Suspendisse id maximus nunc, et mollis sapien. Curabitur vel semper sapien, non pulvinar dolor. Etiam finibus nisi vel mi molestie consectetur. - -Aenean ut placerat velit. Etiam laoreet ullamcorper risus, eget lobortis enim scelerisque non. Suspendisse id maximus nunc, et mollis sapien. Curabitur vel semper sapien, non pulvinar dolor. Etiam finibus nisi vel mi molestie consectetur. Donec quis ante nunc. Mauris ut leo ipsum. Vestibulum est neque, hendrerit nec neque a, ullamcorper lobortis tellus. Fusce sollicitudin purus quis congue bibendum. Aliquam condimentum ipsum tristique blandit tristique. Donec pulvinar neque ac suscipit malesuada. - -Aliquam ut nisl arcu. Ut ultricies, lorem dignissim rutrum convallis, risus orci tempus lectus, congue feugiat sem lectus vitae odio. Duis sit amet justo finibus, hendrerit nulla at, ullamcorper enim. Praesent vel tellus sit amet tellus vulputate bibendum. Morbi eleifend sagittis sem, ac volutpat ante congue non. In hac habitasse platea dictumst. Morbi lobortis fermentum elit, dignissim sagittis ligula volutpat lacinia. Vestibulum eu interdum odio. Integer ac purus commodo metus congue tempor non at urna. Sed eget tortor vel quam viverra egestas. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec non convallis mauris, ac feugiat ex. - diff --git a/tests/reference/guiSplit_25fc0e7096fc6.nwd b/tests/reference/guiSplit_25fc0e7096fc6.nwd deleted file mode 100644 index 3247412b..00000000 --- a/tests/reference/guiSplit_25fc0e7096fc6.nwd +++ /dev/null @@ -1,13 +0,0 @@ -%%~name: Chapter One -%%~path: 811786ad1ae74/25fc0e7096fc6 -%%~kind: NOVEL/CHAPTER -## Chapter One - -@pov: Bod -@plot: Main -@location: Europe - -% Synopsis: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque at aliquam quam. - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque at aliquam quam. Praesent magna nunc, lacinia sit amet quam eget, aliquet ultrices justo. Morbi ornare enim et lorem rutrum finibus ut eu dolor. Aliquam a orci odio. Ut ultrices sem quis massa placerat, eget mollis nisl cursus. Cras vel sagittis justo. Ut non ultricies leo. Maecenas rutrum velit in est varius, et egestas massa pulvinar. - diff --git a/tests/reference/guiSplit_2858dcd1057d3.nwd b/tests/reference/guiSplit_2858dcd1057d3.nwd deleted file mode 100644 index c1e79bdf..00000000 --- a/tests/reference/guiSplit_2858dcd1057d3.nwd +++ /dev/null @@ -1,17 +0,0 @@ -%%~name: Scene Two -%%~path: 0e17daca5f3e1/2858dcd1057d3 -%%~kind: NOVEL/SCENE -### Scene Two - -@pov: Bod -@plot: Main -@location: Europe - -% Synopsis: Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Integer sapien nulla, dictum at lacus a, dignissim consectetur dolor. Nunc vel eleifend lacus, eu dapibus orci. - -Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Integer sapien nulla, dictum at lacus a, dignissim consectetur dolor. Nunc vel eleifend lacus, eu dapibus orci. Vestibulum facilisis bibendum aliquam. Aliquam posuere, turpis ac bibendum varius, sem tellus venenatis risus, in elementum massa enim ac lorem. Integer in sem ac diam blandit ultricies ut in nulla. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sit amet erat est. Curabitur vitae cursus justo, sit amet placerat dolor. Vivamus eu felis hendrerit, tincidunt massa rutrum, maximus arcu. Pellentesque commodo justo odio, vel rutrum nulla tincidunt eu. Integer non neque condimentum, convallis diam non, varius ligula. Aliquam eget sapien mauris. Aenean pharetra nunc nisi, vel maximus ante tristique sit amet. Aliquam risus metus, interdum non odio eu, consectetur lacinia sapien. - -Proin vitae gravida nisl. Integer viverra orci turpis, sit amet pretium ligula facilisis consequat. Nulla interdum commodo metus, mollis consequat dui tincidunt et. Proin consequat bibendum justo id commodo. Fusce fermentum nunc turpis, eu vestibulum risus feugiat ut. Sed scelerisque vel ligula ut interdum. Suspendisse ac blandit ligula, sagittis fringilla dolor. In tincidunt convallis diam et ornare. Aenean id dignissim est, ut rhoncus quam. Donec vitae nisl velit. In convallis nibh ut augue dignissim, eu elementum quam cursus. Phasellus in lectus lorem. Curabitur in pellentesque nisi, at gravida sapien. Sed cursus justo volutpat lacus placerat, sit amet dignissim turpis commodo. Aliquam vitae orci eget nulla posuere condimentum in ut felis. - -Nulla accumsan ante in pulvinar efficitur. Nulla non velit quis urna hendrerit bibendum. Suspendisse ultrices ante eu justo malesuada, sed fermentum enim rutrum. Nunc fermentum pharetra felis, vitae sollicitudin quam rutrum porta. Aliquam fringilla velit a mi laoreet, et luctus est rutrum. In gravida non ipsum sit amet tempus. Curabitur et eleifend purus. Nulla facilisi. - diff --git a/tests/reference/guiSplit_2fca346db6561.nwd b/tests/reference/guiSplit_2fca346db6561.nwd deleted file mode 100644 index c33e7901..00000000 --- a/tests/reference/guiSplit_2fca346db6561.nwd +++ /dev/null @@ -1,11 +0,0 @@ -%%~name: Scene Two, Section Two -%%~path: 0e17daca5f3e1/2fca346db6561 -%%~kind: NOVEL/SCENE -#### Scene Two, Section Two - -Suspendisse potenti. Fusce tempus lorem nec laoreet suscipit. Fusce vulputate nisl ac diam tincidunt, nec malesuada quam pellentesque. Maecenas congue, tellus quis commodo rutrum, magna leo egestas arcu, quis suscipit ex risus id ligula. Suspendisse potenti. Morbi blandit lacus vitae laoreet vulputate. Donec vitae tellus eleifend, lobortis eros eu, tincidunt enim. Nullam et ullamcorper nisi. Vivamus tellus ex, lobortis quis rutrum ut, dapibus sit amet turpis. Phasellus pellentesque metus diam, commodo tristique ante commodo ac. Ut mollis ipsum nec diam blandit sollicitudin. Duis bibendum lacus nec commodo dapibus. Sed condimentum luctus ante, id ultricies urna varius nec. Nam convallis magna nec bibendum ultrices. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed auctor pharetra quam, vitae porta ex bibendum eu. - -Vivamus ut venenatis lectus. Phasellus nec elit id sem dictum ornare. Quisque feugiat, diam eget sagittis ultricies, orci turpis efficitur nisi, et fringilla justo odio nec nibh. In hac habitasse platea dictumst. Sed tempus bibendum feugiat. Etiam luctus mauris arcu, non interdum ipsum ultrices id. Vivamus blandit urna sit amet scelerisque vulputate. Quisque in metus eget massa rutrum dictum sit amet sed nulla. Vivamus vel efficitur dolor. - -Ut et consequat enim, quis ornare nibh. In lectus neque, mollis et suscipit et, vestibulum vitae augue. Praesent id ante sit amet odio venenatis placerat a at erat. Sed sed metus sed nisi dictum varius. Integer tincidunt fermentum purus ac porta. Fusce porttitor non risus eget tristique. Donec augue nunc, maximus at fermentum vel, varius et neque. Ut sed consectetur mauris. Quisque ipsum enim, porttitor vitae imperdiet sit amet, tempor et mauris. Aliquam malesuada tincidunt lectus quis blandit. Sed commodo orci felis, quis ultrices tellus facilisis sed. Nunc vel varius est. Duis ullamcorper eu metus in pulvinar. Morbi at sapien dictum, rutrum mauris eget, interdum tellus. - diff --git a/tests/reference/guiSplit_31489056e0916.nwd b/tests/reference/guiSplit_31489056e0916.nwd deleted file mode 100644 index e494f6b9..00000000 --- a/tests/reference/guiSplit_31489056e0916.nwd +++ /dev/null @@ -1,21 +0,0 @@ -%%~name: Scene One -%%~path: 811786ad1ae74/31489056e0916 -%%~kind: NOVEL/SCENE -### Scene One - -@pov: Bod -@plot: Main -@location: Europe - -% Synopsis: Aenean ut placerat velit. Etiam laoreet ullamcorper risus, eget lobortis enim scelerisque non. Suspendisse id maximus nunc, et mollis sapien. Curabitur vel semper sapien, non pulvinar dolor. Etiam finibus nisi vel mi molestie consectetur. - -Aenean ut placerat velit. Etiam laoreet ullamcorper risus, eget lobortis enim scelerisque non. Suspendisse id maximus nunc, et mollis sapien. Curabitur vel semper sapien, non pulvinar dolor. Etiam finibus nisi vel mi molestie consectetur. Donec quis ante nunc. Mauris ut leo ipsum. Vestibulum est neque, hendrerit nec neque a, ullamcorper lobortis tellus. Fusce sollicitudin purus quis congue bibendum. Aliquam condimentum ipsum tristique blandit tristique. Donec pulvinar neque ac suscipit malesuada. - -Aliquam ut nisl arcu. Ut ultricies, lorem dignissim rutrum convallis, risus orci tempus lectus, congue feugiat sem lectus vitae odio. Duis sit amet justo finibus, hendrerit nulla at, ullamcorper enim. Praesent vel tellus sit amet tellus vulputate bibendum. Morbi eleifend sagittis sem, ac volutpat ante congue non. In hac habitasse platea dictumst. Morbi lobortis fermentum elit, dignissim sagittis ligula volutpat lacinia. Vestibulum eu interdum odio. Integer ac purus commodo metus congue tempor non at urna. Sed eget tortor vel quam viverra egestas. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec non convallis mauris, ac feugiat ex. - -#### Scene One, Section Two - -Integer vel libero ipsum. Donec varius aliquam libero, sit amet commodo urna hendrerit non. Nullam quis erat mollis nunc viverra volutpat tincidunt in odio. Nam vitae quam sem. Aliquam suscipit nulla non lorem pharetra semper. Ut suscipit erat eu ligula accumsan ultrices. Phasellus nisl tellus, placerat sed laoreet id, consectetur nec dolor. Sed fringilla ipsum id dapibus posuere. Aenean finibus pharetra tincidunt. Ut molestie malesuada nulla, id posuere lorem tincidunt eu. Aliquam tempor eros a est vulputate, scelerisque pulvinar ipsum fermentum. In hac habitasse platea dictumst. - -Curabitur congue, justo quis interdum fermentum, tellus nulla imperdiet sapien, eu interdum enim tellus condimentum metus. Vivamus nunc velit, dignissim ut ultrices sit amet, ultricies quis enim. Donec ut vestibulum neque. Vivamus semper neque id ex ullamcorper varius. Fusce mattis nibh viverra lorem sagittis, et tempor arcu congue. Suspendisse sit amet felis sed urna facilisis mattis eget vitae arcu. Proin eu magna hendrerit, tristique sem maximus, placerat diam. Nulla tristique sed velit sit amet varius. Etiam vel ornare magna, in vulputate arcu. Cras velit orci, tincidunt sed volutpat cursus, bibendum vel sem. Nunc vulputate pharetra tortor, ac consectetur neque tincidunt sit amet. Nulla ornare mi sed mi dignissim ultricies. Ut tincidunt bibendum mauris, sed elementum ex vulputate vel. Mauris fermentum, felis nec vehicula congue, felis lorem facilisis erat, a dictum dolor augue vitae quam. Maecenas rutrum tortor nec consequat eleifend. - diff --git a/tests/reference/guiSplit_41cfc0d1f2d12.nwd b/tests/reference/guiSplit_41cfc0d1f2d12.nwd deleted file mode 100644 index 6f887f44..00000000 --- a/tests/reference/guiSplit_41cfc0d1f2d12.nwd +++ /dev/null @@ -1,9 +0,0 @@ -%%~name: Scene One, Section Two -%%~path: 0e17daca5f3e1/41cfc0d1f2d12 -%%~kind: NOVEL/SCENE -#### Scene One, Section Two - -Integer vel libero ipsum. Donec varius aliquam libero, sit amet commodo urna hendrerit non. Nullam quis erat mollis nunc viverra volutpat tincidunt in odio. Nam vitae quam sem. Aliquam suscipit nulla non lorem pharetra semper. Ut suscipit erat eu ligula accumsan ultrices. Phasellus nisl tellus, placerat sed laoreet id, consectetur nec dolor. Sed fringilla ipsum id dapibus posuere. Aenean finibus pharetra tincidunt. Ut molestie malesuada nulla, id posuere lorem tincidunt eu. Aliquam tempor eros a est vulputate, scelerisque pulvinar ipsum fermentum. In hac habitasse platea dictumst. - -Curabitur congue, justo quis interdum fermentum, tellus nulla imperdiet sapien, eu interdum enim tellus condimentum metus. Vivamus nunc velit, dignissim ut ultrices sit amet, ultricies quis enim. Donec ut vestibulum neque. Vivamus semper neque id ex ullamcorper varius. Fusce mattis nibh viverra lorem sagittis, et tempor arcu congue. Suspendisse sit amet felis sed urna facilisis mattis eget vitae arcu. Proin eu magna hendrerit, tristique sem maximus, placerat diam. Nulla tristique sed velit sit amet varius. Etiam vel ornare magna, in vulputate arcu. Cras velit orci, tincidunt sed volutpat cursus, bibendum vel sem. Nunc vulputate pharetra tortor, ac consectetur neque tincidunt sit amet. Nulla ornare mi sed mi dignissim ultricies. Ut tincidunt bibendum mauris, sed elementum ex vulputate vel. Mauris fermentum, felis nec vehicula congue, felis lorem facilisis erat, a dictum dolor augue vitae quam. Maecenas rutrum tortor nec consequat eleifend. - diff --git a/tests/reference/guiSplit_98010bd9270f9.nwd b/tests/reference/guiSplit_98010bd9270f9.nwd deleted file mode 100644 index 0725f6a5..00000000 --- a/tests/reference/guiSplit_98010bd9270f9.nwd +++ /dev/null @@ -1,25 +0,0 @@ -%%~name: Scene Two -%%~path: 811786ad1ae74/98010bd9270f9 -%%~kind: NOVEL/SCENE -### Scene Two - -@pov: Bod -@plot: Main -@location: Europe - -% Synopsis: Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Integer sapien nulla, dictum at lacus a, dignissim consectetur dolor. Nunc vel eleifend lacus, eu dapibus orci. - -Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Integer sapien nulla, dictum at lacus a, dignissim consectetur dolor. Nunc vel eleifend lacus, eu dapibus orci. Vestibulum facilisis bibendum aliquam. Aliquam posuere, turpis ac bibendum varius, sem tellus venenatis risus, in elementum massa enim ac lorem. Integer in sem ac diam blandit ultricies ut in nulla. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sit amet erat est. Curabitur vitae cursus justo, sit amet placerat dolor. Vivamus eu felis hendrerit, tincidunt massa rutrum, maximus arcu. Pellentesque commodo justo odio, vel rutrum nulla tincidunt eu. Integer non neque condimentum, convallis diam non, varius ligula. Aliquam eget sapien mauris. Aenean pharetra nunc nisi, vel maximus ante tristique sit amet. Aliquam risus metus, interdum non odio eu, consectetur lacinia sapien. - -Proin vitae gravida nisl. Integer viverra orci turpis, sit amet pretium ligula facilisis consequat. Nulla interdum commodo metus, mollis consequat dui tincidunt et. Proin consequat bibendum justo id commodo. Fusce fermentum nunc turpis, eu vestibulum risus feugiat ut. Sed scelerisque vel ligula ut interdum. Suspendisse ac blandit ligula, sagittis fringilla dolor. In tincidunt convallis diam et ornare. Aenean id dignissim est, ut rhoncus quam. Donec vitae nisl velit. In convallis nibh ut augue dignissim, eu elementum quam cursus. Phasellus in lectus lorem. Curabitur in pellentesque nisi, at gravida sapien. Sed cursus justo volutpat lacus placerat, sit amet dignissim turpis commodo. Aliquam vitae orci eget nulla posuere condimentum in ut felis. - -Nulla accumsan ante in pulvinar efficitur. Nulla non velit quis urna hendrerit bibendum. Suspendisse ultrices ante eu justo malesuada, sed fermentum enim rutrum. Nunc fermentum pharetra felis, vitae sollicitudin quam rutrum porta. Aliquam fringilla velit a mi laoreet, et luctus est rutrum. In gravida non ipsum sit amet tempus. Curabitur et eleifend purus. Nulla facilisi. - -#### Scene Two, Section Two - -Suspendisse potenti. Fusce tempus lorem nec laoreet suscipit. Fusce vulputate nisl ac diam tincidunt, nec malesuada quam pellentesque. Maecenas congue, tellus quis commodo rutrum, magna leo egestas arcu, quis suscipit ex risus id ligula. Suspendisse potenti. Morbi blandit lacus vitae laoreet vulputate. Donec vitae tellus eleifend, lobortis eros eu, tincidunt enim. Nullam et ullamcorper nisi. Vivamus tellus ex, lobortis quis rutrum ut, dapibus sit amet turpis. Phasellus pellentesque metus diam, commodo tristique ante commodo ac. Ut mollis ipsum nec diam blandit sollicitudin. Duis bibendum lacus nec commodo dapibus. Sed condimentum luctus ante, id ultricies urna varius nec. Nam convallis magna nec bibendum ultrices. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed auctor pharetra quam, vitae porta ex bibendum eu. - -Vivamus ut venenatis lectus. Phasellus nec elit id sem dictum ornare. Quisque feugiat, diam eget sagittis ultricies, orci turpis efficitur nisi, et fringilla justo odio nec nibh. In hac habitasse platea dictumst. Sed tempus bibendum feugiat. Etiam luctus mauris arcu, non interdum ipsum ultrices id. Vivamus blandit urna sit amet scelerisque vulputate. Quisque in metus eget massa rutrum dictum sit amet sed nulla. Vivamus vel efficitur dolor. - -Ut et consequat enim, quis ornare nibh. In lectus neque, mollis et suscipit et, vestibulum vitae augue. Praesent id ante sit amet odio venenatis placerat a at erat. Sed sed metus sed nisi dictum varius. Integer tincidunt fermentum purus ac porta. Fusce porttitor non risus eget tristique. Donec augue nunc, maximus at fermentum vel, varius et neque. Ut sed consectetur mauris. Quisque ipsum enim, porttitor vitae imperdiet sit amet, tempor et mauris. Aliquam malesuada tincidunt lectus quis blandit. Sed commodo orci felis, quis ultrices tellus facilisis sed. Nunc vel varius est. Duis ullamcorper eu metus in pulvinar. Morbi at sapien dictum, rutrum mauris eget, interdum tellus. -