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