def testCoreProject_Save(monkeypatch, nwMinimal, mockGUI, refDir): """Test saving a project. """ theProject = NWProject(mockGUI) testFile = os.path.join(nwMinimal, "nwProject.nwx") backFile = os.path.join(nwMinimal, "nwProject.bak") compFile = os.path.join(refDir, os.path.pardir, "minimal", "nwProject.nwx") # Nothing to save assert theProject.saveProject() is False # Open test project assert theProject.openProject(nwMinimal) # Fail on folder structure check with monkeypatch.context() as mp: mp.setattr("os.path.isdir", lambda *a: False) assert theProject.saveProject() is False # Fail on open file with monkeypatch.context() as mp: mp.setattr("builtins.open", causeOSError) assert theProject.saveProject() is False # Fail on creating .bak file with monkeypatch.context() as mp: mp.setattr("os.replace", causeOSError) assert theProject.saveProject() is False assert os.path.isfile(backFile) is False # Successful save saveCount = theProject.saveCount autoCount = theProject.autoCount assert theProject.saveProject() is True assert theProject.saveCount == saveCount + 1 assert theProject.autoCount == autoCount assert cmpFiles(testFile, compFile, [2, 6, 7, 8, 9]) # Check that a second save creates a .bak file assert os.path.isfile(backFile) is True # Successful autosave saveCount = theProject.saveCount autoCount = theProject.autoCount assert theProject.saveProject(autoSave=True) is True assert theProject.saveCount == saveCount assert theProject.autoCount == autoCount + 1 assert cmpFiles(testFile, compFile, [2, 6, 7, 8, 9]) # Close test project assert theProject.closeProject()
def testCoreProject_NewRoot(fncDir, outDir, refDir, dummyGUI): """Check that new root folders can be added to the project. """ projFile = os.path.join(fncDir, "nwProject.nwx") testFile = os.path.join(outDir, "coreProject_NewRoot_nwProject.nwx") compFile = os.path.join(refDir, "coreProject_NewRoot_nwProject.nwx") theProject = NWProject(dummyGUI) theProject.projTree.setSeed(42) assert theProject.newProject({"projPath": fncDir}) assert theProject.setProjectPath(fncDir) assert theProject.saveProject() assert theProject.closeProject() assert theProject.openProject(projFile) assert isinstance(theProject.newRoot("Novel", nwItemClass.NOVEL), type(None)) assert isinstance(theProject.newRoot("Plot", nwItemClass.PLOT), type(None)) assert isinstance(theProject.newRoot("Character", nwItemClass.CHARACTER), type(None)) assert isinstance(theProject.newRoot("World", nwItemClass.WORLD), type(None)) assert isinstance(theProject.newRoot("Timeline", nwItemClass.TIMELINE), str) assert isinstance(theProject.newRoot("Object", nwItemClass.OBJECT), str) assert isinstance(theProject.newRoot("Custom1", nwItemClass.CUSTOM), str) assert isinstance(theProject.newRoot("Custom2", nwItemClass.CUSTOM), str) assert theProject.projChanged assert theProject.saveProject() assert theProject.closeProject() copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [2, 6, 7, 8]) assert not theProject.projChanged
def testCoreToOdt_SaveFlat(mockGUI, fncDir, outDir, refDir): """Test the document save functions. """ theProject = NWProject(mockGUI) theDoc = ToOdt(theProject, isFlat=True) theDoc._isNovel = True assert theDoc.setLanguage(None) is False assert theDoc.setLanguage("nb_NO") is True theDoc.setColourHeaders(True) theDoc._theText = ("## Chapter One\n\n" "Text\n\n" "## Chapter Two\n\n" "Text\n\n") theDoc.tokenizeText() theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() flatFile = os.path.join(fncDir, "document.fodt") testFile = os.path.join(outDir, "coreToOdt_SaveFlat_document.fodt") compFile = os.path.join(refDir, "coreToOdt_SaveFlat_document.fodt") theDoc.saveFlatXML(flatFile) assert os.path.isfile(flatFile) copyfile(flatFile, testFile) assert cmpFiles(testFile, compFile, [4, 5])
def testCoreProject_NewFile(fncDir, outDir, refDir, dummyGUI): """Check that new files can be added to the project. """ projFile = os.path.join(fncDir, "nwProject.nwx") testFile = os.path.join(outDir, "coreProject_NewFile_nwProject.nwx") compFile = os.path.join(refDir, "coreProject_NewFile_nwProject.nwx") theProject = NWProject(dummyGUI) theProject.projTree.setSeed(42) assert theProject.newProject({"projPath": fncDir}) assert theProject.setProjectPath(fncDir) assert theProject.saveProject() assert theProject.closeProject() assert theProject.openProject(projFile) assert isinstance( theProject.newFile("Hello", nwItemClass.NOVEL, "31489056e0916"), str) assert isinstance( theProject.newFile("Jane", nwItemClass.CHARACTER, "71ee45a3c0db9"), str) assert theProject.projChanged assert theProject.saveProject() assert theProject.closeProject() copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [2, 6, 7, 8]) assert not theProject.projChanged
def testCoreProject_NewMinimal(fncDir, outDir, refDir, tmpDir, dummyGUI): """Create a new project from a project wizard dictionary. With default setting, creating a Minimal project. """ projFile = os.path.join(fncDir, "nwProject.nwx") testFile = os.path.join(outDir, "coreProject_NewMinimal_nwProject.nwx") compFile = os.path.join(refDir, "coreProject_NewMinimal_nwProject.nwx") theProject = NWProject(dummyGUI) theProject.projTree.setSeed(42) # Setting no data should fail assert not theProject.newProject({}) # Try again with a proper path assert theProject.newProject({"projPath": fncDir}) assert theProject.saveProject() assert theProject.closeProject() # Creating the project once more should fail assert not theProject.newProject({"projPath": fncDir}) # Check the new project copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [2, 6, 7, 8]) # Open again assert theProject.openProject(projFile) # Save and close assert theProject.saveProject() assert theProject.closeProject() copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [2, 6, 7, 8]) assert not theProject.projChanged # Open a second time assert theProject.openProject(projFile) assert not theProject.openProject(projFile) assert theProject.openProject(projFile, overrideLock=True) assert theProject.saveProject() assert theProject.closeProject() copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
def testCoreProject_Save(monkeypatch, nwMinimal, dummyGUI, refDir): """Test saving a project. """ theProject = NWProject(dummyGUI) testFile = os.path.join(nwMinimal, "nwProject.nwx") compFile = os.path.join(refDir, os.path.pardir, "minimal", "nwProject.nwx") # Nothing to save assert theProject.saveProject() is False # Open test project assert theProject.openProject(nwMinimal) # Fail on folder structure check monkeypatch.setattr("os.path.isdir", lambda *args: False) assert theProject.saveProject() is False monkeypatch.undo() # Fail on open file monkeypatch.setattr("builtins.open", causeOSError) assert theProject.saveProject() is False monkeypatch.undo() # Successful save saveCount = theProject.saveCount autoCount = theProject.autoCount assert theProject.saveProject() is True assert theProject.saveCount == saveCount + 1 assert theProject.autoCount == autoCount assert cmpFiles(testFile, compFile, [2, 6, 7, 8, 9]) # Successful autosave saveCount = theProject.saveCount autoCount = theProject.autoCount assert theProject.saveProject(autoSave=True) is True assert theProject.saveCount == saveCount assert theProject.autoCount == autoCount + 1 assert cmpFiles(testFile, compFile, [2, 6, 7, 8, 9]) # Close test project assert theProject.closeProject()
def testCoreProject_NewCustomA(fncDir, outDir, refDir, dummyGUI): """Create a new project from a project wizard dictionary. Custom type with chapters and scenes. """ projFile = os.path.join(fncDir, "nwProject.nwx") testFile = os.path.join(outDir, "coreProject_NewCustomA_nwProject.nwx") compFile = os.path.join(refDir, "coreProject_NewCustomA_nwProject.nwx") projData = { "projName": "Test Custom", "projTitle": "Test Novel", "projAuthors": "Jane Doe\nJohn Doh\n", "projPath": fncDir, "popSample": False, "popMinimal": False, "popCustom": True, "addRoots": [ nwItemClass.PLOT, nwItemClass.CHARACTER, nwItemClass.WORLD, nwItemClass.TIMELINE, nwItemClass.OBJECT, nwItemClass.ENTITY, ], "numChapters": 3, "numScenes": 3, "chFolders": True, } theProject = NWProject(dummyGUI) theProject.projTree.setSeed(42) assert theProject.newProject(projData) assert theProject.saveProject() assert theProject.closeProject() copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
def testCoreIndex_LoadSave(monkeypatch, nwLipsum, mockGUI, outDir, refDir): """Test core functionality of scaning, saving, loading and checking the index cache file. """ projFile = os.path.join(nwLipsum, "meta", "tagsIndex.json") testFile = os.path.join(outDir, "coreIndex_LoadSave_tagsIndex.json") compFile = os.path.join(refDir, "coreIndex_LoadSave_tagsIndex.json") theProject = NWProject(mockGUI) theProject.projTree.setSeed(42) assert theProject.openProject(nwLipsum) theIndex = NWIndex(theProject) notIndexable = { "b3643d0f92e32": False, # Novel ROOT "45e6b01ca35c1": False, # Chapter One FOLDER "6bd935d2490cd": False, # Chapter Two FOLDER "67a8707f2f249": False, # Character ROOT "6c6afb1247750": False, # Plot ROOT "60bdf227455cc": False, # World ROOT } for tItem in theProject.projTree: assert theIndex.reIndexHandle(tItem.itemHandle) is notIndexable.get( tItem.itemHandle, True) assert theIndex.reIndexHandle(None) is False # Make the save fail with monkeypatch.context() as mp: mp.setattr("builtins.open", causeException) assert theIndex.saveIndex() is False # Make the save pass assert theIndex.saveIndex() is True # Take a copy of the index tagIndex = str(theIndex._tagIndex) refIndex = str(theIndex._refIndex) fileIndex = str(theIndex._fileIndex) textCounts = str(theIndex._fileMeta) # Delete a handle assert theIndex._tagIndex.get("Bod", None) is not None assert theIndex._refIndex.get("4c4f28287af27", None) is not None assert theIndex._fileIndex.get("4c4f28287af27", None) is not None assert theIndex._fileMeta.get("4c4f28287af27", None) is not None theIndex.deleteHandle("4c4f28287af27") assert theIndex._tagIndex.get("Bod", None) is None assert theIndex._refIndex.get("4c4f28287af27", None) is None assert theIndex._fileIndex.get("4c4f28287af27", None) is None assert theIndex._fileMeta.get("4c4f28287af27", None) is None # Clear the index theIndex.clearIndex() assert theIndex._tagIndex == {} assert theIndex._refIndex == {} assert theIndex._fileIndex == {} assert theIndex._fileMeta == {} # Make the load fail with monkeypatch.context() as mp: mp.setattr(json, "load", causeException) assert theIndex.loadIndex() is False # Make the load pass assert theIndex.loadIndex() is True assert str(theIndex._tagIndex) == tagIndex assert str(theIndex._refIndex) == refIndex assert str(theIndex._fileIndex) == fileIndex assert str(theIndex._fileMeta) == textCounts # Break the index and check that we notice assert theIndex.indexBroken is False theIndex._tagIndex["Bod"].append("Stuff") theIndex._checkIndex() assert theIndex.indexBroken is True # Finalise assert theProject.closeProject() is True copyfile(projFile, testFile) assert cmpFiles(testFile, compFile)
def testCoreProject_Backup(monkeypatch, dummyGUI, nwMinimal, tmpDir): """Test the automated backup feature of the project class. The test creates a backup of the Minimal test project, and then unzips the backupd file and checks that the project XML file is identical to the original file. """ theProject = NWProject(dummyGUI) assert theProject.openProject(nwMinimal) # Test faulty settings # No project dummyGUI.hasProject = False assert not theProject.zipIt(doNotify=False) dummyGUI.hasProject = True # Invalid path theProject.mainConf.backupPath = None assert not theProject.zipIt(doNotify=False) # Missing project name theProject.mainConf.backupPath = tmpDir theProject.projName = "" assert not theProject.zipIt(doNotify=False) # Non-existent folder theProject.mainConf.backupPath = os.path.join(tmpDir, "nonexistent") theProject.projName = "Test Minimal" assert not theProject.zipIt(doNotify=False) # Same folder as project (causes infinite loop in zipping) theProject.mainConf.backupPath = nwMinimal assert not theProject.zipIt(doNotify=False) # Set a valid folder theProject.mainConf.backupPath = tmpDir # Can't make folder monkeypatch.setattr("os.mkdir", causeOSError) assert not theProject.zipIt(doNotify=False) monkeypatch.undo() # Can't write archive monkeypatch.setattr("shutil.make_archive", causeOSError) assert not theProject.zipIt(doNotify=False) monkeypatch.undo() # Test correct settings assert theProject.zipIt(doNotify=True) theFiles = os.listdir(os.path.join(tmpDir, "Test Minimal")) assert len(theFiles) == 1 theZip = theFiles[0] assert theZip[:12] == "Backup from " assert theZip[-4:] == ".zip" # Extract the archive with ZipFile(os.path.join(tmpDir, "Test Minimal", theZip), "r") as inZip: inZip.extractall(os.path.join(tmpDir, "extract")) # Check that the main project file was restored assert cmpFiles(os.path.join(nwMinimal, "nwProject.nwx"), os.path.join(tmpDir, "extract", "nwProject.nwx"))
def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mockRnd): """Test the document editor. """ # Block message box monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes) monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes) monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *a: True) monkeypatch.setattr(GuiDocEditor, "hasFocus", lambda *a: True) monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True)) monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True)) # Create new, save, close project buildTestProject(nwGUI, fncProj) assert nwGUI.saveProject() assert nwGUI.closeProject() assert len(nwGUI.theProject.tree) == 0 assert len(nwGUI.theProject.tree._treeOrder) == 0 assert len(nwGUI.theProject.tree._treeRoots) == 0 assert nwGUI.theProject.tree.trashRoot() is None assert nwGUI.theProject.projPath is None assert nwGUI.theProject.projMeta is None assert nwGUI.theProject.projFile == "nwProject.nwx" assert nwGUI.theProject.projName == "" assert nwGUI.theProject.bookTitle == "" assert len(nwGUI.theProject.bookAuthors) == 0 assert not nwGUI.theProject.spellCheck # Check the files projFile = os.path.join(fncProj, "nwProject.nwx") testFile = os.path.join(outDir, "guiEditor_Main_Initial_nwProject.nwx") compFile = os.path.join(refDir, "guiEditor_Main_Initial_nwProject.nwx") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE) qtbot.wait(stepDelay) # qtbot.stopForInteraction() # Re-open project assert nwGUI.openProject(fncProj) qtbot.wait(stepDelay) # Check that we loaded the data assert len(nwGUI.theProject.tree) == 8 assert len(nwGUI.theProject.tree._treeOrder) == 8 assert len(nwGUI.theProject.tree._treeRoots) == 4 assert nwGUI.theProject.tree.trashRoot() is None assert nwGUI.theProject.projPath == fncProj assert nwGUI.theProject.projMeta == os.path.join(fncProj, "meta") assert nwGUI.theProject.projFile == "nwProject.nwx" assert nwGUI.theProject.projName == "New Project" assert nwGUI.theProject.bookTitle == "New Novel" assert len(nwGUI.theProject.bookAuthors) == 1 assert nwGUI.theProject.spellCheck is False # Check that tree items have been created assert nwGUI.projView.projTree._getTreeItem("0000000000008") is not None assert nwGUI.projView.projTree._getTreeItem("0000000000009") is not None assert nwGUI.projView.projTree._getTreeItem("000000000000a") is not None assert nwGUI.projView.projTree._getTreeItem("000000000000b") is not None assert nwGUI.projView.projTree._getTreeItem("000000000000c") is not None assert nwGUI.projView.projTree._getTreeItem("000000000000d") is not None assert nwGUI.projView.projTree._getTreeItem("000000000000e") is not None assert nwGUI.projView.projTree._getTreeItem("000000000000f") is not None nwGUI.mainMenu.aSpellCheck.setChecked(True) assert nwGUI.mainMenu._toggleSpellCheck() # Change some settings nwGUI.mainConf.hideHScroll = True nwGUI.mainConf.hideVScroll = True nwGUI.mainConf.autoScrollPos = 80 nwGUI.mainConf.autoScroll = True # Add a Character File nwGUI.switchFocus(nwWidget.TREE) nwGUI.projView.projTree.clearSelection() nwGUI.projView.projTree._getTreeItem("000000000000a").setSelected(True) nwGUI.projView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True) assert nwGUI.openSelectedItem() # Type something into the document nwGUI.switchFocus(nwWidget.EDITOR) qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay) for c in "# Jane Doe": 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 "@tag: Jane": 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 a file about Jane.": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) # Add a Plot File nwGUI.switchFocus(nwWidget.TREE) nwGUI.projView.projTree.clearSelection() nwGUI.projView.projTree._getTreeItem("0000000000009").setSelected(True) nwGUI.projView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True) assert nwGUI.openSelectedItem() # Type something into the document nwGUI.switchFocus(nwWidget.EDITOR) qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay) for c in "# Main Plot": 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 "@tag: MainPlot": 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 a file detailing the main plot.": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) # Add a World File nwGUI.switchFocus(nwWidget.TREE) nwGUI.projView.projTree.clearSelection() nwGUI.projView.projTree._getTreeItem("000000000000b").setSelected(True) nwGUI.projView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True) assert nwGUI.openSelectedItem() # Add Some Text nwGUI.docEditor.replaceText("Hello World!") assert nwGUI.docEditor.getText() == "Hello World!" nwGUI.docEditor.replaceText("") # Type something into the document nwGUI.switchFocus(nwWidget.EDITOR) qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay) for c in "# Main Location": 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 "@tag: Home": 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 a file describing Jane's home.": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) # Trigger autosaves before making more changes nwGUI._autoSaveDocument() nwGUI._autoSaveProject() # Select the 'New Scene' file nwGUI.switchFocus(nwWidget.TREE) nwGUI.projView.projTree.clearSelection() nwGUI.projView.projTree._getTreeItem("0000000000008").setExpanded(True) nwGUI.projView.projTree._getTreeItem("000000000000d").setExpanded(True) nwGUI.projView.projTree._getTreeItem("000000000000f").setSelected(True) assert nwGUI.openSelectedItem() # Type something into the document nwGUI.switchFocus(nwWidget.EDITOR) qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay) for c in "# Novel": 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 "## Chapter": 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 "@pov: Jane": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@plot: MainPlot": 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 "### Scene": 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 "% How about a comment?": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@pov: Jane": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@plot: MainPlot": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@location: Home": 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 "#### Some Section": 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 "@char: Jane": 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 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 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. ": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) for c in "Isn't that nice? ": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) for c in "We can hyphen-ate, make dashes -- and even longer dashes --- if we want. ": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) for c in "Ellipsis? Not a problem either ... ": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) for c in "How about three hyphens - -": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Left, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Backspace, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Right, delay=keyDelay) for c in "- for long dash? It works too.": 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 "\"Full line double quoted 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 "'Full line single quoted 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 "\t\"Tab-indented 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 ">\"Paragraph-indented 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 ">>\"Right-aligned 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 "\t'Tab-indented 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 ">'Paragraph-indented 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 ">>'Right-aligned 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) qtbot.wait(stepDelay) nwGUI.docEditor.wCounterDoc.run() qtbot.wait(stepDelay) # Save the document assert nwGUI.docEditor.docChanged() assert nwGUI.saveDocument() assert not nwGUI.docEditor.docChanged() qtbot.wait(stepDelay) nwGUI.rebuildIndex() qtbot.wait(stepDelay) # Open and view the edited document nwGUI.switchFocus(nwWidget.VIEWER) assert nwGUI.openDocument("000000000000f") assert nwGUI.viewDocument("000000000000f") qtbot.wait(stepDelay) assert nwGUI.saveProject() assert nwGUI.closeDocViewer() qtbot.wait(stepDelay) # Check a Quick Create and Delete assert nwGUI.projView.projTree.newTreeItem(nwItemType.FILE, None) newHandle = nwGUI.projView.getSelectedHandle() assert nwGUI.theProject.tree["0000000000020"] is not None assert nwGUI.projView.deleteItem() assert nwGUI.projView.setSelectedHandle(newHandle) assert nwGUI.projView.deleteItem() assert nwGUI.theProject.tree["0000000000024"] is not None # Trash assert nwGUI.saveProject() # Check the files projFile = os.path.join(fncProj, "nwProject.nwx") testFile = os.path.join(outDir, "guiEditor_Main_Final_nwProject.nwx") compFile = os.path.join(refDir, "guiEditor_Main_Final_nwProject.nwx") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE) projFile = os.path.join(fncProj, "content", "000000000000f.nwd") testFile = os.path.join(outDir, "guiEditor_Main_Final_000000000000f.nwd") compFile = os.path.join(refDir, "guiEditor_Main_Final_000000000000f.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) projFile = os.path.join(fncProj, "content", "0000000000020.nwd") testFile = os.path.join(outDir, "guiEditor_Main_Final_0000000000020.nwd") compFile = os.path.join(refDir, "guiEditor_Main_Final_0000000000020.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) projFile = os.path.join(fncProj, "content", "0000000000021.nwd") testFile = os.path.join(outDir, "guiEditor_Main_Final_0000000000021.nwd") compFile = os.path.join(refDir, "guiEditor_Main_Final_0000000000021.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) projFile = os.path.join(fncProj, "content", "0000000000022.nwd") testFile = os.path.join(outDir, "guiEditor_Main_Final_0000000000022.nwd") compFile = os.path.join(refDir, "guiEditor_Main_Final_0000000000022.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile)
def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir): """Test config intialisation. """ tstConf = Config() confFile = os.path.join(tmpDir, "novelwriter.conf") testFile = os.path.join(outDir, "baseConfig_novelwriter.conf") compFile = os.path.join(refDir, "baseConfig_novelwriter.conf") # Make sure we don't have any old conf file if os.path.isfile(confFile): os.unlink(confFile) # Let the config class figure out the path monkeypatch.setattr("PyQt5.QtCore.QStandardPaths.writableLocation", lambda *args: fncDir) tstConf.verQtValue = 50600 tstConf.initConfig() assert tstConf.confPath == os.path.join(fncDir, tstConf.appHandle) assert tstConf.dataPath == os.path.join(fncDir, tstConf.appHandle) assert not os.path.isfile(confFile) tstConf.verQtValue = 50000 tstConf.initConfig() assert tstConf.confPath == os.path.join(fncDir, tstConf.appHandle) assert tstConf.dataPath == os.path.join(fncDir, tstConf.appHandle) assert not os.path.isfile(confFile) monkeypatch.undo() # Fail to make folders monkeypatch.setattr("os.mkdir", causeOSError) tstConfDir = os.path.join(fncDir, "test_conf") tstConf.initConfig(confPath=tstConfDir, dataPath=tmpDir) assert tstConf.confPath is None assert tstConf.dataPath == tmpDir assert not os.path.isfile(confFile) tstDataDir = os.path.join(fncDir, "test_data") tstConf.initConfig(confPath=tmpDir, dataPath=tstDataDir) assert tstConf.confPath == tmpDir assert tstConf.dataPath is None assert os.path.isfile(confFile) os.unlink(confFile) monkeypatch.undo() # Test load/save with no path tstConf.confPath = None assert not tstConf.loadConfig() assert not tstConf.saveConfig() # Run again and set the paths directly and correctly # This should create a config file as well monkeypatch.setattr("os.path.expanduser", lambda *args: "") tstConf.spellTool = nwConst.SP_INTERNAL tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir) assert tstConf.confPath == tmpDir assert tstConf.dataPath == tmpDir assert os.path.isfile(confFile) copyfile(confFile, testFile) assert cmpFiles(testFile, compFile, [2, 9]) monkeypatch.undo() # Load and save with OSError monkeypatch.setattr("builtins.open", causeOSError) assert not tstConf.loadConfig() assert tstConf.hasError is True assert tstConf.errData != [] assert tstConf.getErrData().startswith("Could not") assert tstConf.hasError is False assert tstConf.errData == [] assert not tstConf.saveConfig() assert tstConf.hasError is True assert tstConf.errData != [] assert tstConf.getErrData().startswith("Could not") assert tstConf.hasError is False assert tstConf.errData == [] monkeypatch.undo() assert tstConf.loadConfig() assert tstConf.saveConfig() copyfile(confFile, testFile) assert cmpFiles(testFile, compFile, [2, 9])
def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI, fncDir, fncProj, outDir, refDir): """Test the full project settings dialog. """ projFile = os.path.join(fncProj, "nwProject.nwx") testFile = os.path.join(outDir, "guiProjSettings_Dialog_nwProject.nwx") compFile = os.path.join(refDir, "guiProjSettings_Dialog_nwProject.nwx") # Block message box monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes) monkeypatch.setattr(QMessageBox, "critical", lambda *args: QMessageBox.Yes) # Check that we cannot open when there is no project nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger) assert getGuiItem("GuiProjectSettings") is None # Create new project nwGUI.theProject.projTree.setSeed(42) assert nwGUI.newProject({"projPath": fncProj}) nwGUI.mainConf.backupPath = fncDir nwGUI.theProject.setSpellLang("en") nwGUI.theProject.setBookAuthors("Jane Smith\nJohn Smith") nwGUI.theProject.setAutoReplace({"A": "B", "C": "D"}) # Get the dialog object monkeypatch.setattr(GuiProjectSettings, "exec_", lambda *args: None) monkeypatch.setattr(GuiProjectSettings, "result", lambda *args: QDialog.Accepted) nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger) qtbot.waitUntil(lambda: getGuiItem("GuiProjectSettings") is not None, timeout=1000) projEdit = getGuiItem("GuiProjectSettings") assert isinstance(projEdit, GuiProjectSettings) projEdit.show() qtbot.addWidget(projEdit) # Settings Tab # ============ assert projEdit.tabMain.editName.text() == "New Project" assert projEdit.tabMain.editTitle.text() == "" assert projEdit.tabMain.editAuthors.toPlainText( ) == "Jane Smith\nJohn Smith" assert projEdit.tabMain.spellLang.currentData() == "en" assert projEdit.tabMain.doBackup.isChecked() is False qtbot.wait(stepDelay) projEdit.tabMain.editName.setText("") for c in "Project Name": qtbot.keyClick(projEdit.tabMain.editName, c, delay=typeDelay) for c in "Project Title": qtbot.keyClick(projEdit.tabMain.editTitle, c, delay=typeDelay) projEdit.tabMain.editAuthors.clear() for c in "Jane Doe": qtbot.keyClick(projEdit.tabMain.editAuthors, c, delay=typeDelay) qtbot.keyClick(projEdit.tabMain.editAuthors, Qt.Key_Return, delay=keyDelay) for c in "John Doh": qtbot.keyClick(projEdit.tabMain.editAuthors, c, delay=typeDelay) qtbot.keyClick(projEdit.tabMain.editAuthors, Qt.Key_Return, delay=keyDelay) qtbot.wait(stepDelay) assert projEdit.tabMain.editName.text() == "Project Name" assert projEdit.tabMain.editTitle.text() == "Project Title" assert projEdit.tabMain.editAuthors.toPlainText() == "Jane Doe\nJohn Doh\n" # Status Tab # ========== projEdit._tabBox.setCurrentWidget(projEdit.tabStatus) assert projEdit.tabStatus.colChanged is False assert projEdit.tabStatus.getNewList() is None assert projEdit.tabStatus.listBox.topLevelItemCount() == 4 # Fake drag'n'drop should change changed status projEdit.tabStatus._rowsMoved() assert projEdit.tabStatus.colChanged is True projEdit.tabStatus.colChanged = False projEdit.tabStatus.listBox.clearSelection() assert projEdit.tabStatus._getSelectedItem() is None projEdit.tabStatus.listBox.topLevelItem(0).setSelected(True) assert isinstance(projEdit.tabStatus._getSelectedItem(), QTreeWidgetItem) # Can't delete the first item (it's in use) projEdit.tabStatus.listBox.clearSelection() projEdit.tabStatus.listBox.topLevelItem(0).setSelected(True) qtbot.mouseClick(projEdit.tabStatus.delButton, Qt.LeftButton) assert projEdit.tabStatus.listBox.topLevelItemCount() == 4 # Can delete the third item projEdit.tabStatus.listBox.clearSelection() projEdit.tabStatus.listBox.topLevelItem(2).setSelected(True) qtbot.mouseClick(projEdit.tabStatus.delButton, Qt.LeftButton) assert projEdit.tabStatus.listBox.topLevelItemCount() == 3 # Add a new item monkeypatch.setattr(QColorDialog, "getColor", lambda *args: QColor(20, 30, 40)) qtbot.mouseClick(projEdit.tabStatus.addButton, Qt.LeftButton) projEdit.tabStatus.listBox.topLevelItem(3).setSelected(True) for n in range(8): qtbot.keyClick(projEdit.tabStatus.editName, Qt.Key_Backspace, delay=typeDelay) for c in "Final": qtbot.keyClick(projEdit.tabStatus.editName, c, delay=typeDelay) qtbot.mouseClick(projEdit.tabStatus.colButton, Qt.LeftButton) qtbot.mouseClick(projEdit.tabStatus.saveButton, Qt.LeftButton) assert projEdit.tabStatus.listBox.topLevelItemCount() == 4 qtbot.wait(stepDelay) assert projEdit.tabStatus.colChanged is True assert projEdit.tabStatus.getNewList() == [("New", 100, 100, 100, "New"), ("Note", 200, 50, 0, "Note"), ("Finished", 50, 200, 0, "Finished"), ("Final", 20, 30, 40, None)] # Importance Tab # ============== projEdit._tabBox.setCurrentWidget(projEdit.tabImport) projEdit.tabStatus.listBox.clearSelection() projEdit.tabImport.listBox.topLevelItem(3).setSelected(True) qtbot.mouseClick(projEdit.tabImport.delButton, Qt.LeftButton) qtbot.mouseClick(projEdit.tabImport.addButton, Qt.LeftButton) projEdit.tabStatus.listBox.clearSelection() projEdit.tabImport.listBox.topLevelItem(3).setSelected(True) for n in range(8): qtbot.keyClick(projEdit.tabImport.editName, Qt.Key_Backspace, delay=typeDelay) for c in "Final": qtbot.keyClick(projEdit.tabImport.editName, c, delay=typeDelay) qtbot.mouseClick(projEdit.tabImport.saveButton, Qt.LeftButton) qtbot.wait(stepDelay) # Auto-Replace Tab # ================ qtbot.wait(stepDelay) projEdit._tabBox.setCurrentWidget(projEdit.tabReplace) assert projEdit.tabReplace.listBox.topLevelItem(0).text(0) == "<A>" assert projEdit.tabReplace.listBox.topLevelItem(0).text(1) == "B" assert projEdit.tabReplace.listBox.topLevelItem(1).text(0) == "<C>" assert projEdit.tabReplace.listBox.topLevelItem(1).text(1) == "D" qtbot.mouseClick(projEdit.tabReplace.addButton, Qt.LeftButton) projEdit.tabReplace.listBox.topLevelItem(2).setSelected(True) projEdit.tabReplace.editKey.setText("") for c in "Th is ": qtbot.keyClick(projEdit.tabReplace.editKey, c, delay=typeDelay) projEdit.tabReplace.editValue.setText("") for c in "With This Stuff ": qtbot.keyClick(projEdit.tabReplace.editValue, c, delay=typeDelay) qtbot.mouseClick(projEdit.tabReplace.saveButton, Qt.LeftButton) qtbot.wait(stepDelay) projEdit.tabReplace.listBox.clearSelection() assert not projEdit.tabReplace._saveEntry() assert not projEdit.tabReplace._delEntry() qtbot.mouseClick(projEdit.tabReplace.addButton, Qt.LeftButton) newIdx = -1 for i in range(projEdit.tabReplace.listBox.topLevelItemCount()): if projEdit.tabReplace.listBox.topLevelItem(i).text(0) == "<keyword4>": newIdx = i break assert newIdx >= 0 newItem = projEdit.tabReplace.listBox.topLevelItem(newIdx) projEdit.tabReplace.listBox.setCurrentItem(newItem) qtbot.mouseClick(projEdit.tabReplace.delButton, Qt.LeftButton) qtbot.wait(stepDelay) # Save & Check # ============ projEdit._doSave() # Open again, and check project settings nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger) qtbot.waitUntil(lambda: getGuiItem("GuiProjectSettings") is not None, timeout=1000) projEdit = getGuiItem("GuiProjectSettings") assert isinstance(projEdit, GuiProjectSettings) qtbot.addWidget(projEdit) assert projEdit.tabMain.editName.text() == "Project Name" assert projEdit.tabMain.editTitle.text() == "Project Title" theAuth = projEdit.tabMain.editAuthors.toPlainText().strip().splitlines() assert len(theAuth) == 2 assert theAuth[0] == "Jane Doe" assert theAuth[1] == "John Doh" projEdit._doClose() qtbot.wait(stepDelay) assert nwGUI.saveProject() qtbot.wait(stepDelay) # Check the files copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [2, 8, 9, 10])
def testDlgItemEditor_Dialog(qtbot, monkeypatch, nwGUI, fncDir, fncProj, refDir, outDir): """Test the full item editor dialog. """ projFile = os.path.join(fncProj, "nwProject.nwx") testFile = os.path.join(outDir, "guiItemEditor_Dialog_nwProject.nwx") compFile = os.path.join(refDir, "guiItemEditor_Dialog_nwProject.nwx") # Block message box monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes) monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *args: True) # Create new, save, open project nwGUI.theProject.projTree.setSeed(42) assert nwGUI.newProject({"projPath": fncProj}) assert nwGUI.openDocument("0e17daca5f3e1") assert nwGUI.treeView.setSelectedHandle("0e17daca5f3e1", doScroll=True) monkeypatch.setattr(GuiItemEditor, "exec_", lambda *args: None) nwGUI.mainMenu.aEditItem.activate(QAction.Trigger) qtbot.waitUntil(lambda: getGuiItem("GuiItemEditor") is not None, timeout=1000) itemEdit = getGuiItem("GuiItemEditor") assert isinstance(itemEdit, GuiItemEditor) itemEdit.show() qtbot.addWidget(itemEdit) assert itemEdit.editName.text() == "New Scene" assert itemEdit.editStatus.currentData() == "New" assert itemEdit.editLayout.currentData() == nwItemLayout.SCENE for c in "Just a Page": qtbot.keyClick(itemEdit.editName, c, delay=typeDelay) itemEdit.editStatus.setCurrentIndex(1) layoutIdx = itemEdit.editLayout.findData(nwItemLayout.PAGE) itemEdit.editLayout.setCurrentIndex(layoutIdx) itemEdit.editExport.setChecked(False) assert not itemEdit.editExport.isChecked() itemEdit._doSave() nwGUI.mainMenu.aEditItem.activate(QAction.Trigger) qtbot.waitUntil(lambda: getGuiItem("GuiItemEditor") is not None, timeout=1000) itemEdit = getGuiItem("GuiItemEditor") assert isinstance(itemEdit, GuiItemEditor) itemEdit.show() qtbot.addWidget(itemEdit) assert itemEdit.editName.text() == "Just a Page" assert itemEdit.editStatus.currentData() == "Note" assert itemEdit.editLayout.currentData() == nwItemLayout.PAGE itemEdit._doClose() # Check that the header is updated nwGUI.docEditor.updateDocInfo("0e17daca5f3e1") assert nwGUI.docEditor.docHeader.theTitle.text( ) == "Novel › New Chapter › Just a Page" assert not nwGUI.docEditor.setCursorLine("where?") assert nwGUI.docEditor.setCursorLine(2) qtbot.wait(stepDelay) assert nwGUI.docEditor.getCursorPosition() == 15 qtbot.wait(stepDelay) assert nwGUI.saveProject() qtbot.wait(stepDelay) # Check the files copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
def testDlgPreferences_Main(qtbot, monkeypatch, fncDir, outDir, refDir): """Test the load project wizard. """ # Block message box monkeypatch.setattr(QMessageBox, "warning", lambda *a: QMessageBox.Yes) monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes) monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes) # Must create a clean config and GUI object as the test-wide # novelwriter.CONFIG object is created on import an can be tainted by other tests confFile = os.path.join(fncDir, "novelwriter.conf") if os.path.isfile(confFile): os.unlink(confFile) theConf = Config() theConf.initConfig(fncDir, fncDir) theConf.setLastPath("") origConf = novelwriter.CONFIG novelwriter.CONFIG = theConf nwGUI = novelwriter.main( ["--testmode", "--config=%s" % fncDir, "--data=%s" % fncDir]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.wait(stepDelay) theConf = nwGUI.mainConf assert theConf.confPath == fncDir monkeypatch.setattr(GuiPreferences, "exec_", lambda *a: None) monkeypatch.setattr(GuiPreferences, "result", lambda *a: QDialog.Accepted) monkeypatch.setattr(nwGUI.docEditor.spEnchant, "listDictionaries", lambda: [("en", "none")]) nwGUI.mainMenu.aPreferences.activate(QAction.Trigger) qtbot.waitUntil(lambda: getGuiItem("GuiPreferences") is not None, timeout=1000) nwPrefs = getGuiItem("GuiPreferences") assert isinstance(nwPrefs, GuiPreferences) nwPrefs.show() assert nwPrefs.mainConf.confPath == fncDir # General Settings qtbot.wait(keyDelay) tabGeneral = nwPrefs.tabGeneral nwPrefs._tabBox.setCurrentWidget(tabGeneral) qtbot.wait(keyDelay) assert tabGeneral.showFullPath.isChecked() qtbot.mouseClick(tabGeneral.showFullPath, Qt.LeftButton) assert not tabGeneral.showFullPath.isChecked() qtbot.wait(keyDelay) assert not tabGeneral.hideVScroll.isChecked() qtbot.mouseClick(tabGeneral.hideVScroll, Qt.LeftButton) assert tabGeneral.hideVScroll.isChecked() qtbot.wait(keyDelay) assert not tabGeneral.hideHScroll.isChecked() qtbot.mouseClick(tabGeneral.hideHScroll, Qt.LeftButton) assert tabGeneral.hideHScroll.isChecked() # Check font button monkeypatch.setattr(QFontDialog, "getFont", lambda font, obj: (font, True)) qtbot.mouseClick(tabGeneral.fontButton, Qt.LeftButton) qtbot.wait(keyDelay) tabGeneral.guiFontSize.setValue(12) # Projects Settings qtbot.wait(keyDelay) tabProjects = nwPrefs.tabProjects nwPrefs._tabBox.setCurrentWidget(tabProjects) tabProjects.backupPath = "no/where" qtbot.wait(keyDelay) assert not tabProjects.backupOnClose.isChecked() qtbot.mouseClick(tabProjects.backupOnClose, Qt.LeftButton) assert tabProjects.backupOnClose.isChecked() # qtbot.stopForInteraction() # Check Browse button monkeypatch.setattr(QFileDialog, "getExistingDirectory", lambda *a, **k: "") assert not tabProjects._backupFolder() monkeypatch.setattr(QFileDialog, "getExistingDirectory", lambda *a, **k: "some/dir") qtbot.mouseClick(tabProjects.backupGetPath, Qt.LeftButton) qtbot.wait(keyDelay) tabProjects.autoSaveDoc.setValue(20) tabProjects.autoSaveProj.setValue(40) # Document Settings qtbot.wait(keyDelay) tabDocs = nwPrefs.tabDocs nwPrefs._tabBox.setCurrentWidget(tabDocs) qtbot.wait(keyDelay) qtbot.mouseClick(tabDocs.fontButton, Qt.LeftButton) qtbot.wait(keyDelay) tabDocs.textSize.setValue(13) tabDocs.textWidth.setValue(700) tabDocs.focusWidth.setValue(900) tabDocs.textMargin.setValue(45) tabDocs.tabWidth.setValue(45) qtbot.wait(keyDelay) assert not tabDocs.hideFocusFooter.isChecked() qtbot.mouseClick(tabDocs.hideFocusFooter, Qt.LeftButton) assert tabDocs.hideFocusFooter.isChecked() qtbot.wait(keyDelay) assert not tabDocs.doJustify.isChecked() qtbot.mouseClick(tabDocs.doJustify, Qt.LeftButton) assert tabDocs.doJustify.isChecked() # Editor Settings qtbot.wait(keyDelay) tabEditor = nwPrefs.tabEditor nwPrefs._tabBox.setCurrentWidget(tabEditor) qtbot.wait(keyDelay) assert not tabEditor.showTabsNSpaces.isChecked() qtbot.mouseClick(tabEditor.showTabsNSpaces, Qt.LeftButton) assert tabEditor.showTabsNSpaces.isChecked() qtbot.wait(keyDelay) assert not tabEditor.showLineEndings.isChecked() qtbot.mouseClick(tabEditor.showLineEndings, Qt.LeftButton) assert tabEditor.showLineEndings.isChecked() qtbot.wait(keyDelay) assert not tabEditor.autoScroll.isChecked() qtbot.mouseClick(tabEditor.autoScroll, Qt.LeftButton) assert tabEditor.autoScroll.isChecked() qtbot.wait(keyDelay) tabEditor.scrollPastEnd.setValue(0) qtbot.wait(keyDelay) tabEditor.bigDocLimit.setValue(500) # Syntax Settings qtbot.wait(keyDelay) tabSyntax = nwPrefs.tabSyntax nwPrefs._tabBox.setCurrentWidget(tabSyntax) qtbot.wait(keyDelay) assert tabSyntax.highlightQuotes.isChecked() qtbot.mouseClick(tabSyntax.highlightQuotes, Qt.LeftButton) assert not tabSyntax.highlightQuotes.isChecked() qtbot.wait(keyDelay) assert tabSyntax.highlightEmph.isChecked() qtbot.mouseClick(tabSyntax.highlightEmph, Qt.LeftButton) assert not tabSyntax.highlightEmph.isChecked() # Automation Settings qtbot.wait(keyDelay) tabAuto = nwPrefs.tabAuto nwPrefs._tabBox.setCurrentWidget(tabAuto) qtbot.wait(keyDelay) assert tabAuto.autoSelect.isChecked() qtbot.mouseClick(tabAuto.autoSelect, Qt.LeftButton) assert not tabAuto.autoSelect.isChecked() qtbot.wait(keyDelay) assert tabAuto.doReplace.isChecked() qtbot.mouseClick(tabAuto.doReplace, Qt.LeftButton) assert not tabAuto.doReplace.isChecked() qtbot.wait(keyDelay) assert not tabAuto.doReplaceSQuote.isEnabled() assert not tabAuto.doReplaceDQuote.isEnabled() assert not tabAuto.doReplaceDash.isEnabled() assert not tabAuto.doReplaceDots.isEnabled() # Quotation Style qtbot.wait(keyDelay) tabQuote = nwPrefs.tabQuote nwPrefs._tabBox.setCurrentWidget(tabQuote) monkeypatch.setattr(GuiQuoteSelect, "selectedQuote", "'") monkeypatch.setattr(GuiQuoteSelect, "exec_", lambda *args: QDialog.Accepted) qtbot.mouseClick(tabQuote.btnDoubleStyleC, Qt.LeftButton) # Save and Check Config qtbot.mouseClick(nwPrefs.buttonBox.button(QDialogButtonBox.Ok), Qt.LeftButton) nwPrefs._doClose() assert theConf.confChanged theConf.lastPath = "" assert nwGUI.mainConf.saveConfig() projFile = os.path.join(fncDir, "novelwriter.conf") testFile = os.path.join(outDir, "guiPreferences_novelwriter.conf") compFile = os.path.join(refDir, "guiPreferences_novelwriter.conf") copyfile(projFile, testFile) ignTuple = ("timestamp", "guifont", "lastnotes", "guilang", "geometry", "preferences", "treecols", "novelcols", "projcols", "mainpane", "docpane", "viewpane", "outlinepane", "textfont", "textsize") assert cmpFiles(testFile, compFile, ignoreStart=ignTuple) # Clean up novelwriter.CONFIG = origConf nwGUI.closeMain()
def testBaseConfig_SettersGetters(tmpConf, tmpDir, outDir, refDir): """Set various sizes and positions """ confFile = os.path.join(tmpDir, "novelwriter.conf") testFile = os.path.join(outDir, "baseConfig_novelwriter.conf") compFile = os.path.join(refDir, "baseConfig_novelwriter.conf") # GUI Scaling # =========== tmpConf.guiScale = 1.0 assert tmpConf.pxInt(10) == 10 assert tmpConf.pxInt(13) == 13 assert tmpConf.rpxInt(10) == 10 assert tmpConf.rpxInt(13) == 13 tmpConf.guiScale = 2.0 assert tmpConf.pxInt(10) == 20 assert tmpConf.pxInt(13) == 26 assert tmpConf.rpxInt(10) == 5 assert tmpConf.rpxInt(13) == 6 # Setter + Getter Combos # ====================== # Window Size tmpConf.guiScale = 1.0 assert tmpConf.setWinSize(1205, 655) assert not tmpConf.confChanged tmpConf.guiScale = 2.0 assert tmpConf.setWinSize(70, 70) assert tmpConf.getWinSize() == [70, 70] assert tmpConf.winGeometry == [35, 35] tmpConf.guiScale = 1.0 assert tmpConf.setWinSize(70, 70) assert tmpConf.getWinSize() == [70, 70] assert tmpConf.winGeometry == [70, 70] assert tmpConf.setWinSize(1200, 650) # Project Tree Columns tmpConf.guiScale = 2.0 assert tmpConf.setTreeColWidths([10, 20, 25]) assert tmpConf.getTreeColWidths() == [10, 20, 24] assert tmpConf.treeColWidth == [5, 10, 12] tmpConf.guiScale = 1.0 assert tmpConf.setTreeColWidths([10, 20, 25]) assert tmpConf.getTreeColWidths() == [10, 20, 25] assert tmpConf.treeColWidth == [10, 20, 25] assert tmpConf.setTreeColWidths([200, 50, 30]) # Novel Tree Columns tmpConf.guiScale = 2.0 assert tmpConf.setNovelColWidths([10, 20]) assert tmpConf.getNovelColWidths() == [10, 20] assert tmpConf.novelColWidth == [5, 10] tmpConf.guiScale = 1.0 assert tmpConf.setNovelColWidths([10, 20]) assert tmpConf.getNovelColWidths() == [10, 20] assert tmpConf.novelColWidth == [10, 20] assert tmpConf.setNovelColWidths([200, 50]) # Project Settings Tree Columns tmpConf.guiScale = 2.0 assert tmpConf.setProjColWidths([10, 20, 30]) assert tmpConf.getProjColWidths() == [10, 20, 30] assert tmpConf.projColWidth == [5, 10, 15] tmpConf.guiScale = 1.0 assert tmpConf.setProjColWidths([10, 20, 30]) assert tmpConf.getProjColWidths() == [10, 20, 30] assert tmpConf.projColWidth == [10, 20, 30] assert tmpConf.setProjColWidths([200, 60, 140]) # Main Pane Splitter tmpConf.guiScale = 2.0 assert tmpConf.setMainPanePos([200, 700]) assert tmpConf.getMainPanePos() == [200, 700] assert tmpConf.mainPanePos == [100, 350] tmpConf.guiScale = 1.0 assert tmpConf.setMainPanePos([200, 700]) assert tmpConf.getMainPanePos() == [200, 700] assert tmpConf.mainPanePos == [200, 700] assert tmpConf.setMainPanePos([300, 800]) # Doc Pane Splitter tmpConf.guiScale = 2.0 assert tmpConf.setDocPanePos([300, 300]) assert tmpConf.getDocPanePos() == [300, 300] assert tmpConf.docPanePos == [150, 150] tmpConf.guiScale = 1.0 assert tmpConf.setDocPanePos([300, 300]) assert tmpConf.getDocPanePos() == [300, 300] assert tmpConf.docPanePos == [300, 300] assert tmpConf.setDocPanePos([400, 400]) # View Pane Splitter tmpConf.guiScale = 2.0 assert tmpConf.setViewPanePos([400, 250]) assert tmpConf.getViewPanePos() == [400, 250] assert tmpConf.viewPanePos == [200, 125] tmpConf.guiScale = 1.0 assert tmpConf.setViewPanePos([400, 250]) assert tmpConf.getViewPanePos() == [400, 250] assert tmpConf.viewPanePos == [400, 250] assert tmpConf.setViewPanePos([500, 150]) # Outline Pane Splitter tmpConf.guiScale = 2.0 assert tmpConf.setOutlinePanePos([400, 250]) assert tmpConf.getOutlinePanePos() == [400, 250] assert tmpConf.outlnPanePos == [200, 125] tmpConf.guiScale = 1.0 assert tmpConf.setOutlinePanePos([400, 250]) assert tmpConf.getOutlinePanePos() == [400, 250] assert tmpConf.outlnPanePos == [400, 250] assert tmpConf.setOutlinePanePos([500, 150]) # Getters Only # ============ tmpConf.guiScale = 1.0 assert tmpConf.getTextWidth() == 600 assert tmpConf.getTextMargin() == 40 assert tmpConf.getTabWidth() == 40 assert tmpConf.getFocusWidth() == 800 tmpConf.guiScale = 2.0 assert tmpConf.getTextWidth() == 1200 assert tmpConf.getTextMargin() == 80 assert tmpConf.getTabWidth() == 80 assert tmpConf.getFocusWidth() == 1600 # Flag Setters # ============ assert not tmpConf.setShowRefPanel(False) assert not tmpConf.showRefPanel assert tmpConf.setShowRefPanel(True) assert not tmpConf.setViewComments(False) assert not tmpConf.viewComments assert tmpConf.setViewComments(True) assert not tmpConf.setViewSynopsis(False) assert not tmpConf.viewSynopsis assert tmpConf.setViewSynopsis(True) # Check Final File # ================ assert tmpConf.confChanged assert tmpConf.saveConfig() assert not tmpConf.confChanged copyfile(confFile, testFile) assert cmpFiles(testFile, compFile, [2, 9, 10])
def testCoreIndex_LoadSave(monkeypatch, nwLipsum, dummyGUI, outDir, refDir): """Test core functionality of scaning, saving, loading and checking the index cache file. """ projFile = os.path.join(nwLipsum, "meta", "tagsIndex.json") testFile = os.path.join(outDir, "coreIndex_LoadSave_tagsIndex.json") compFile = os.path.join(refDir, "coreIndex_LoadSave_tagsIndex.json") theProject = NWProject(dummyGUI) theProject.projTree.setSeed(42) assert theProject.openProject(nwLipsum) monkeypatch.setattr("nw.core.index.time", lambda: 123.4) theIndex = NWIndex(theProject, dummyGUI) notIndexable = { "b3643d0f92e32": False, # Novel ROOT "45e6b01ca35c1": False, # Chapter One FOLDER "6bd935d2490cd": False, # Chapter Two FOLDER "67a8707f2f249": False, # Character ROOT "6c6afb1247750": False, # Plot ROOT "60bdf227455cc": False, # World ROOT } for tItem in theProject.projTree: assert theIndex.reIndexHandle(tItem.itemHandle) is notIndexable.get( tItem.itemHandle, True) assert not theIndex.reIndexHandle(None) # Dummy exception function def doPanic(*arg, **kwargs): raise Exception # Make the save fail monkeypatch.setattr(json, "dump", doPanic) assert not theIndex.saveIndex() # Make the save pass monkeypatch.undo() assert theIndex.saveIndex() # Take a copy of the index tagIndex = str(theIndex.tagIndex) refIndex = str(theIndex.refIndex) novelIndex = str(theIndex.novelIndex) noteIndex = str(theIndex.noteIndex) textCounts = str(theIndex.textCounts) # Delete a handle assert theIndex.tagIndex.get("Bod", None) is not None assert theIndex.refIndex.get("4c4f28287af27", None) is not None assert theIndex.noteIndex.get("4c4f28287af27", None) is not None assert theIndex.textCounts.get("4c4f28287af27", None) is not None theIndex.deleteHandle("4c4f28287af27") assert theIndex.tagIndex.get("Bod", None) is None assert theIndex.refIndex.get("4c4f28287af27", None) is None assert theIndex.noteIndex.get("4c4f28287af27", None) is None assert theIndex.textCounts.get("4c4f28287af27", None) is None # Clear the index theIndex.clearIndex() assert not theIndex.tagIndex assert not theIndex.refIndex assert not theIndex.novelIndex assert not theIndex.noteIndex assert not theIndex.textCounts # Make the load fail monkeypatch.setattr(json, "load", doPanic) assert not theIndex.loadIndex() # Make the load pass monkeypatch.undo() assert theIndex.loadIndex() assert str(theIndex.tagIndex) == tagIndex assert str(theIndex.refIndex) == refIndex assert str(theIndex.novelIndex) == novelIndex assert str(theIndex.noteIndex) == noteIndex assert str(theIndex.textCounts) == textCounts # Break the index and check that we notice assert not theIndex.indexBroken theIndex.tagIndex["Bod"].append("Stuff") # No longer len() == 4 theIndex.checkIndex() assert theIndex.indexBroken assert theIndex.loadIndex() assert not theIndex.indexBroken theIndex.refIndex["fb609cd8319dc"]["T000001"]["tags"].append( "Stuff") # No longer len() == 3 theIndex.checkIndex() assert theIndex.indexBroken assert theIndex.loadIndex() assert not theIndex.indexBroken theIndex.novelIndex["7a992350f3eb6"]["T000001"][ "Stuff"] = "" # No longer len(keys()) == 8 theIndex.checkIndex() assert theIndex.indexBroken assert theIndex.loadIndex() assert not theIndex.indexBroken theIndex.noteIndex["4c4f28287af27"]["T000001"][ "Stuff"] = "" # No longer len(keys()) == 8 theIndex.checkIndex() assert theIndex.indexBroken assert theIndex.loadIndex() assert not theIndex.indexBroken theIndex.textCounts["7a992350f3eb6"].append( "Stuff") # No longer len() == 3 theIndex.checkIndex() assert theIndex.indexBroken # Make the try/except trigger as well assert theIndex.loadIndex() assert not theIndex.indexBroken theIndex.refIndex["fb609cd8319dc"]["T000001"] = { "tagssss": [] } # Wrong key name theIndex.checkIndex() assert theIndex.indexBroken # Finalise assert theProject.closeProject() copyfile(projFile, testFile) assert cmpFiles(testFile, compFile)
def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir, filesDir): """Test config intialisation. """ tstConf = Config() confFile = os.path.join(tmpDir, "novelwriter.conf") testFile = os.path.join(outDir, "baseConfig_novelwriter.conf") compFile = os.path.join(refDir, "baseConfig_novelwriter.conf") # Make sure we don't have any old conf file if os.path.isfile(confFile): os.unlink(confFile) # Let the config class figure out the path with monkeypatch.context() as mp: mp.setattr("PyQt5.QtCore.QStandardPaths.writableLocation", lambda *a: fncDir) tstConf.verQtValue = 50600 tstConf.initConfig() assert tstConf.confPath == os.path.join(fncDir, tstConf.appHandle) assert tstConf.dataPath == os.path.join(fncDir, tstConf.appHandle) assert not os.path.isfile(confFile) tstConf.verQtValue = 50000 tstConf.initConfig() assert tstConf.confPath == os.path.join(fncDir, tstConf.appHandle) assert tstConf.dataPath == os.path.join(fncDir, tstConf.appHandle) assert not os.path.isfile(confFile) # Fail to make folders with monkeypatch.context() as mp: mp.setattr("os.mkdir", causeOSError) tstConfDir = os.path.join(fncDir, "test_conf") tstConf.initConfig(confPath=tstConfDir, dataPath=tmpDir) assert tstConf.confPath is None assert tstConf.dataPath == tmpDir assert not os.path.isfile(confFile) tstDataDir = os.path.join(fncDir, "test_data") tstConf.initConfig(confPath=tmpDir, dataPath=tstDataDir) assert tstConf.confPath == tmpDir assert tstConf.dataPath is None assert os.path.isfile(confFile) os.unlink(confFile) # Test load/save with no path tstConf.confPath = None assert tstConf.loadConfig() is False assert tstConf.saveConfig() is False # Run again and set the paths directly and correctly # This should create a config file as well with monkeypatch.context() as mp: mp.setattr("os.path.expanduser", lambda *a: "") tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir) assert tstConf.confPath == tmpDir assert tstConf.dataPath == tmpDir assert os.path.isfile(confFile) copyfile(confFile, testFile) assert cmpFiles(testFile, compFile, ignoreStart=("timestamp", "lastnotes", "guilang")) # Load and save with OSError with monkeypatch.context() as mp: mp.setattr("builtins.open", causeOSError) assert not tstConf.loadConfig() assert tstConf.hasError is True assert tstConf.errData != [] assert tstConf.getErrData().startswith("Could not") assert tstConf.hasError is False assert tstConf.errData == [] assert not tstConf.saveConfig() assert tstConf.hasError is True assert tstConf.errData != [] assert tstConf.getErrData().startswith("Could not") assert tstConf.hasError is False assert tstConf.errData == [] # Check handling of novelWriter as a package with monkeypatch.context() as mp: tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir) assert tstConf.confPath == tmpDir assert tstConf.dataPath == tmpDir appRoot = tstConf.appRoot mp.setattr("os.path.isfile", lambda *a: True) tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir) assert tstConf.confPath == tmpDir assert tstConf.dataPath == tmpDir assert tstConf.appRoot == os.path.dirname(appRoot) assert tstConf.appPath == os.path.dirname(appRoot) assert tstConf.loadConfig() is True assert tstConf.saveConfig() is True # Test Correcting Quote Settings origDbl = tstConf.fmtDoubleQuotes origSng = tstConf.fmtSingleQuotes orDoDbl = tstConf.doReplaceDQuote orDoSng = tstConf.doReplaceSQuote tstConf.fmtDoubleQuotes = ["\"", "\""] tstConf.fmtSingleQuotes = ["'", "'"] tstConf.doReplaceDQuote = True tstConf.doReplaceSQuote = True assert tstConf.saveConfig() is True assert tstConf.loadConfig() is True assert tstConf.doReplaceDQuote is False assert tstConf.doReplaceSQuote is False tstConf.fmtDoubleQuotes = origDbl tstConf.fmtSingleQuotes = origSng tstConf.doReplaceDQuote = orDoDbl tstConf.doReplaceSQuote = orDoSng assert tstConf.saveConfig() is True # Test Correcting icon theme origIcons = tstConf.guiIcons tstConf.guiIcons = "typicons_colour_dark" assert tstConf.saveConfig() is True assert tstConf.loadConfig() is True assert tstConf.guiIcons == "typicons_dark" tstConf.guiIcons = "typicons_grey_dark" assert tstConf.saveConfig() is True assert tstConf.loadConfig() is True assert tstConf.guiIcons == "typicons_dark" tstConf.guiIcons = "typicons_colour_light" assert tstConf.saveConfig() is True assert tstConf.loadConfig() is True assert tstConf.guiIcons == "typicons_light" tstConf.guiIcons = "typicons_grey_light" assert tstConf.saveConfig() is True assert tstConf.loadConfig() is True assert tstConf.guiIcons == "typicons_light" tstConf.guiIcons = origIcons assert tstConf.saveConfig() # Localisation # ============ i18nDir = os.path.join(fncDir, "i18n") os.mkdir(i18nDir) os.mkdir(os.path.join(i18nDir, "stuff")) tstConf.nwLangPath = i18nDir copyfile(os.path.join(filesDir, "nw_en_GB.qm"), os.path.join(i18nDir, "nw_en_GB.qm")) writeFile(os.path.join(i18nDir, "nw_en_GB.ts"), "") writeFile(os.path.join(i18nDir, "nw_abcd.qm"), "") tstApp = MockApp() tstConf.initLocalisation(tstApp) # Check Lists theList = tstConf.listLanguages(tstConf.LANG_NW) assert theList == [("en_GB", "British English")] theList = tstConf.listLanguages(tstConf.LANG_PROJ) assert theList == [("en_GB", "British English")] theList = tstConf.listLanguages(None) assert theList == [] # Add Language copyfile(os.path.join(filesDir, "nw_en_GB.qm"), os.path.join(i18nDir, "nw_fr.qm")) writeFile(os.path.join(i18nDir, "nw_fr.ts"), "") theList = tstConf.listLanguages(tstConf.LANG_NW) assert theList == [("en_GB", "British English"), ("fr", "Français")] copyfile(confFile, testFile) assert cmpFiles(testFile, compFile, ignoreStart=("timestamp", "lastnotes", "guilang"))
def testCoreToOdt_SaveFull(mockGUI, fncDir, outDir, refDir): """Test the document save functions. """ theProject = NWProject(mockGUI) theDoc = ToOdt(theProject, isFlat=False) theDoc._isNovel = True theDoc._theText = ("## Chapter One\n\n" "Text\n\n" "## Chapter Two\n\n" "Text\n\n") theDoc.tokenizeText() theDoc.initDocument() theDoc.doConvert() theDoc.closeDocument() fullFile = os.path.join(fncDir, "document.odt") theDoc.saveOpenDocText(fullFile) assert os.path.isfile(fullFile) assert zipfile.is_zipfile(fullFile) maniFile = os.path.join(outDir, "coreToOdt_SaveFull_manifest.xml") settFile = os.path.join(outDir, "coreToOdt_SaveFull_settings.xml") contFile = os.path.join(outDir, "coreToOdt_SaveFull_content.xml") metaFile = os.path.join(outDir, "coreToOdt_SaveFull_meta.xml") stylFile = os.path.join(outDir, "coreToOdt_SaveFull_styles.xml") maniComp = os.path.join(refDir, "coreToOdt_SaveFull_manifest.xml") settComp = os.path.join(refDir, "coreToOdt_SaveFull_settings.xml") contComp = os.path.join(refDir, "coreToOdt_SaveFull_content.xml") metaComp = os.path.join(refDir, "coreToOdt_SaveFull_meta.xml") stylComp = os.path.join(refDir, "coreToOdt_SaveFull_styles.xml") extaxtTo = os.path.join(outDir, "coreToOdt_SaveFull") with zipfile.ZipFile(fullFile, mode="r") as theZip: theZip.extract("META-INF/manifest.xml", extaxtTo) theZip.extract("settings.xml", extaxtTo) theZip.extract("content.xml", extaxtTo) theZip.extract("meta.xml", extaxtTo) theZip.extract("styles.xml", extaxtTo) maniOut = os.path.join(outDir, "coreToOdt_SaveFull", "META-INF", "manifest.xml") settOut = os.path.join(outDir, "coreToOdt_SaveFull", "settings.xml") contOut = os.path.join(outDir, "coreToOdt_SaveFull", "content.xml") metaOut = os.path.join(outDir, "coreToOdt_SaveFull", "meta.xml") stylOut = os.path.join(outDir, "coreToOdt_SaveFull", "styles.xml") def prettifyXml(inFile, outFile): with open(outFile, mode="wb") as fileStream: fileStream.write( etree.tostring(etree.parse(inFile), pretty_print=True, encoding="utf-8", xml_declaration=True)) prettifyXml(maniOut, maniFile) prettifyXml(settOut, settFile) prettifyXml(contOut, contFile) prettifyXml(metaOut, metaFile) prettifyXml(stylOut, stylFile) assert cmpFiles(maniFile, maniComp) assert cmpFiles(settFile, settComp) assert cmpFiles(contFile, contComp) assert cmpFiles(metaFile, metaComp, [4, 5]) assert cmpFiles(stylFile, stylComp)
def testGuiBuild_Tool(qtbot, monkeypatch, nwGUI, nwLipsum, refDir, outDir): """Test the build tool. """ # Block message box monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes) monkeypatch.setattr(QMessageBox, "information", lambda *args: QMessageBox.Yes) monkeypatch.setattr(QFileDialog, "getSaveFileName", lambda a, b, c, **kwargs: (c, None)) # Check that we cannot open when there is no project nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger) assert getGuiItem("GuiBuildNovel") is None # Open a project assert nwGUI.openProject(nwLipsum) nwGUI.mainConf.lastPath = nwLipsum # Open the tool nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger) qtbot.waitUntil(lambda: getGuiItem("GuiBuildNovel") is not None, timeout=1000) nwBuild = getGuiItem("GuiBuildNovel") assert isinstance(nwBuild, GuiBuildNovel) # Default Settings qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton) assert nwBuild._saveDocument(nwBuild.FMT_NWD) assert nwBuild._saveDocument(nwBuild.FMT_HTM) projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd") testFile = os.path.join(outDir, "guiBuild_Tool_Step1_Lorem_Ipsum.nwd") compFile = os.path.join(refDir, "guiBuild_Tool_Step1_Lorem_Ipsum.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm") testFile = os.path.join(outDir, "guiBuild_Tool_Step1_Lorem_Ipsum.htm") compFile = os.path.join(refDir, "guiBuild_Tool_Step1_Lorem_Ipsum.htm") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) # Change Title Formats and Flip Switches nwBuild.fmtChapter.setText(r"Chapter %chw%: %title%") qtbot.wait(stepDelay) nwBuild.fmtScene.setText(r"Scene %ch%.%sc%: %title%") qtbot.wait(stepDelay) nwBuild.fmtSection.setText(r"%ch%.%sc%.1: %title%") qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.justifyText, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.includeSynopsis, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.includeComments, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.includeKeywords, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.noteFiles, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.ignoreFlag, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton) assert nwBuild._saveDocument(nwBuild.FMT_NWD) assert nwBuild._saveDocument(nwBuild.FMT_HTM) projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd") testFile = os.path.join(outDir, "guiBuild_Tool_Step2_Lorem_Ipsum.nwd") compFile = os.path.join(refDir, "guiBuild_Tool_Step2_Lorem_Ipsum.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm") testFile = os.path.join(outDir, "guiBuild_Tool_Step2_Lorem_Ipsum.htm") compFile = os.path.join(refDir, "guiBuild_Tool_Step2_Lorem_Ipsum.htm") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) # Replace Tabs with Spaces qtbot.mouseClick(nwBuild.replaceTabs, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton) # Save files that can be compared assert nwBuild._saveDocument(nwBuild.FMT_NWD) projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd") testFile = os.path.join(outDir, "guiBuild_Tool_Step3_Lorem_Ipsum.nwd") compFile = os.path.join(refDir, "guiBuild_Tool_Step3_Lorem_Ipsum.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) assert nwBuild._saveDocument(nwBuild.FMT_HTM) projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm") testFile = os.path.join(outDir, "guiBuild_Tool_Step3_Lorem_Ipsum.htm") compFile = os.path.join(refDir, "guiBuild_Tool_Step3_Lorem_Ipsum.htm") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) # Putline Mode nwBuild.fmtChapter.setText(r"Chapter %chw%: %title%") qtbot.wait(stepDelay) nwBuild.fmtScene.setText(r"Scene %sca%: %title%") qtbot.wait(stepDelay) nwBuild.fmtSection.setText(r"Section: %title%") qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.includeComments, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.noteFiles, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.ignoreFlag, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.includeBody, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton) # Save files that can be compared assert nwBuild._saveDocument(nwBuild.FMT_NWD) projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd") testFile = os.path.join(outDir, "guiBuild_Tool_Step4_Lorem_Ipsum.nwd") compFile = os.path.join(refDir, "guiBuild_Tool_Step4_Lorem_Ipsum.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) assert nwBuild._saveDocument(nwBuild.FMT_HTM) projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm") testFile = os.path.join(outDir, "guiBuild_Tool_Step4_Lorem_Ipsum.htm") compFile = os.path.join(refDir, "guiBuild_Tool_Step4_Lorem_Ipsum.htm") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) # Check the JSON files too at this stage assert nwBuild._saveDocument(nwBuild.FMT_JSON_H) projFile = os.path.join(nwLipsum, "Lorem Ipsum.json") testFile = os.path.join(outDir, "guiBuild_Tool_Step4H_Lorem_Ipsum.json") compFile = os.path.join(refDir, "guiBuild_Tool_Step4H_Lorem_Ipsum.json") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [8]) assert nwBuild._saveDocument(nwBuild.FMT_JSON_M) projFile = os.path.join(nwLipsum, "Lorem Ipsum.json") testFile = os.path.join(outDir, "guiBuild_Tool_Step4M_Lorem_Ipsum.json") compFile = os.path.join(refDir, "guiBuild_Tool_Step4M_Lorem_Ipsum.json") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [8]) # Save other file types handled by Qt # We assume the export itself by the Qt library works, so we just # check that novelWriter successfully writes the files. assert nwBuild._saveDocument(nwBuild.FMT_ODT) assert os.path.isfile(os.path.join(nwLipsum, "Lorem Ipsum.odt")) if not nwGUI.mainConf.osDarwin: assert nwBuild._saveDocument(nwBuild.FMT_PDF) assert os.path.isfile(os.path.join(nwLipsum, "Lorem Ipsum.pdf")) assert nwBuild._saveDocument(nwBuild.FMT_MD) assert os.path.isfile(os.path.join(nwLipsum, "Lorem Ipsum.md")) assert nwBuild._saveDocument(nwBuild.FMT_TXT) assert os.path.isfile(os.path.join(nwLipsum, "Lorem Ipsum.txt")) # Close the build tool htmlText = nwBuild.htmlText htmlStyle = nwBuild.htmlStyle nwdText = nwBuild.nwdText buildTime = nwBuild.buildTime nwBuild._doClose() # Re-open build dialog from cahce nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger) qtbot.waitUntil(lambda: getGuiItem("GuiBuildNovel") is not None, timeout=1000) nwBuild = getGuiItem("GuiBuildNovel") assert isinstance(nwBuild, GuiBuildNovel) assert nwBuild.viewCachedDoc() assert nwBuild.htmlText == htmlText assert nwBuild.htmlStyle == htmlStyle assert nwBuild.nwdText == nwdText assert nwBuild.buildTime == buildTime nwBuild._doClose()
def testGuiPreferences_Main(qtbot, monkeypatch, fncDir, outDir, refDir): """Test the load project wizard. """ # Block message box monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes) monkeypatch.setattr(QMessageBox, "information", lambda *args: QMessageBox.Yes) # Must create a clean config and GUI object as the test-wide # nw.CONFIG object is created on import an can be tainted by other tests confFile = os.path.join(fncDir, "novelwriter.conf") if os.path.isfile(confFile): os.unlink(confFile) theConf = Config() theConf.initConfig(fncDir, fncDir) theConf.setLastPath("") origConf = nw.CONFIG nw.CONFIG = theConf nwGUI = nw.main( ["--testmode", "--config=%s" % fncDir, "--data=%s" % fncDir]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(20) theConf = nwGUI.mainConf assert theConf.confPath == fncDir monkeypatch.setattr(GuiPreferences, "exec_", lambda *args: None) monkeypatch.setattr(GuiPreferences, "result", lambda *args: QDialog.Accepted) nwGUI.mainMenu.aPreferences.activate(QAction.Trigger) qtbot.waitUntil(lambda: getGuiItem("GuiPreferences") is not None, timeout=1000) nwPrefs = getGuiItem("GuiPreferences") assert isinstance(nwPrefs, GuiPreferences) nwPrefs.show() assert nwPrefs.mainConf.confPath == fncDir # qtbot.stopForInteraction() # General Settings qtbot.wait(keyDelay) tabGeneral = nwPrefs.tabGeneral nwPrefs._tabBox.setCurrentWidget(tabGeneral) qtbot.wait(keyDelay) assert not tabGeneral.preferDarkIcons.isChecked() qtbot.mouseClick(tabGeneral.preferDarkIcons, Qt.LeftButton) assert tabGeneral.preferDarkIcons.isChecked() qtbot.wait(keyDelay) assert tabGeneral.showFullPath.isChecked() qtbot.mouseClick(tabGeneral.showFullPath, Qt.LeftButton) assert not tabGeneral.showFullPath.isChecked() qtbot.wait(keyDelay) assert not tabGeneral.hideVScroll.isChecked() qtbot.mouseClick(tabGeneral.hideVScroll, Qt.LeftButton) assert tabGeneral.hideVScroll.isChecked() qtbot.wait(keyDelay) assert not tabGeneral.hideHScroll.isChecked() qtbot.mouseClick(tabGeneral.hideHScroll, Qt.LeftButton) assert tabGeneral.hideHScroll.isChecked() # Check font button monkeypatch.setattr(QFontDialog, "getFont", lambda font, obj: (font, True)) qtbot.mouseClick(tabGeneral.fontButton, Qt.LeftButton) qtbot.wait(keyDelay) tabGeneral.guiFontSize.setValue(12) # Projects Settings qtbot.wait(keyDelay) tabProjects = nwPrefs.tabProjects nwPrefs._tabBox.setCurrentWidget(tabProjects) tabProjects.backupPath = "no/where" qtbot.wait(keyDelay) assert not tabProjects.backupOnClose.isChecked() qtbot.mouseClick(tabProjects.backupOnClose, Qt.LeftButton) assert tabProjects.backupOnClose.isChecked() # Check Browse button monkeypatch.setattr(QFileDialog, "getExistingDirectory", lambda *args, **kwargs: "") assert not tabProjects._backupFolder() monkeypatch.setattr(QFileDialog, "getExistingDirectory", lambda *args, **kwargs: "some/dir") qtbot.mouseClick(tabProjects.backupGetPath, Qt.LeftButton) qtbot.wait(keyDelay) tabProjects.autoSaveDoc.setValue(20) tabProjects.autoSaveProj.setValue(40) # Text Layout Settings qtbot.wait(keyDelay) tabLayout = nwPrefs.tabLayout nwPrefs._tabBox.setCurrentWidget(tabLayout) qtbot.wait(keyDelay) qtbot.mouseClick(tabLayout.fontButton, Qt.LeftButton) qtbot.wait(keyDelay) tabLayout.textStyleSize.setValue(13) tabLayout.textFlowMax.setValue(700) tabLayout.focusDocWidth.setValue(900) tabLayout.textMargin.setValue(45) tabLayout.tabWidth.setValue(45) qtbot.wait(keyDelay) assert not tabLayout.textFlowFixed.isChecked() qtbot.mouseClick(tabLayout.textFlowFixed, Qt.LeftButton) assert tabLayout.textFlowFixed.isChecked() qtbot.wait(keyDelay) assert not tabLayout.hideFocusFooter.isChecked() qtbot.mouseClick(tabLayout.hideFocusFooter, Qt.LeftButton) assert tabLayout.hideFocusFooter.isChecked() qtbot.wait(keyDelay) assert not tabLayout.textJustify.isChecked() qtbot.mouseClick(tabLayout.textJustify, Qt.LeftButton) assert tabLayout.textJustify.isChecked() qtbot.wait(keyDelay) assert tabLayout.scrollPastEnd.isChecked() qtbot.mouseClick(tabLayout.scrollPastEnd, Qt.LeftButton) assert not tabLayout.scrollPastEnd.isChecked() qtbot.wait(keyDelay) assert not tabLayout.autoScroll.isChecked() qtbot.mouseClick(tabLayout.autoScroll, Qt.LeftButton) assert tabLayout.autoScroll.isChecked() # Editor Settings qtbot.wait(keyDelay) tabEditing = nwPrefs.tabEditing nwPrefs._tabBox.setCurrentWidget(tabEditing) qtbot.wait(keyDelay) assert tabEditing.highlightQuotes.isChecked() qtbot.mouseClick(tabEditing.highlightQuotes, Qt.LeftButton) assert not tabEditing.highlightQuotes.isChecked() qtbot.wait(keyDelay) assert tabEditing.highlightEmph.isChecked() qtbot.mouseClick(tabEditing.highlightEmph, Qt.LeftButton) assert not tabEditing.highlightEmph.isChecked() qtbot.wait(keyDelay) assert not tabEditing.showTabsNSpaces.isChecked() qtbot.mouseClick(tabEditing.showTabsNSpaces, Qt.LeftButton) assert tabEditing.showTabsNSpaces.isChecked() qtbot.wait(keyDelay) assert not tabEditing.showLineEndings.isChecked() qtbot.mouseClick(tabEditing.showLineEndings, Qt.LeftButton) assert tabEditing.showLineEndings.isChecked() qtbot.wait(keyDelay) tabEditing.bigDocLimit.setValue(500) # Auto-Replace Settings qtbot.wait(keyDelay) tabAutoRep = nwPrefs.tabAutoRep nwPrefs._tabBox.setCurrentWidget(tabAutoRep) qtbot.wait(keyDelay) assert tabAutoRep.autoSelect.isChecked() qtbot.mouseClick(tabAutoRep.autoSelect, Qt.LeftButton) assert not tabAutoRep.autoSelect.isChecked() qtbot.wait(keyDelay) assert tabAutoRep.autoReplaceMain.isChecked() qtbot.mouseClick(tabAutoRep.autoReplaceMain, Qt.LeftButton) assert not tabAutoRep.autoReplaceMain.isChecked() qtbot.wait(keyDelay) assert not tabAutoRep.autoReplaceSQ.isEnabled() assert not tabAutoRep.autoReplaceDQ.isEnabled() assert not tabAutoRep.autoReplaceDash.isEnabled() assert not tabAutoRep.autoReplaceDots.isEnabled() monkeypatch.setattr(QuotesDialog, "selectedQuote", "'") monkeypatch.setattr(QuotesDialog, "exec_", lambda *args: QDialog.Accepted) qtbot.mouseClick(tabAutoRep.btnDoubleStyleC, Qt.LeftButton) # Save and Check Config qtbot.mouseClick(nwPrefs.buttonBox.button(QDialogButtonBox.Ok), Qt.LeftButton) nwPrefs._doClose() assert theConf.confChanged theConf.lastPath = "" assert nwGUI.mainConf.saveConfig() projFile = os.path.join(fncDir, "novelwriter.conf") testFile = os.path.join(outDir, "guiPreferences_novelwriter.conf") compFile = os.path.join(refDir, "guiPreferences_novelwriter.conf") copyfile(projFile, testFile) ignoreLines = [ 2, # Timestamp 9, # Release Notes 12, 13, 14, 15, 16, 17, 18, # Window sizes 7, 28, # Fonts (depends on system default) ] assert cmpFiles(testFile, compFile, ignoreLines) # Clean up nw.CONFIG = origConf nwGUI.closeMain()
def testToolBuild_Main(qtbot, monkeypatch, nwGUI, nwLipsum, refDir, outDir): """Test the build tool. """ # Block message box monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes) monkeypatch.setattr(QMessageBox, "information", lambda *args: QMessageBox.Yes) monkeypatch.setattr(QFileDialog, "getSaveFileName", lambda a, b, c, **kwargs: (c, None)) # Check that we cannot open when there is no project nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger) assert getGuiItem("GuiBuildNovel") is None # Open a project assert nwGUI.openProject(nwLipsum) # Open the tool nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger) qtbot.waitUntil(lambda: getGuiItem("GuiBuildNovel") is not None, timeout=1000) nwBuild = getGuiItem("GuiBuildNovel") assert isinstance(nwBuild, GuiBuildNovel) nwBuild.textFont.setText("DejaVu Sans") nwBuild.textSize.setValue(11) # Test Save # ========= # Invalid file format assert not nwBuild._saveDocument(-1) # Non-existent path with monkeypatch.context() as mp: mp.setattr("os.path.expanduser", lambda *args, **kwargs: nwLipsum) assert nwGUI.mainConf.lastPath != nwLipsum nwGUI.mainConf.lastPath = "no_such_path" assert nwBuild._saveDocument(nwBuild.FMT_NWD) assert nwGUI.mainConf.lastPath == nwLipsum # No path selected with monkeypatch.context() as mp: mp.setattr(QFileDialog, "getSaveFileName", lambda *args, **kwargs: ("", "")) assert not nwBuild._saveDocument(nwBuild.FMT_NWD) # Default Settings nwGUI.mainConf.lastPath = nwLipsum qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton) assert nwBuild._saveDocument(nwBuild.FMT_NWD) projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd") testFile = os.path.join(outDir, "guiBuild_Tool_Step1_Lorem_Ipsum.nwd") compFile = os.path.join(refDir, "guiBuild_Tool_Step1_Lorem_Ipsum.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) assert nwBuild._saveDocument(nwBuild.FMT_HTM) projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm") testFile = os.path.join(outDir, "guiBuild_Tool_Step1_Lorem_Ipsum.htm") compFile = os.path.join(refDir, "guiBuild_Tool_Step1_Lorem_Ipsum.htm") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) assert nwBuild._saveDocument(nwBuild.FMT_MD) projFile = os.path.join(nwLipsum, "Lorem Ipsum.md") testFile = os.path.join(outDir, "guiBuild_Tool_Step1_Lorem_Ipsum.md") compFile = os.path.join(refDir, "guiBuild_Tool_Step1_Lorem_Ipsum.md") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) assert nwBuild._saveDocument(nwBuild.FMT_GH) projFile = os.path.join(nwLipsum, "Lorem Ipsum.md") testFile = os.path.join(outDir, "guiBuild_Tool_Step1G_Lorem_Ipsum.md") compFile = os.path.join(refDir, "guiBuild_Tool_Step1G_Lorem_Ipsum.md") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) assert nwBuild._saveDocument(nwBuild.FMT_FODT) projFile = os.path.join(nwLipsum, "Lorem Ipsum.fodt") testFile = os.path.join(outDir, "guiBuild_Tool_Step1_Lorem_Ipsum.fodt") compFile = os.path.join(refDir, "guiBuild_Tool_Step1_Lorem_Ipsum.fodt") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [4, 5]) # Change Title Formats and Flip Switches nwBuild.fmtChapter.setText(r"Chapter %chw%: %title%") qtbot.wait(stepDelay) nwBuild.fmtScene.setText(r"Scene %ch%.%sc%: %title%") qtbot.wait(stepDelay) nwBuild.fmtSection.setText(r"%ch%.%sc%.1: %title%") qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.justifyText, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.includeSynopsis, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.includeComments, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.includeKeywords, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.replaceUCode, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.noteFiles, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.ignoreFlag, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton) assert nwBuild._saveDocument(nwBuild.FMT_NWD) projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd") testFile = os.path.join(outDir, "guiBuild_Tool_Step2_Lorem_Ipsum.nwd") compFile = os.path.join(refDir, "guiBuild_Tool_Step2_Lorem_Ipsum.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) assert nwBuild._saveDocument(nwBuild.FMT_HTM) projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm") testFile = os.path.join(outDir, "guiBuild_Tool_Step2_Lorem_Ipsum.htm") compFile = os.path.join(refDir, "guiBuild_Tool_Step2_Lorem_Ipsum.htm") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) assert nwBuild._saveDocument(nwBuild.FMT_MD) projFile = os.path.join(nwLipsum, "Lorem Ipsum.md") testFile = os.path.join(outDir, "guiBuild_Tool_Step2_Lorem_Ipsum.md") compFile = os.path.join(refDir, "guiBuild_Tool_Step2_Lorem_Ipsum.md") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) assert nwBuild._saveDocument(nwBuild.FMT_FODT) projFile = os.path.join(nwLipsum, "Lorem Ipsum.fodt") testFile = os.path.join(outDir, "guiBuild_Tool_Step2_Lorem_Ipsum.fodt") compFile = os.path.join(refDir, "guiBuild_Tool_Step2_Lorem_Ipsum.fodt") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [4, 5]) # Replace Tabs with Spaces qtbot.mouseClick(nwBuild.replaceTabs, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton) # Save files that can be compared assert nwBuild._saveDocument(nwBuild.FMT_NWD) projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd") testFile = os.path.join(outDir, "guiBuild_Tool_Step3_Lorem_Ipsum.nwd") compFile = os.path.join(refDir, "guiBuild_Tool_Step3_Lorem_Ipsum.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) assert nwBuild._saveDocument(nwBuild.FMT_HTM) projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm") testFile = os.path.join(outDir, "guiBuild_Tool_Step3_Lorem_Ipsum.htm") compFile = os.path.join(refDir, "guiBuild_Tool_Step3_Lorem_Ipsum.htm") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) assert nwBuild._saveDocument(nwBuild.FMT_MD) projFile = os.path.join(nwLipsum, "Lorem Ipsum.md") testFile = os.path.join(outDir, "guiBuild_Tool_Step3_Lorem_Ipsum.md") compFile = os.path.join(refDir, "guiBuild_Tool_Step3_Lorem_Ipsum.md") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) assert nwBuild._saveDocument(nwBuild.FMT_FODT) projFile = os.path.join(nwLipsum, "Lorem Ipsum.fodt") testFile = os.path.join(outDir, "guiBuild_Tool_Step3_Lorem_Ipsum.fodt") compFile = os.path.join(refDir, "guiBuild_Tool_Step3_Lorem_Ipsum.fodt") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [4, 5]) # Putline Mode nwBuild.fmtChapter.setText(r"Chapter %chw%: %title%") qtbot.wait(stepDelay) nwBuild.fmtScene.setText(r"Scene %sca%: %title%") qtbot.wait(stepDelay) nwBuild.fmtSection.setText(r"Section: %title%") qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.includeComments, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.noteFiles, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.ignoreFlag, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.includeBody, Qt.LeftButton) qtbot.wait(stepDelay) qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton) # Save files that can be compared assert nwBuild._saveDocument(nwBuild.FMT_NWD) projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd") testFile = os.path.join(outDir, "guiBuild_Tool_Step4_Lorem_Ipsum.nwd") compFile = os.path.join(refDir, "guiBuild_Tool_Step4_Lorem_Ipsum.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) assert nwBuild._saveDocument(nwBuild.FMT_HTM) projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm") testFile = os.path.join(outDir, "guiBuild_Tool_Step4_Lorem_Ipsum.htm") compFile = os.path.join(refDir, "guiBuild_Tool_Step4_Lorem_Ipsum.htm") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) # Check the JSON files too at this stage assert nwBuild._saveDocument(nwBuild.FMT_JSON_H) projFile = os.path.join(nwLipsum, "Lorem Ipsum.json") testFile = os.path.join(outDir, "guiBuild_Tool_Step4H_Lorem_Ipsum.json") compFile = os.path.join(refDir, "guiBuild_Tool_Step4H_Lorem_Ipsum.json") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [8]) assert nwBuild._saveDocument(nwBuild.FMT_JSON_M) projFile = os.path.join(nwLipsum, "Lorem Ipsum.json") testFile = os.path.join(outDir, "guiBuild_Tool_Step4M_Lorem_Ipsum.json") compFile = os.path.join(refDir, "guiBuild_Tool_Step4M_Lorem_Ipsum.json") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [8]) # Since odt and fodt is built by the same code, we don't check the # output. but just that the different format can be written as well assert nwBuild._saveDocument(nwBuild.FMT_ODT) assert os.path.isfile(os.path.join(nwLipsum, "Lorem Ipsum.odt")) # Print to PDF if not nwGUI.mainConf.osDarwin: assert nwBuild._saveDocument(nwBuild.FMT_PDF) assert os.path.isfile(os.path.join(nwLipsum, "Lorem Ipsum.pdf")) # Close the build tool htmlText = nwBuild.htmlText htmlStyle = nwBuild.htmlStyle buildTime = nwBuild.buildTime nwBuild._doClose() # Re-open build dialog from cahce nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger) qtbot.waitUntil(lambda: getGuiItem("GuiBuildNovel") is not None, timeout=1000) nwBuild = getGuiItem("GuiBuildNovel") assert isinstance(nwBuild, GuiBuildNovel) assert nwBuild.viewCachedDoc() assert nwBuild.htmlText == htmlText assert nwBuild.htmlStyle == htmlStyle assert nwBuild.buildTime == buildTime nwBuild._doClose()
def testGuiMergeSplit_Tools(qtbot, monkeypatch, nwGUI, nwLipsum, refDir, outDir): """Test the full merge and split tools. """ # Block message box monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes) nwGUI.theProject.projTree.setSeed(42) assert nwGUI.openProject(nwLipsum) qtbot.wait(stepDelay) assert nwGUI.treeView.setSelectedHandle("45e6b01ca35c1") qtbot.wait(stepDelay) monkeypatch.setattr(GuiDocMerge, "exec_", lambda *args: 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) nwMerge._doMerge() qtbot.wait(stepDelay) assert nwGUI.theProject.projTree["73475cb40a568"] is not None 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) # Split By Chapter assert nwGUI.treeView.setSelectedHandle("73475cb40a568") qtbot.wait(stepDelay) monkeypatch.setattr(GuiDocSplit, "exec_", lambda *args: None) nwGUI.mainMenu.aSplitDoc.activate(QAction.Trigger) qtbot.waitUntil(lambda: getGuiItem("GuiDocSplit") is not None, timeout=1000) nwSplit = getGuiItem("GuiDocSplit") assert isinstance(nwSplit, GuiDocSplit) nwSplit.show() qtbot.wait(stepDelay) nwSplit.splitLevel.setCurrentIndex(1) qtbot.wait(stepDelay) 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) nwSplit.splitLevel.setCurrentIndex(2) qtbot.wait(stepDelay) 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) nwSplit.splitLevel.setCurrentIndex(3) qtbot.wait(stepDelay) nwSplit._doSplit() 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 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]) 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) 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) 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) 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)
def testGuiEditor_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj, refDir, outDir): """Test the document editor. """ # Block message box monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes) monkeypatch.setattr(QMessageBox, "information", lambda *args: QMessageBox.Yes) monkeypatch.setattr(GuiItemEditor, "exec_", lambda *args: None) monkeypatch.setattr(GuiItemEditor, "result", lambda *args: QDialog.Accepted) monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *args: True) monkeypatch.setattr(GuiDocEditor, "hasFocus", lambda *args: True) # Create new, save, close project nwGUI.theProject.projTree.setSeed(42) assert nwGUI.newProject({"projPath": fncProj}) assert nwGUI.saveProject() assert nwGUI.closeProject() assert len(nwGUI.theProject.projTree) == 0 assert len(nwGUI.theProject.projTree._treeOrder) == 0 assert len(nwGUI.theProject.projTree._treeRoots) == 0 assert nwGUI.theProject.projTree.trashRoot() is None assert nwGUI.theProject.projPath is None assert nwGUI.theProject.projMeta is None assert nwGUI.theProject.projFile == "nwProject.nwx" assert nwGUI.theProject.projName == "" assert nwGUI.theProject.bookTitle == "" assert len(nwGUI.theProject.bookAuthors) == 0 assert not nwGUI.theProject.spellCheck # Check the files projFile = os.path.join(fncProj, "nwProject.nwx") testFile = os.path.join(outDir, "guiEditor_Main_Initial_nwProject.nwx") compFile = os.path.join(refDir, "guiEditor_Main_Initial_nwProject.nwx") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [2, 6, 7, 8]) qtbot.wait(stepDelay) # qtbot.stopForInteraction() # Re-open project assert nwGUI.openProject(fncProj) qtbot.wait(stepDelay) # Check that we loaded the data assert len(nwGUI.theProject.projTree) == 8 assert len(nwGUI.theProject.projTree._treeOrder) == 8 assert len(nwGUI.theProject.projTree._treeRoots) == 4 assert nwGUI.theProject.projTree.trashRoot() is None assert nwGUI.theProject.projPath == fncProj assert nwGUI.theProject.projMeta == os.path.join(fncProj, "meta") assert nwGUI.theProject.projFile == "nwProject.nwx" assert nwGUI.theProject.projName == "New Project" assert nwGUI.theProject.bookTitle == "" assert len(nwGUI.theProject.bookAuthors) == 0 assert not nwGUI.theProject.spellCheck # Check that tree items have been created assert nwGUI.treeView._getTreeItem("73475cb40a568") is not None assert nwGUI.treeView._getTreeItem("25fc0e7096fc6") is not None assert nwGUI.treeView._getTreeItem("31489056e0916") is not None assert nwGUI.treeView._getTreeItem("98010bd9270f9") is not None assert nwGUI.treeView._getTreeItem("0e17daca5f3e1") is not None assert nwGUI.treeView._getTreeItem("44cb730c42048") is not None assert nwGUI.treeView._getTreeItem("71ee45a3c0db9") is not None assert nwGUI.treeView._getTreeItem("811786ad1ae74") is not None nwGUI.mainMenu.aSpellCheck.setChecked(True) assert nwGUI.mainMenu._toggleSpellCheck() # Change some settings nwGUI.mainConf.hideHScroll = True nwGUI.mainConf.hideVScroll = True nwGUI.mainConf.scrollPastEnd = True nwGUI.mainConf.autoScrollPos = 80 nwGUI.mainConf.autoScroll = True # Add a Character File nwGUI.switchFocus(nwWidget.TREE) nwGUI.treeView.clearSelection() nwGUI.treeView._getTreeItem("71ee45a3c0db9").setSelected(True) nwGUI.treeView.newTreeItem(nwItemType.FILE, None) assert nwGUI.openSelectedItem() # Type something into the document nwGUI.switchFocus(nwWidget.EDITOR) qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay) for c in "# Jane Doe": 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 "@tag: Jane": 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 a file about Jane.": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) # Add a Plot File nwGUI.switchFocus(nwWidget.TREE) nwGUI.treeView.clearSelection() nwGUI.treeView._getTreeItem("44cb730c42048").setSelected(True) nwGUI.treeView.newTreeItem(nwItemType.FILE, None) assert nwGUI.openSelectedItem() # Type something into the document nwGUI.switchFocus(nwWidget.EDITOR) qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay) for c in "# Main Plot": 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 "@tag: MainPlot": 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 a file detailing the main plot.": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) # Add a World File nwGUI.switchFocus(nwWidget.TREE) nwGUI.treeView.clearSelection() nwGUI.treeView._getTreeItem("811786ad1ae74").setSelected(True) nwGUI.treeView.newTreeItem(nwItemType.FILE, None) assert nwGUI.openSelectedItem() # Add Some Text nwGUI.docEditor.replaceText("Hello World!") assert nwGUI.docEditor.getText() == "Hello World!" nwGUI.docEditor.replaceText("") # Type something into the document nwGUI.switchFocus(nwWidget.EDITOR) qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay) for c in "# Main Location": 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 "@tag: Home": 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 a file describing Jane's home.": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) # Trigger autosaves before making more changes nwGUI._autoSaveDocument() nwGUI._autoSaveProject() # Select the 'New Scene' file nwGUI.switchFocus(nwWidget.TREE) nwGUI.treeView.clearSelection() nwGUI.treeView._getTreeItem("73475cb40a568").setExpanded(True) nwGUI.treeView._getTreeItem("31489056e0916").setExpanded(True) nwGUI.treeView._getTreeItem("0e17daca5f3e1").setSelected(True) assert nwGUI.openSelectedItem() # Type something into the document nwGUI.switchFocus(nwWidget.EDITOR) qtbot.keyClick(nwGUI.docEditor, "a", modifier=Qt.ControlModifier, delay=keyDelay) for c in "# Novel": 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 "## Chapter": 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 "@pov: Jane": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@plot: MainPlot": 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 "### Scene": 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 "% How about a comment?": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@pov: Jane": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@plot: MainPlot": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@location: Home": 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 "#### Some Section": 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 "@char: Jane": 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 a paragraph of dummy 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! "): qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) for c in "We can also try replacing \"quotes\", even single 'quotes' are replaced. ": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) for c in "Isn't that nice? ": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) for c in "We can hyphen-ate, make dashes -- and even longer dashes --- if we want. ": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) for c in "Ellipsis? Not a problem either ... ": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) for c in "How about three hyphens - -": qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Left, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Backspace, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Right, delay=keyDelay) for c in "- for long dash? It works too.": 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 "\"Full line double quoted 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 "'Full line single quoted 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) qtbot.wait(stepDelay) nwGUI.docEditor.wCounter.run() qtbot.wait(stepDelay) # Save the document assert nwGUI.docEditor.docChanged assert nwGUI.saveDocument() assert not nwGUI.docEditor.docChanged qtbot.wait(stepDelay) nwGUI.rebuildIndex() qtbot.wait(stepDelay) # Open and view the edited document nwGUI.switchFocus(nwWidget.VIEWER) assert nwGUI.openDocument("0e17daca5f3e1") assert nwGUI.viewDocument("0e17daca5f3e1") qtbot.wait(stepDelay) assert nwGUI.saveProject() assert nwGUI.closeDocViewer() qtbot.wait(stepDelay) # Check a Quick Create and Delete assert nwGUI.treeView.newTreeItem(nwItemType.FILE, None) newHandle = nwGUI.treeView.getSelectedHandle() assert nwGUI.theProject.projTree["2858dcd1057d3"] is not None assert nwGUI.treeView.deleteItem() assert nwGUI.treeView.setSelectedHandle(newHandle) assert nwGUI.treeView.deleteItem() assert nwGUI.theProject.projTree["2fca346db6561"] is not None # Trash assert nwGUI.saveProject() # Check the files projFile = os.path.join(fncProj, "nwProject.nwx") testFile = os.path.join(outDir, "guiEditor_Main_Final_nwProject.nwx") compFile = os.path.join(refDir, "guiEditor_Main_Final_nwProject.nwx") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile, [2, 6, 7, 8]) projFile = os.path.join(fncProj, "content", "031b4af5197ec.nwd") testFile = os.path.join(outDir, "guiEditor_Main_Final_031b4af5197ec.nwd") compFile = os.path.join(refDir, "guiEditor_Main_Final_031b4af5197ec.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) projFile = os.path.join(fncProj, "content", "1a6562590ef19.nwd") testFile = os.path.join(outDir, "guiEditor_Main_Final_1a6562590ef19.nwd") compFile = os.path.join(refDir, "guiEditor_Main_Final_1a6562590ef19.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) projFile = os.path.join(fncProj, "content", "0e17daca5f3e1.nwd") testFile = os.path.join(outDir, "guiEditor_Main_Final_0e17daca5f3e1.nwd") compFile = os.path.join(refDir, "guiEditor_Main_Final_0e17daca5f3e1.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) projFile = os.path.join(fncProj, "content", "41cfc0d1f2d12.nwd") testFile = os.path.join(outDir, "guiEditor_Main_Final_41cfc0d1f2d12.nwd") compFile = os.path.join(refDir, "guiEditor_Main_Final_41cfc0d1f2d12.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, compFile)
def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir, filesDir): """Test config intialisation. """ tstConf = Config() confFile = os.path.join(tmpDir, "novelwriter.conf") testFile = os.path.join(outDir, "baseConfig_novelwriter.conf") compFile = os.path.join(refDir, "baseConfig_novelwriter.conf") # Make sure we don't have any old conf file if os.path.isfile(confFile): os.unlink(confFile) # Let the config class figure out the path with monkeypatch.context() as mp: mp.setattr("PyQt5.QtCore.QStandardPaths.writableLocation", lambda *args: fncDir) tstConf.verQtValue = 50600 tstConf.initConfig() assert tstConf.confPath == os.path.join(fncDir, tstConf.appHandle) assert tstConf.dataPath == os.path.join(fncDir, tstConf.appHandle) assert not os.path.isfile(confFile) tstConf.verQtValue = 50000 tstConf.initConfig() assert tstConf.confPath == os.path.join(fncDir, tstConf.appHandle) assert tstConf.dataPath == os.path.join(fncDir, tstConf.appHandle) assert not os.path.isfile(confFile) # Fail to make folders with monkeypatch.context() as mp: mp.setattr("os.mkdir", causeOSError) tstConfDir = os.path.join(fncDir, "test_conf") tstConf.initConfig(confPath=tstConfDir, dataPath=tmpDir) assert tstConf.confPath is None assert tstConf.dataPath == tmpDir assert not os.path.isfile(confFile) tstDataDir = os.path.join(fncDir, "test_data") tstConf.initConfig(confPath=tmpDir, dataPath=tstDataDir) assert tstConf.confPath == tmpDir assert tstConf.dataPath is None assert os.path.isfile(confFile) os.unlink(confFile) # Test load/save with no path tstConf.confPath = None assert not tstConf.loadConfig() assert not tstConf.saveConfig() # Run again and set the paths directly and correctly # This should create a config file as well with monkeypatch.context() as mp: mp.setattr("os.path.expanduser", lambda *args: "") tstConf.spellTool = nwConst.SP_INTERNAL tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir) assert tstConf.confPath == tmpDir assert tstConf.dataPath == tmpDir assert os.path.isfile(confFile) copyfile(confFile, testFile) assert cmpFiles(testFile, compFile, [2, 9, 10]) # Load and save with OSError with monkeypatch.context() as mp: mp.setattr("builtins.open", causeOSError) assert not tstConf.loadConfig() assert tstConf.hasError is True assert tstConf.errData != [] assert tstConf.getErrData().startswith("Could not") assert tstConf.hasError is False assert tstConf.errData == [] assert not tstConf.saveConfig() assert tstConf.hasError is True assert tstConf.errData != [] assert tstConf.getErrData().startswith("Could not") assert tstConf.hasError is False assert tstConf.errData == [] assert tstConf.loadConfig() assert tstConf.saveConfig() # Test Correcting Quote Settings origDbl = tstConf.fmtDoubleQuotes origSng = tstConf.fmtSingleQuotes orDoDbl = tstConf.doReplaceDQuote orDoSng = tstConf.doReplaceSQuote tstConf.fmtDoubleQuotes = ["\"", "\""] tstConf.fmtSingleQuotes = ["'", "'"] tstConf.doReplaceDQuote = True tstConf.doReplaceSQuote = True assert tstConf.saveConfig() assert tstConf.loadConfig() assert not tstConf.doReplaceDQuote assert not tstConf.doReplaceSQuote tstConf.fmtDoubleQuotes = origDbl tstConf.fmtSingleQuotes = origSng tstConf.doReplaceDQuote = orDoDbl tstConf.doReplaceSQuote = orDoSng assert tstConf.saveConfig() # Localisation i18nDir = os.path.join(fncDir, "i18n") os.mkdir(i18nDir) os.mkdir(os.path.join(i18nDir, "stuff")) tstConf.nwLangPath = i18nDir copyfile(os.path.join(filesDir, "nw_en_GB.qm"), os.path.join(fncDir, "nw_en_GB.qm")) writeFile(os.path.join(i18nDir, "nw_en_GB.ts"), "") writeFile(os.path.join(i18nDir, "nw_abcd.qm"), "") tstApp = DummyApp() tstConf.initLocalisation(tstApp) theList = tstConf.listLanguages(tstConf.LANG_NW) assert theList == [("en_GB", "British English")] copyfile(confFile, testFile) assert cmpFiles(testFile, compFile, [2, 9, 10])
def testCoreIndex_LoadSave(monkeypatch, nwLipsum, mockGUI, outDir, refDir): """Test core functionality of scaning, saving, loading and checking the index cache file. """ projFile = os.path.join(nwLipsum, "meta", "tagsIndex.json") testFile = os.path.join(outDir, "coreIndex_LoadSave_tagsIndex.json") compFile = os.path.join(refDir, "coreIndex_LoadSave_tagsIndex.json") theProject = NWProject(mockGUI) assert theProject.openProject(nwLipsum) theIndex = NWIndex(theProject) assert repr(theIndex) == "<NWIndex project='Lorem Ipsum'>" notIndexable = { "b3643d0f92e32": False, # Novel ROOT "45e6b01ca35c1": False, # Chapter One FOLDER "6bd935d2490cd": False, # Chapter Two FOLDER "67a8707f2f249": False, # Character ROOT "6c6afb1247750": False, # Plot ROOT "60bdf227455cc": False, # World ROOT } for tItem in theProject.tree: assert theIndex.reIndexHandle(tItem.itemHandle) is notIndexable.get( tItem.itemHandle, True) assert theIndex.reIndexHandle(None) is False # Make the save fail with monkeypatch.context() as mp: mp.setattr("builtins.open", causeException) assert theIndex.saveIndex() is False # Make the save pass assert theIndex.saveIndex() is True # Take a copy of the index tagIndex = str(theIndex._tagsIndex.packData()) itemsIndex = str(theIndex._itemIndex.packData()) # Delete a handle assert theIndex._tagsIndex["Bod"] is not None assert theIndex._itemIndex["4c4f28287af27"] is not None theIndex.deleteHandle("4c4f28287af27") assert theIndex._tagsIndex["Bod"] is None assert theIndex._itemIndex["4c4f28287af27"] is None # Clear the index theIndex.clearIndex() assert theIndex._tagsIndex._tags == {} assert theIndex._itemIndex._items == {} # Make the load fail with monkeypatch.context() as mp: mp.setattr(json, "load", causeException) assert theIndex.loadIndex() is False assert theIndex.indexBroken is True # Make the load pass assert theIndex.loadIndex() is True assert theIndex.indexBroken is False assert str(theIndex._tagsIndex.packData()) == tagIndex assert str(theIndex._itemIndex.packData()) == itemsIndex # Check File copyfile(projFile, testFile) assert cmpFiles(testFile, compFile) # Write an emtpy index file and load it writeFile(projFile, "{}") assert theIndex.loadIndex() is False assert theIndex.indexBroken is True # Write an index file that passes loading, but is still empty writeFile(projFile, '{"tagsIndex": {}, "itemIndex": {}}') assert theIndex.loadIndex() is True assert theIndex.indexBroken is False # Check that the index is re-populated assert "04468803b92e1" in theIndex._itemIndex assert "2426c6f0ca922" in theIndex._itemIndex assert "441420a886d82" in theIndex._itemIndex assert "47666c91c7ccf" in theIndex._itemIndex assert "4c4f28287af27" in theIndex._itemIndex assert "846352075de7d" in theIndex._itemIndex assert "88243afbe5ed8" in theIndex._itemIndex assert "88d59a277361b" in theIndex._itemIndex assert "8c58a65414c23" in theIndex._itemIndex assert "db7e733775d4d" in theIndex._itemIndex assert "eb103bc70c90c" in theIndex._itemIndex assert "f8c0562e50f1b" in theIndex._itemIndex assert "f96ec11c6a3da" in theIndex._itemIndex assert "fb609cd8319dc" in theIndex._itemIndex assert "7a992350f3eb6" in theIndex._itemIndex # Finalise assert theProject.closeProject() is True