def testBaseInit_Launch(caplog, monkeypatch, tmpDir): """Check launching the main GUI. """ monkeypatch.setattr("nw.guimain.GuiMain", DummyMain) # Testmode launch nwGUI = nw.main( ["--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir] ) assert isinstance(nwGUI, DummyMain) # Darwin launch monkeypatch.setitem(sys.modules, "Foundation", None) osDarwin = nw.CONFIG.osDarwin nw.CONFIG.osDarwin = True nwGUI = nw.main( ["--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir] ) assert isinstance(nwGUI, DummyMain) assert "Foundation" in caplog.messages[1] nw.CONFIG.osDarwin = osDarwin # Normal launch monkeypatch.setattr("PyQt5.QtWidgets.QApplication.__init__", lambda *args: None) monkeypatch.setattr("PyQt5.QtWidgets.QApplication.setApplicationName", lambda *args: None) monkeypatch.setattr("PyQt5.QtWidgets.QApplication.setApplicationVersion", lambda *args: None) monkeypatch.setattr("PyQt5.QtWidgets.QApplication.setWindowIcon", lambda *args: None) monkeypatch.setattr("PyQt5.QtWidgets.QApplication.setOrganizationDomain", lambda *args: None) monkeypatch.setattr("PyQt5.QtWidgets.QApplication.exec_", lambda *args: 0) with pytest.raises(SystemExit) as ex: nw.main(["--config=%s" % tmpDir, "--data=%s" % tmpDir]) assert ex.value.code == 0
def testAboutBox(qtbot, monkeypatch, nwFuncTemp, nwTemp): nwGUI = nw.main(["--testmode", "--config=%s" % nwFuncTemp, "--data=%s" % nwTemp]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(stepDelay) # NW About monkeypatch.setattr(GuiAbout, "exec_", lambda *args: None) nwGUI.mainMenu.aAboutNW.activate(QAction.Trigger) qtbot.waitUntil(lambda: getGuiItem("GuiAbout") is not None, timeout=1000) msgAbout = getGuiItem("GuiAbout") assert isinstance(msgAbout, GuiAbout) msgAbout.show() assert msgAbout.pageAbout.document().characterCount() > 100 assert msgAbout.pageLicense.document().characterCount() > 100 msgAbout.mainConf.guiLang = "whatever" msgAbout._fillLicensePage() assert msgAbout.pageLicense.toPlainText() == "Error loading license text ..." # Qt About monkeypatch.setattr(QMessageBox, "aboutQt", lambda *args, **kwargs: None) nwGUI.mainMenu.aAboutQt.activate(QAction.Trigger) # qtbot.stopForInteraction() msgAbout._doClose() nwGUI.closeMain()
def testQuotesDialog(qtbot, yesToAll, nwMinimal, nwTemp): nwGUI = nw.main(["--testmode", "--config=%s" % nwMinimal, "--data=%s" % nwTemp, nwMinimal]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(stepDelay) nwQuot = QuotesDialog(nwGUI) nwQuot.show() lastItem = "" for i in range(nwQuot.listBox.count()): anItem = nwQuot.listBox.item(i) assert isinstance(anItem, QListWidgetItem) nwQuot.listBox.clearSelection() nwQuot.listBox.setCurrentItem(anItem, QItemSelectionModel.Select) lastItem = anItem.text()[2] assert nwQuot.previewLabel.text() == lastItem nwQuot._doAccept() assert nwQuot.result() == QDialog.Accepted assert nwQuot.selectedQuote == lastItem # qtbot.stopForInteraction() nwQuot._doReject() nwQuot.close() nwGUI.closeMain() nwGUI.close()
def testBaseInit_Imports(caplog, monkeypatch, tmpDir): """Check import error handling. """ monkeypatch.setattr("nw.guimain.GuiMain", DummyMain) monkeypatch.setattr("PyQt5.QtWidgets.QApplication.__init__", lambda *args: None) monkeypatch.setattr("PyQt5.QtWidgets.QApplication.exec_", lambda *args: 0) monkeypatch.setattr("PyQt5.QtWidgets.QErrorMessage.__init__", lambda *args: None) monkeypatch.setattr("PyQt5.QtWidgets.QErrorMessage.resize", lambda *args: None) monkeypatch.setattr("PyQt5.QtWidgets.QErrorMessage.showMessage", lambda *args: None) monkeypatch.setitem(sys.modules, "lxml", None) monkeypatch.setattr("sys.hexversion", 0x0) monkeypatch.setattr("nw.CONFIG.verQtValue", 50000) monkeypatch.setattr("nw.CONFIG.verPyQtValue", 50000) with pytest.raises(SystemExit) as ex: _ = nw.main( ["--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir]) assert ex.value.code & 4 == 4 # Python version not satisfied assert ex.value.code & 8 == 8 # Qt version not satisfied assert ex.value.code & 16 == 16 # PyQt version not satisfied assert ex.value.code & 32 == 32 # lxml package missing assert "At least Python" in caplog.messages[0] assert "At least Qt5" in caplog.messages[1] assert "At least PyQt5" in caplog.messages[2] assert "lxml" in caplog.messages[3] monkeypatch.undo()
def testDialogsOpenClose(qtbot, monkeypatch, yesToAll, nwMinimal, nwTemp): nwGUI = nw.main(["--testmode", "--config=%s" % nwMinimal, "--data=%s" % nwTemp, nwMinimal]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(stepDelay) monkeypatch.setattr(QFileDialog, "getExistingDirectory", lambda *args, **kwargs: nwTemp) assert nwGUI.selectProjectPath() == nwTemp # qtbot.stopForInteraction() nwGUI.closeMain() nwGUI.close()
def nwGUI(qtbot, monkeypatch, fncDir, fncConf): """Create an instance of the novelWriter GUI. """ monkeypatch.setattr("nw.CONFIG", fncConf) nwGUI = nw.main(["--testmode", "--config=%s" % fncDir, "--data=%s" % fncDir]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(20) nwGUI.mainConf.lastPath = fncDir yield nwGUI qtbot.wait(20) nwGUI.closeMain() qtbot.wait(20) return
def testItemEditor(qtbot, nwTempGUI, nwRef): nwGUI = nw.main(["--testmode", "--config=%s" % nwTempGUI]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(stepDelay) # Create new, save, open project nwGUI.theProject.handleSeed = 42 assert nwGUI.newProject(nwTempGUI, True) itemEdit = GuiItemEditor(nwGUI, nwGUI.theProject, "31489056e0916") 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=keyDelay) itemEdit.editStatus.setCurrentIndex(1) layoutIdx = itemEdit.editLayout.findData(nwItemLayout.PAGE) itemEdit.editLayout.setCurrentIndex(layoutIdx) qtbot.mouseClick(itemEdit.saveButton, Qt.LeftButton) itemEdit = GuiItemEditor(nwGUI, nwGUI.theProject, "31489056e0916") qtbot.addWidget(itemEdit) assert itemEdit.editName.text() == "Just a Page" assert itemEdit.editStatus.currentData() == "Note" assert itemEdit.editLayout.currentData() == nwItemLayout.PAGE qtbot.mouseClick(itemEdit.closeButton, Qt.LeftButton) qtbot.wait(stepDelay) assert nwGUI.saveProject() qtbot.wait(stepDelay) # Check the files projFile = path.join(nwTempGUI, "nwProject.nwx") assert cmpFiles(projFile, path.join(nwRef, "gui", "3_nwProject.nwx"), [2]) nwGUI.closeMain()
def testBaseError_Handler(qtbot, monkeypatch, fncDir, tmpDir): """Test the error handler. This test doesn'thave any asserts, but it checks that the error handler handles potential exceptions. The test will fail if excpetions are not handled. """ qApp.closeAllWindows() nwGUI = nw.main( ["--testmode", "--config=%s" % fncDir, "--data=%s" % tmpDir]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) # Normal shutdown monkeypatch.setattr(NWErrorMessage, "exec_", lambda *args: None) monkeypatch.setattr("PyQt5.QtWidgets.qApp.exit", lambda *args: None) exceptionHandler(Exception, "Error Message", None) monkeypatch.undo() # Should not crash when no GUI is found monkeypatch.setattr(NWErrorMessage, "exec_", lambda *args: None) monkeypatch.setattr("PyQt5.QtWidgets.qApp.exit", lambda *args: None) monkeypatch.setattr("PyQt5.QtWidgets.qApp.topLevelWidgets", lambda: []) exceptionHandler(Exception, "Error Message", None) monkeypatch.undo() # Should handle qApp failing monkeypatch.setattr(NWErrorMessage, "exec_", lambda *args: None) monkeypatch.setattr("PyQt5.QtWidgets.qApp.exit", lambda *args: None) monkeypatch.setattr("PyQt5.QtWidgets.qApp.topLevelWidgets", causeException) exceptionHandler(Exception, "Error Message", None) monkeypatch.undo() # Should handle failing to close main GUI monkeypatch.setattr(NWErrorMessage, "exec_", lambda *args: None) monkeypatch.setattr("PyQt5.QtWidgets.qApp.exit", lambda *args: None) monkeypatch.setattr(nwGUI, "closeMain", causeException) exceptionHandler(Exception, "Error Message", None) monkeypatch.undo() nwGUI.closeMain()
def testTimeLineView(qtbot, nwTempGUI, nwRef): nwGUI = nw.main(["--testmode", "--config=%s" % nwTempGUI]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(stepDelay) # Create new, save, open project nwGUI.theProject.handleSeed = 42 assert nwGUI.openProject(nwTempGUI) qtbot.wait(stepDelay) timeLine = GuiTimeLineView(nwGUI, nwGUI.theProject, nwGUI.theIndex) qtbot.addWidget(timeLine) assert timeLine.numRows == 4 assert timeLine.numCols == 3 # qtbot.stopForInteraction() nwGUI.closeMain()
def testBaseError_Dialog(qtbot, monkeypatch, fncDir, tmpDir): """Test the error dialog. """ qApp.closeAllWindows() nwGUI = nw.main( ["--testmode", "--config=%s" % fncDir, "--data=%s" % tmpDir]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) nwErr = NWErrorMessage(nwGUI) qtbot.addWidget(nwErr) nwErr.show() # Invalid Error Message nwErr.setMessage(Exception, "Faulty Error", 123) assert nwErr.msgBody.toPlainText() == "Failed to generate error report ..." # Valid Error Message monkeypatch.setattr("PyQt5.QtCore.QSysInfo.kernelVersion", lambda: "1.2.3") nwErr.setMessage(Exception, "Fine Error", None) theMessage = nwErr.msgBody.toPlainText() assert theMessage assert "Fine Error" in theMessage assert "Exception" in theMessage assert "(1.2.3)" in theMessage monkeypatch.undo() # No kernel version retrieved monkeypatch.setattr("PyQt5.QtCore.QSysInfo.kernelVersion", causeException) nwErr.setMessage(Exception, "Almost Fine Error", None) theMessage = nwErr.msgBody.toPlainText() assert theMessage assert "(Unknown)" in theMessage monkeypatch.undo() nwErr._doClose() nwErr.close() nwGUI.closeMain()
def testErrorDialog(qtbot, nwFuncTemp, nwTemp): qApp.closeAllWindows() nwGUI = nw.main( ["--testmode", "--config=%s" % nwFuncTemp, "--data=%s" % nwTemp]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) nwErr = NWErrorMessage(nwGUI) qtbot.addWidget(nwErr) nwErr.show() # Invalid Error nwErr.setMessage(Exception, "Faulty Error", 123) assert nwErr.msgBody.toPlainText() == "Failed to generate error report ..." # Valid Error nwErr.setMessage(Exception, "First Error", None) theMessage = nwErr.msgBody.toPlainText() assert theMessage assert "First Error" in theMessage assert "Exception" in theMessage nwErr._doClose() nwErr.close() theMessage = exceptionHandler(Exception, "Second Error", None, testMode=True) assert theMessage assert "Second Error" in theMessage assert "Exception" in theMessage nwGUI.closeMain()
def testLoadProject(qtbot, monkeypatch, yesToAll, nwMinimal, nwTemp): nwGUI = nw.main(["--testmode", "--config=%s" % nwMinimal, "--data=%s" % nwTemp]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(stepDelay) assert nwGUI.openProject(nwMinimal) assert nwGUI.closeProject() qtbot.wait(stepDelay) monkeypatch.setattr(GuiProjectLoad, "exec_", lambda *args: None) monkeypatch.setattr(GuiProjectLoad, "result", lambda *args: QDialog.Accepted) nwGUI.mainMenu.aOpenProject.activate(QAction.Trigger) qtbot.waitUntil(lambda: getGuiItem("GuiProjectLoad") is not None, timeout=1000) nwLoad = getGuiItem("GuiProjectLoad") assert isinstance(nwLoad, GuiProjectLoad) nwLoad.show() qtbot.wait(stepDelay) recentCount = nwLoad.listBox.topLevelItemCount() assert recentCount > 0 qtbot.wait(stepDelay) selItem = nwLoad.listBox.topLevelItem(0) selPath = selItem.data(nwLoad.C_NAME, Qt.UserRole) assert isinstance(selItem, QTreeWidgetItem) qtbot.wait(stepDelay) nwLoad.selPath.setText("") nwLoad.listBox.setCurrentItem(selItem) nwLoad._doSelectRecent() assert nwLoad.selPath.text() == selPath qtbot.wait(stepDelay) qtbot.mouseClick(nwLoad.buttonBox.button(QDialogButtonBox.Open), Qt.LeftButton) assert nwLoad.openPath == selPath assert nwLoad.openState == nwLoad.OPEN_STATE # Just create a new project load from scratch for the rest of the test del nwLoad qtbot.wait(stepDelay) nwGUI.mainMenu.aOpenProject.activate(QAction.Trigger) qtbot.waitUntil(lambda: getGuiItem("GuiProjectLoad") is not None, timeout=1000) qtbot.wait(stepDelay) nwLoad = getGuiItem("GuiProjectLoad") assert isinstance(nwLoad, GuiProjectLoad) nwLoad.show() qtbot.wait(stepDelay) qtbot.mouseClick(nwLoad.buttonBox.button(QDialogButtonBox.Cancel), Qt.LeftButton) assert nwLoad.openPath is None assert nwLoad.openState == nwLoad.NONE_STATE qtbot.wait(stepDelay) nwLoad.show() qtbot.mouseClick(nwLoad.newButton, Qt.LeftButton) assert nwLoad.openPath is None assert nwLoad.openState == nwLoad.NEW_STATE qtbot.wait(stepDelay) nwLoad.show() nwLoad._keyPressDelete() assert nwLoad.listBox.topLevelItemCount() == recentCount - 1 getFile = os.path.join(nwMinimal, "nwProject.nwx") monkeypatch.setattr(QFileDialog, "getOpenFileName", lambda *args, **kwargs: (getFile, None)) qtbot.mouseClick(nwLoad.browseButton, Qt.LeftButton) assert nwLoad.openPath == nwMinimal assert nwLoad.openState == nwLoad.OPEN_STATE # qtbot.stopForInteraction() nwLoad.close() nwGUI.closeMain() nwGUI.close()
def testNewProjectWizard(qtbot, monkeypatch, yesToAll, nwMinimal, nwTemp): if sys.platform.startswith("darwin"): # Disable for macOS because the test segfaults on QWizard.show() return from PyQt5.QtWidgets import QWizard from nw.gui.projwizard import ( ProjWizardIntroPage, ProjWizardFolderPage, ProjWizardPopulatePage, ProjWizardCustomPage, ProjWizardFinalPage ) nwGUI = nw.main(["--testmode", "--config=%s" % nwTemp, "--data=%s" % nwTemp]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(stepDelay) ## # Test New Project Function ## # New with a project open should cause an error assert nwGUI.openProject(nwMinimal) assert not nwGUI.newProject() # Close project, but call with invalid path assert nwGUI.closeProject() monkeypatch.setattr(nwGUI, "showNewProjectDialog", lambda *args: None) assert not nwGUI.newProject() # Now, with an empty dictionary monkeypatch.setattr(nwGUI, "showNewProjectDialog", lambda *args: {}) assert not nwGUI.newProject() # Now, with a non-empty folder monkeypatch.setattr(nwGUI, "showNewProjectDialog", lambda *args: {"projPath": nwMinimal}) assert not nwGUI.newProject() monkeypatch.undo() ## # Test the Wizard ## monkeypatch.setattr(GuiProjectWizard, "exec_", lambda *args: None) nwGUI.mainConf.lastPath = " " nwGUI.closeProject() nwGUI.showNewProjectDialog() qtbot.waitUntil(lambda: getGuiItem("GuiProjectWizard") is not None, timeout=1000) nwWiz = getGuiItem("GuiProjectWizard") assert isinstance(nwWiz, GuiProjectWizard) nwWiz.show() qtbot.wait(stepDelay) for wStep in range(4): # This does not actually create the project, it just generates the # dictionary that defines it. # Intro Page introPage = nwWiz.currentPage() assert isinstance(introPage, ProjWizardIntroPage) assert not nwWiz.button(QWizard.NextButton).isEnabled() qtbot.wait(stepDelay) for c in ("Test Minimal %d" % wStep): qtbot.keyClick(introPage.projName, c, delay=typeDelay) qtbot.wait(stepDelay) for c in "Minimal Novel": qtbot.keyClick(introPage.projTitle, c, delay=typeDelay) qtbot.wait(stepDelay) for c in "Jane Doe": qtbot.keyClick(introPage.projAuthors, c, delay=typeDelay) # Setting projName should activate the button assert nwWiz.button(QWizard.NextButton).isEnabled() qtbot.wait(stepDelay) qtbot.mouseClick(nwWiz.button(QWizard.NextButton), Qt.LeftButton) # Folder Page storagePage = nwWiz.currentPage() assert isinstance(storagePage, ProjWizardFolderPage) assert not nwWiz.button(QWizard.NextButton).isEnabled() if wStep == 0: # Check invalid path first, the first time we reach here monkeypatch.setattr(QFileDialog, "getExistingDirectory", lambda *a, **kw: "") qtbot.wait(stepDelay) qtbot.mouseClick(storagePage.browseButton, Qt.LeftButton, delay=100) assert storagePage.projPath.text() == "" # Then, we always return nwMinimal as path monkeypatch.setattr(QFileDialog, "getExistingDirectory", lambda *a, **kw: nwMinimal) qtbot.wait(stepDelay) qtbot.mouseClick(storagePage.browseButton, Qt.LeftButton, delay=100) projPath = os.path.join(nwMinimal, "Test Minimal %d" % wStep) assert storagePage.projPath.text() == projPath # Setting projPath should activate the button assert nwWiz.button(QWizard.NextButton).isEnabled() qtbot.wait(stepDelay) qtbot.mouseClick(nwWiz.button(QWizard.NextButton), Qt.LeftButton) # Populate Page popPage = nwWiz.currentPage() assert isinstance(popPage, ProjWizardPopulatePage) assert nwWiz.button(QWizard.NextButton).isEnabled() qtbot.wait(stepDelay) if wStep == 0: popPage.popMinimal.setChecked(True) elif wStep == 1: popPage.popCustom.setChecked(True) elif wStep == 2: popPage.popCustom.setChecked(True) elif wStep == 3: popPage.popSample.setChecked(True) qtbot.wait(stepDelay) qtbot.mouseClick(nwWiz.button(QWizard.NextButton), Qt.LeftButton) # Custom Page if wStep == 1 or wStep == 2: customPage = nwWiz.currentPage() assert isinstance(customPage, ProjWizardCustomPage) assert nwWiz.button(QWizard.NextButton).isEnabled() customPage.addPlot.setChecked(True) customPage.addChar.setChecked(True) customPage.addWorld.setChecked(True) customPage.addTime.setChecked(True) customPage.addObject.setChecked(True) customPage.addEntity.setChecked(True) if wStep == 2: customPage.numChapters.setValue(0) customPage.numScenes.setValue(10) customPage.chFolders.setChecked(False) qtbot.wait(stepDelay) qtbot.mouseClick(nwWiz.button(QWizard.NextButton), Qt.LeftButton) # Final Page finalPage = nwWiz.currentPage() assert isinstance(finalPage, ProjWizardFinalPage) assert nwWiz.button(QWizard.FinishButton).isEnabled() # But we don't click it # Check Data projData = nwGUI._assembleProjectWizardData(nwWiz) assert projData["projName"] == "Test Minimal %d" % wStep assert projData["projTitle"] == "Minimal Novel" assert projData["projAuthors"] == "Jane Doe" assert projData["projPath"] == projPath assert projData["popMinimal"] == (wStep == 0) assert projData["popCustom"] == (wStep == 1 or wStep == 2) assert projData["popSample"] == (wStep == 3) if wStep == 1 or wStep == 2: assert projData["addRoots"] == [ nwItemClass.PLOT, nwItemClass.CHARACTER, nwItemClass.WORLD, nwItemClass.TIMELINE, nwItemClass.OBJECT, nwItemClass.ENTITY, ] if wStep == 1: assert projData["numChapters"] == 5 assert projData["numScenes"] == 5 assert projData["chFolders"] else: assert projData["numChapters"] == 0 assert projData["numScenes"] == 10 assert not projData["chFolders"] else: assert projData["addRoots"] == [] assert projData["numChapters"] == 0 assert projData["numScenes"] == 0 assert not projData["chFolders"] # Restart the wizard for next iteration nwWiz.restart() nwWiz.reject() nwWiz.close() # qtbot.stopForInteraction() nwGUI.closeMain() nwGUI.close()
def testMergeSplitTools(qtbot, monkeypatch, yesToAll, nwTempGUI, nwLipsum, nwRef, nwTemp): nwGUI = nw.main(["--testmode", "--config=%s" % nwLipsum, "--data=%s" % nwTemp]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(stepDelay) 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(nwTempGUI, "4_73475cb40a568.nwd") refFile = os.path.join(nwRef, "gui", "4_73475cb40a568.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile) # 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(nwTempGUI, "4_71ee45a3c0db9.nwd") refFile = os.path.join(nwRef, "gui", "4_73475cb40a568.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile, [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(nwTempGUI, "5_25fc0e7096fc6.nwd") refFile = os.path.join(nwRef, "gui", "5_25fc0e7096fc6.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile) projFile = os.path.join(nwLipsum, "content", "31489056e0916.nwd") testFile = os.path.join(nwTempGUI, "5_31489056e0916.nwd") refFile = os.path.join(nwRef, "gui", "5_31489056e0916.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile) projFile = os.path.join(nwLipsum, "content", "98010bd9270f9.nwd") testFile = os.path.join(nwTempGUI, "5_98010bd9270f9.nwd") refFile = os.path.join(nwRef, "gui", "5_98010bd9270f9.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile) # 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(nwTempGUI, "5_25fc0e7096fc6.nwd") refFile = os.path.join(nwRef, "gui", "5_25fc0e7096fc6.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile, [1, 2, 3]) projFile = os.path.join(nwLipsum, "content", "031b4af5197ec.nwd") testFile = os.path.join(nwTempGUI, "5_031b4af5197ec.nwd") refFile = os.path.join(nwRef, "gui", "5_031b4af5197ec.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile) projFile = os.path.join(nwLipsum, "content", "41cfc0d1f2d12.nwd") testFile = os.path.join(nwTempGUI, "5_41cfc0d1f2d12.nwd") refFile = os.path.join(nwRef, "gui", "5_41cfc0d1f2d12.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile) projFile = os.path.join(nwLipsum, "content", "2858dcd1057d3.nwd") testFile = os.path.join(nwTempGUI, "5_2858dcd1057d3.nwd") refFile = os.path.join(nwRef, "gui", "5_2858dcd1057d3.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile) projFile = os.path.join(nwLipsum, "content", "2fca346db6561.nwd") testFile = os.path.join(nwTempGUI, "5_2fca346db6561.nwd") refFile = os.path.join(nwRef, "gui", "5_2fca346db6561.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile) # qtbot.stopForInteraction() nwGUI.closeMain()
def testBuildTool(qtbot, yesToAll, nwTempBuild, nwLipsum, nwRef, nwTemp): nwGUI = nw.main(["--testmode", "--config=%s" % nwLipsum, "--data=%s" % nwTemp]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(stepDelay) # 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(nwTempBuild, "1_LoremIpsum.nwd") refFile = os.path.join(nwRef, "build", "1_LoremIpsum.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile) projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm") testFile = os.path.join(nwTempBuild, "1_LoremIpsum.htm") refFile = os.path.join(nwRef, "build", "1_LoremIpsum.htm") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile) # 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(nwTempBuild, "2_LoremIpsum.nwd") refFile = os.path.join(nwRef, "build", "2_LoremIpsum.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile) projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm") testFile = os.path.join(nwTempBuild, "2_LoremIpsum.htm") refFile = os.path.join(nwRef, "build", "2_LoremIpsum.htm") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile) # 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(nwTempBuild, "3_LoremIpsum.nwd") refFile = os.path.join(nwRef, "build", "3_LoremIpsum.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile) assert nwBuild._saveDocument(nwBuild.FMT_HTM) projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm") testFile = os.path.join(nwTempBuild, "3_LoremIpsum.htm") refFile = os.path.join(nwRef, "build", "3_LoremIpsum.htm") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile) # 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(nwTempBuild, "4_LoremIpsum.nwd") refFile = os.path.join(nwRef, "build", "4_LoremIpsum.nwd") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile) assert nwBuild._saveDocument(nwBuild.FMT_HTM) projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm") testFile = os.path.join(nwTempBuild, "4_LoremIpsum.htm") refFile = os.path.join(nwRef, "build", "4_LoremIpsum.htm") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile) # 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(nwTempBuild, "4H_LoremIpsum.json") refFile = os.path.join(nwRef, "build", "4H_LoremIpsum.json") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile, [8]) assert nwBuild._saveDocument(nwBuild.FMT_JSON_M) projFile = os.path.join(nwLipsum, "Lorem Ipsum.json") testFile = os.path.join(nwTempBuild, "4M_LoremIpsum.json") refFile = os.path.join(nwRef, "build", "4M_LoremIpsum.json") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile, [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() # qtbot.stopForInteraction() nwGUI.closeMain()
except: print("ERROR: Failed to load dependency python3-pyqt5.qtsvg") exit(1) try: import lxml except: print("ERROR: Failed to load dependency python3-lxml") exit(1) try: import appdirs except: print("ERROR: Failed to load dependency python3-appdirs") exit(1) spellPack = None try: import enchant spellPack = "enchant" except: print("WARNING: No spell check library found.") print("Please install python3-enchant if you want to use spell checking") if __name__ == "__main__": import nw inArgs = sys.argv[1:] if spellPack is not None: inArgs.append("--spell=%s" % spellPack) nw.main(inArgs)
def testItemEditor(qtbot, yesToAll, monkeypatch, nwFuncTemp, nwTempGUI, nwRef, nwTemp): nwGUI = nw.main(["--testmode", "--config=%s" % nwTemp, "--data=%s" % nwTemp]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(stepDelay) # Create new, save, open project nwGUI.theProject.projTree.setSeed(42) assert nwGUI.newProject({"projPath": nwFuncTemp}) 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 projFile = os.path.join(nwFuncTemp, "nwProject.nwx") testFile = os.path.join(nwTempGUI, "3_nwProject.nwx") refFile = os.path.join(nwRef, "gui", "3_nwProject.nwx") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile, [2, 6, 7, 8]) # qtbot.stopForInteraction() nwGUI.closeMain()
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ novelWriter – Start Script ========================== """ import os import sys try: import PyQt5.QtWidgets # noqa: F401 import PyQt5.QtGui # noqa: F401 import PyQt5.QtCore # noqa: F401 except Exception: print("ERROR: Failed to load dependency PyQt5") sys.exit(1) os.curdir = os.path.abspath(os.path.dirname(__file__)) if __name__ == "__main__": import nw nw.main(sys.argv[1:])
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 testPreferences(qtbot, monkeypatch, yesToAll, nwMinimal, nwTemp, nwRef, tmpConf): nwGUI = nw.main(["--testmode", "--config=%s" % nwMinimal, "--data=%s" % nwTemp]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(stepDelay) assert nwGUI.openProject(nwMinimal) 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() # Override Config tmpConf.confPath = nwMinimal tmpConf.showGUI = False nwGUI.mainConf = tmpConf nwPrefs.mainConf = tmpConf nwPrefs.tabGeneral.mainConf = tmpConf nwPrefs.tabProjects.mainConf = tmpConf nwPrefs.tabLayout.mainConf = tmpConf nwPrefs.tabEditing.mainConf = tmpConf nwPrefs.tabAutoRep.mainConf = tmpConf # 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 tabLayout.textJustify.isChecked() qtbot.mouseClick(tabLayout.textJustify, Qt.LeftButton) assert not 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) assert tmpConf.confChanged tmpConf.lastPath = "" assert nwGUI.mainConf.saveConfig() # qtbot.stopForInteraction() nwGUI.closeMain() refConf = os.path.join(nwRef, "novelwriter_prefs.conf") projConf = os.path.join(nwGUI.mainConf.confPath, "novelwriter.conf") testConf = os.path.join(nwTemp, "novelwriter_prefs.conf") copyfile(projConf, testConf) ignoreLines = [ 2, # Timestamp 11, 12, 13, 14, 15, 16, 17, # Window sizes 7, 27, # Fonts (depends on system default) ] assert cmpFiles(testConf, refConf, ignoreLines)
def testGuiTheme_Main(qtbot, monkeypatch, nwMinimal, tmpDir): """Test the theme and icon classes. """ # Block message box monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes) nwGUI = nw.main([ "--testmode", "--config=%s" % nwMinimal, "--data=%s" % tmpDir, nwMinimal ]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(500) # Change Settings assert nw.CONFIG.confPath == nwMinimal nw.CONFIG.guiTheme = "default_dark" nw.CONFIG.guiSyntax = "tomorrow_night_eighties" nw.CONFIG.guiIcons = "typicons_colour_dark" nw.CONFIG.guiDark = True nw.CONFIG.guiFont = "Cantarell" nw.CONFIG.guiFontSize = 11 nw.CONFIG.confChanged = True assert nw.CONFIG.saveConfig() nwGUI.closeMain() nwGUI.close() del nwGUI # Re-open assert nw.CONFIG.confPath == nwMinimal nwGUI = nw.main([ "--testmode", "--config=%s" % nwMinimal, "--data=%s" % tmpDir, nwMinimal ]) assert nwGUI.mainConf.confPath == nwMinimal qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(500) assert nw.CONFIG.guiTheme == "default_dark" assert nw.CONFIG.guiSyntax == "tomorrow_night_eighties" assert nw.CONFIG.guiIcons == "typicons_colour_dark" assert nw.CONFIG.guiDark is True assert nw.CONFIG.guiFont == "Cantarell" assert nw.CONFIG.guiFontSize == 11 # Check GUI Colours thePalette = nwGUI.palette() assert thePalette.window().color() == QColor(54, 54, 54) assert thePalette.windowText().color() == QColor(174, 174, 174) assert thePalette.base().color() == QColor(62, 62, 62) assert thePalette.alternateBase().color() == QColor(67, 67, 67) assert thePalette.text().color() == QColor(174, 174, 174) assert thePalette.toolTipBase().color() == QColor(255, 255, 192) assert thePalette.toolTipText().color() == QColor(21, 21, 13) assert thePalette.button().color() == QColor(62, 62, 62) assert thePalette.buttonText().color() == QColor(174, 174, 174) assert thePalette.brightText().color() == QColor(174, 174, 174) assert thePalette.highlight().color() == QColor(44, 152, 247) assert thePalette.highlightedText().color() == QColor(255, 255, 255) assert thePalette.link().color() == QColor(44, 152, 247) assert thePalette.linkVisited().color() == QColor(44, 152, 247) assert nwGUI.theTheme.statNone == [150, 152, 150] assert nwGUI.theTheme.statSaved == [39, 135, 78] assert nwGUI.theTheme.statUnsaved == [138, 32, 32] # Check Syntax Colours assert nwGUI.theTheme.colBack == [45, 45, 45] assert nwGUI.theTheme.colText == [204, 204, 204] assert nwGUI.theTheme.colLink == [102, 153, 204] assert nwGUI.theTheme.colHead == [102, 153, 204] assert nwGUI.theTheme.colHeadH == [102, 153, 204] assert nwGUI.theTheme.colEmph == [249, 145, 57] assert nwGUI.theTheme.colDialN == [242, 119, 122] assert nwGUI.theTheme.colDialD == [153, 204, 153] assert nwGUI.theTheme.colDialS == [255, 204, 102] assert nwGUI.theTheme.colHidden == [153, 153, 153] assert nwGUI.theTheme.colKey == [242, 119, 122] assert nwGUI.theTheme.colVal == [204, 153, 204] assert nwGUI.theTheme.colSpell == [242, 119, 122] assert nwGUI.theTheme.colTagErr == [153, 204, 153] assert nwGUI.theTheme.colRepTag == [102, 204, 204] assert nwGUI.theTheme.colMod == [249, 145, 57] # Test Icon class theIcons = nwGUI.theTheme.theIcons nw.CONFIG.guiIcons = "invalid" assert not theIcons.updateTheme() nw.CONFIG.guiIcons = "typicons_colour_dark" assert theIcons.updateTheme() # Ask for a non-existent key anImg = theIcons.loadDecoration("nonsense", 20, 20) assert isinstance(anImg, QPixmap) assert anImg.isNull() # Add a non-existent file and request it theIcons.DECO_MAP["nonsense"] = "nofile.jpg" anImg = theIcons.loadDecoration("nonsense", 20, 20) assert isinstance(anImg, QPixmap) assert anImg.isNull() # Get a real image, with different size parameters anImg = theIcons.loadDecoration("wiz-back", 20, None) assert isinstance(anImg, QPixmap) assert not anImg.isNull() assert anImg.width() == 20 assert anImg.height() >= 56 anImg = theIcons.loadDecoration("wiz-back", None, 70) assert isinstance(anImg, QPixmap) assert not anImg.isNull() assert anImg.height() == 70 assert anImg.width() >= 24 anImg = theIcons.loadDecoration("wiz-back", 30, 70) assert isinstance(anImg, QPixmap) assert not anImg.isNull() assert anImg.height() == 70 assert anImg.width() == 30 anImg = theIcons.loadDecoration("wiz-back", None, None) assert isinstance(anImg, QPixmap) assert not anImg.isNull() assert anImg.height() >= 1500 assert anImg.width() >= 500 # Load icons anIcon = theIcons.getIcon("nonsense") assert isinstance(anIcon, QIcon) assert anIcon.isNull() anIcon = theIcons.getIcon("novelwriter") assert isinstance(anIcon, QIcon) assert not anIcon.isNull() # Add dummy icons and test alternative load paths theIcons.ICON_MAP["testicon1"] = (QStyle.SP_DriveHDIcon, None) anIcon = theIcons.getIcon("testicon1") assert isinstance(anIcon, QIcon) assert not anIcon.isNull() theIcons.ICON_MAP["testicon2"] = (None, "folder") anIcon = theIcons.getIcon("testicon2") assert isinstance(anIcon, QIcon) theIcons.ICON_MAP["testicon3"] = (None, None) anIcon = theIcons.getIcon("testicon3") assert isinstance(anIcon, QIcon) assert anIcon.isNull() # qtbot.stopForInteraction() nwGUI.closeMain() nwGUI.close()
def testProjectEditor(qtbot, nwTempGUI, nwRef): nwGUI = nw.main(["--testmode", "--config=%s" % nwTempGUI]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(stepDelay) # Create new, save, open project nwGUI.theProject.handleSeed = 42 assert nwGUI.newProject(nwTempGUI, True) nwGUI.mainConf.backupPath = nwTempGUI projEdit = GuiProjectEditor(nwGUI, nwGUI.theProject) qtbot.addWidget(projEdit) for c in "Project Name": qtbot.keyClick(projEdit.tabMain.editName, c, delay=keyDelay) for c in "Project Title": qtbot.keyClick(projEdit.tabMain.editTitle, c, delay=keyDelay) for c in "Jane Doe": qtbot.keyClick(projEdit.tabMain.editAuthors, c, delay=keyDelay) qtbot.keyClick(projEdit.tabMain.editAuthors, Qt.Key_Return, delay=keyDelay) for c in "John Doh": qtbot.keyClick(projEdit.tabMain.editAuthors, c, delay=keyDelay) # Test Status Tab projEdit.tabWidget.setCurrentWidget(projEdit.tabStatus) projEdit.tabStatus.listBox.item(2).setSelected(True) qtbot.mouseClick(projEdit.tabStatus.delButton, Qt.LeftButton) qtbot.mouseClick(projEdit.tabStatus.newButton, Qt.LeftButton) projEdit.tabStatus.listBox.item(3).setSelected(True) for n in range(8): qtbot.keyClick(projEdit.tabStatus.editName, Qt.Key_Backspace, delay=keyDelay) for c in "Final": qtbot.keyClick(projEdit.tabStatus.editName, c, delay=keyDelay) qtbot.mouseClick(projEdit.tabStatus.saveButton, Qt.LeftButton) # Auto-Replace Tab projEdit.tabWidget.setCurrentWidget(projEdit.tabReplace) qtbot.mouseClick(projEdit.tabReplace.addButton, Qt.LeftButton) projEdit.tabReplace.listBox.topLevelItem(0).setSelected(True) for c in "Th is ": qtbot.keyClick(projEdit.tabReplace.editKey, c, delay=keyDelay) for c in "With This Stuff ": qtbot.keyClick(projEdit.tabReplace.editValue, c, delay=keyDelay) qtbot.mouseClick(projEdit.tabReplace.saveButton, Qt.LeftButton) projEdit.tabReplace.listBox.clearSelection() qtbot.mouseClick(projEdit.tabReplace.addButton, Qt.LeftButton) projEdit.tabReplace.listBox.topLevelItem(0).setSelected(True) for c in "Delete": qtbot.keyClick(projEdit.tabReplace.editKey, c, delay=keyDelay) for c in "This Stuff": qtbot.keyClick(projEdit.tabReplace.editValue, c, delay=keyDelay) qtbot.mouseClick(projEdit.tabReplace.saveButton, Qt.LeftButton) projEdit.tabReplace.listBox.clearSelection() projEdit.tabReplace.listBox.topLevelItem(0).setSelected(True) qtbot.mouseClick(projEdit.tabReplace.delButton, Qt.LeftButton) projEdit._doSave() # Open again, and check project settings projEdit = GuiProjectEditor(nwGUI, nwGUI.theProject) 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 projFile = path.join(nwTempGUI, "nwProject.nwx") assert cmpFiles(projFile, path.join(nwRef, "gui", "2_nwProject.nwx"), [2]) nwGUI.closeMain()
def testBaseInit_Options(monkeypatch, tmpDir): """Test command line options for logging level. """ monkeypatch.setattr("nw.guimain.GuiMain", DummyMain) monkeypatch.setattr(sys, "argv", [ "novelWriter.py", "--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir ]) # Defaults w/None Args nwGUI = nw.main() assert nw.logger.getEffectiveLevel() == logging.WARNING assert nw.CONFIG.debugInfo is False assert nwGUI.closeMain() == "closeMain" # Defaults nwGUI = nw.main([ "--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir, "--style=Fusion" ]) assert nw.logger.getEffectiveLevel() == logging.WARNING assert nw.CONFIG.debugInfo is False assert nwGUI.closeMain() == "closeMain" # Log Levels nwGUI = nw.main( ["--testmode", "--info", "--config=%s" % tmpDir, "--data=%s" % tmpDir]) assert nw.logger.getEffectiveLevel() == logging.INFO assert nw.CONFIG.debugInfo is False assert nwGUI.closeMain() == "closeMain" nwGUI = nw.main([ "--testmode", "--debug", "--config=%s" % tmpDir, "--data=%s" % tmpDir ]) assert nw.logger.getEffectiveLevel() == logging.DEBUG assert nw.CONFIG.debugInfo is True assert nwGUI.closeMain() == "closeMain" nwGUI = nw.main([ "--testmode", "--verbose", "--config=%s" % tmpDir, "--data=%s" % tmpDir ]) assert nw.logger.getEffectiveLevel() == 5 assert nw.CONFIG.debugInfo is True assert nwGUI.closeMain() == "closeMain" # Help and Version with pytest.raises(SystemExit) as ex: nwGUI = nw.main([ "--testmode", "--help", "--config=%s" % tmpDir, "--data=%s" % tmpDir ]) assert nwGUI.closeMain() == "closeMain" assert ex.value.code == 0 with pytest.raises(SystemExit) as ex: nwGUI = nw.main([ "--testmode", "--version", "--config=%s" % tmpDir, "--data=%s" % tmpDir ]) assert nwGUI.closeMain() == "closeMain" assert ex.value.code == 0 # Invalid options with pytest.raises(SystemExit) as ex: nwGUI = nw.main([ "--testmode", "--invalid", "--config=%s" % tmpDir, "--data=%s" % tmpDir ]) assert nwGUI.closeMain() == "closeMain" assert ex.value.code == 2 # Project Path nwGUI = nw.main([ "--testmode", "--config=%s" % tmpDir, "--data=%s" % tmpDir, "sample/" ]) assert nw.CONFIG.cmdOpen == "sample/" assert nwGUI.closeMain() == "closeMain" monkeypatch.undo()
def testWritingStatsExport(qtbot, monkeypatch, yesToAll, nwFuncTemp, nwTemp): nwGUI = nw.main(["--testmode", "--config=%s" % nwTemp, "--data=%s" % nwTemp]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(stepDelay) # Create new, save, close project nwGUI.theProject.projTree.setSeed(42) assert nwGUI.newProject({"projPath": nwFuncTemp}) qtbot.wait(200) assert nwGUI.saveProject() assert nwGUI.closeProject() qtbot.wait(stepDelay) sessFile = os.path.join(nwFuncTemp, "meta", nwFiles.SESS_STATS) with open(sessFile, mode="w+", encoding="utf-8") as outFile: outFile.write( "# Start Time End Time Novel Notes\n" "2020-01-01 21:00:00 2020-01-01 21:00:05 6 0\n" "2020-01-03 21:00:00 2020-01-03 21:00:15 125 0\n" "2020-01-03 21:30:00 2020-01-03 21:30:15 125 5\n" "2020-01-06 21:00:00 2020-01-06 21:00:10 125 5\n" ) # Open again, and check the stats assert nwGUI.openProject(nwFuncTemp) qtbot.wait(stepDelay) nwGUI.mainConf.lastPath = nwFuncTemp nwGUI.mainMenu.aWritingStats.activate(QAction.Trigger) qtbot.waitUntil(lambda: getGuiItem("GuiWritingStats") is not None, timeout=1000) sessLog = getGuiItem("GuiWritingStats") assert isinstance(sessLog, GuiWritingStats) qtbot.wait(stepDelay) monkeypatch.setattr(QFileDialog, "getSaveFileName", lambda *args, **kwargs: ("", "")) assert not sessLog._saveData(sessLog.FMT_CSV) monkeypatch.setattr(QFileDialog, "getSaveFileName", lambda ss, tt, pp, options: (pp, "")) assert sessLog._saveData(sessLog.FMT_CSV) qtbot.wait(100) assert sessLog._saveData(sessLog.FMT_JSON) qtbot.wait(100) jsonStats = os.path.join(nwFuncTemp, "sessionStats.json") with open(jsonStats, mode="r", encoding="utf-8") as inFile: jsonData = json.load(inFile) qtbot.wait(stepDelay) assert len(jsonData) == 3 assert jsonData[1]["length"] >= 14.0 assert jsonData[1]["newWords"] == 119 assert jsonData[1]["novelWords"] == 125 assert jsonData[1]["noteWords"] == 0 # No Novel Files qtbot.mouseClick(sessLog.incNovel, Qt.LeftButton) qtbot.wait(stepDelay) assert sessLog._saveData(sessLog.FMT_JSON) qtbot.wait(stepDelay) jsonStats = os.path.join(nwFuncTemp, "sessionStats.json") with open(jsonStats, mode="r", encoding="utf-8") as inFile: jsonData = json.loads(inFile.read()) assert len(jsonData) == 1 assert jsonData[0]["length"] >= 14.0 assert jsonData[0]["newWords"] == 5 assert jsonData[0]["novelWords"] == 125 assert jsonData[0]["noteWords"] == 5 # No Note Files qtbot.mouseClick(sessLog.incNovel, Qt.LeftButton) qtbot.mouseClick(sessLog.incNotes, Qt.LeftButton) qtbot.wait(stepDelay) assert sessLog._saveData(sessLog.FMT_JSON) qtbot.wait(stepDelay) jsonStats = os.path.join(nwFuncTemp, "sessionStats.json") with open(jsonStats, mode="r", encoding="utf-8") as inFile: jsonData = json.load(inFile) assert len(jsonData) == 2 assert jsonData[1]["length"] >= 14.0 assert jsonData[1]["newWords"] == 119 assert jsonData[1]["novelWords"] == 125 assert jsonData[1]["noteWords"] == 0 # No Negative Entries qtbot.mouseClick(sessLog.incNotes, Qt.LeftButton) qtbot.mouseClick(sessLog.hideNegative, Qt.LeftButton) qtbot.wait(stepDelay) assert sessLog._saveData(sessLog.FMT_JSON) qtbot.wait(stepDelay) jsonStats = os.path.join(nwFuncTemp, "sessionStats.json") with open(jsonStats, mode="r", encoding="utf-8") as inFile: jsonData = json.load(inFile) assert len(jsonData) == 3 # Un-hide Zero Entries qtbot.mouseClick(sessLog.hideNegative, Qt.LeftButton) qtbot.mouseClick(sessLog.hideZeros, Qt.LeftButton) qtbot.wait(stepDelay) assert sessLog._saveData(sessLog.FMT_JSON) qtbot.wait(stepDelay) jsonStats = os.path.join(nwFuncTemp, "sessionStats.json") with open(jsonStats, mode="r", encoding="utf-8") as inFile: jsonData = json.load(inFile) assert len(jsonData) == 4 # Group by Day qtbot.mouseClick(sessLog.groupByDay, Qt.LeftButton) qtbot.wait(stepDelay) assert sessLog._saveData(sessLog.FMT_JSON) qtbot.wait(stepDelay) jsonStats = os.path.join(nwFuncTemp, "sessionStats.json") with open(jsonStats, mode="r", encoding="utf-8") as inFile: jsonData = json.load(inFile) # Check against both 1 and 2 as this can be 2 if test was started just before midnight. # A failed test should in any case produce a 4 assert len(jsonData) == 3 # qtbot.stopForInteraction() sessLog._doClose() assert nwGUI.closeProject() qtbot.wait(stepDelay) nwGUI.closeMain()
def testProjectSettings(qtbot, monkeypatch, yesToAll, nwFuncTemp, nwTempGUI, nwRef, nwTemp): nwGUI = nw.main(["--testmode", "--config=%s" % nwTemp, "--data=%s" % nwTemp]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(stepDelay) # 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": nwFuncTemp}) nwGUI.mainConf.backupPath = nwFuncTemp # 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) # Main settings 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) 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) # Test Status Tab qtbot.wait(stepDelay) projEdit._tabBox.setCurrentWidget(projEdit.tabStatus) projEdit.tabStatus.listBox.item(2).setSelected(True) qtbot.mouseClick(projEdit.tabStatus.delButton, Qt.LeftButton) qtbot.mouseClick(projEdit.tabStatus.newButton, Qt.LeftButton) projEdit.tabStatus.listBox.item(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.saveButton, Qt.LeftButton) # Auto-Replace Tab qtbot.wait(stepDelay) projEdit._tabBox.setCurrentWidget(projEdit.tabReplace) qtbot.mouseClick(projEdit.tabReplace.addButton, Qt.LeftButton) projEdit.tabReplace.listBox.topLevelItem(0).setSelected(True) for c in "Th is ": qtbot.keyClick(projEdit.tabReplace.editKey, c, delay=typeDelay) 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() 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) == "<keyword2>": 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) 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 projFile = os.path.join(nwFuncTemp, "nwProject.nwx") testFile = os.path.join(nwTempGUI, "2_nwProject.nwx") refFile = os.path.join(nwRef, "gui", "2_nwProject.nwx") copyfile(projFile, testFile) assert cmpFiles(testFile, refFile, [2, 8, 9, 10]) # qtbot.stopForInteraction() nwGUI.closeMain()
def testMainWindows(qtbot, nwTempGUI, nwRef): nwGUI = nw.main(["--testmode", "--config=%s" % nwTempGUI]) qtbot.addWidget(nwGUI) nwGUI.show() qtbot.waitForWindowShown(nwGUI) qtbot.wait(stepDelay) # Create new, save, close project nwGUI.theProject.handleSeed = 42 assert nwGUI.newProject(nwTempGUI, True) assert nwGUI.saveProject() assert nwGUI.closeProject() assert len(nwGUI.theProject.projTree) == 0 assert len(nwGUI.theProject.treeOrder) == 0 assert len(nwGUI.theProject.treeRoots) == 0 assert nwGUI.theProject.trashRoot is None assert nwGUI.theProject.projPath is None assert nwGUI.theProject.projMeta is None assert nwGUI.theProject.projCache is None assert nwGUI.theProject.projFile == "nwProject.nwx" assert nwGUI.theProject.projName == "" assert nwGUI.theProject.bookTitle == "" assert len(nwGUI.theProject.bookAuthors) == 0 assert nwGUI.theProject.spellCheck == False # Check the files projFile = path.join(nwTempGUI, "nwProject.nwx") assert cmpFiles(projFile, path.join(nwRef, "gui", "0_nwProject.nwx"), [2]) qtbot.wait(stepDelay) # qtbot.stopForInteraction() # Re-open project assert nwGUI.openProject(nwTempGUI) qtbot.wait(stepDelay) # Check that we loaded the data assert len(nwGUI.theProject.projTree) == 6 assert len(nwGUI.theProject.treeOrder) == 6 assert len(nwGUI.theProject.treeRoots) == 4 assert nwGUI.theProject.trashRoot is None assert nwGUI.theProject.projPath == nwTempGUI assert nwGUI.theProject.projMeta == path.join(nwTempGUI, "meta") assert nwGUI.theProject.projCache == path.join(nwTempGUI, "cache") assert nwGUI.theProject.projFile == "nwProject.nwx" assert nwGUI.theProject.projName == "" assert nwGUI.theProject.bookTitle == "" assert len(nwGUI.theProject.bookAuthors) == 0 assert nwGUI.theProject.spellCheck == False # 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("44cb730c42048") is not None assert nwGUI.treeView._getTreeItem("71ee45a3c0db9") is not None assert nwGUI.treeView._getTreeItem("811786ad1ae74") is not None nwGUI.mainMenu.toolsSpellCheck.setChecked(True) assert nwGUI.mainMenu._toggleSpellCheck() # Add a Character File nwGUI.setFocus(1) nwGUI.treeView.clearSelection() nwGUI.treeView._getTreeItem("44cb730c42048").setSelected(True) nwGUI.treeView.newTreeItem(nwItemType.FILE, None) assert nwGUI.openSelectedItem() # Type something into the document nwGUI.setFocus(2) for c in "# Jane Doe": qtbot.keyClick(nwGUI.docEditor, c, delay=keyDelay) 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=keyDelay) 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=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) # Add a Plot File nwGUI.setFocus(1) nwGUI.treeView.clearSelection() nwGUI.treeView._getTreeItem("71ee45a3c0db9").setSelected(True) nwGUI.treeView.newTreeItem(nwItemType.FILE, None) assert nwGUI.openSelectedItem() # Type something into the document nwGUI.setFocus(2) for c in "# Main Plot": qtbot.keyClick(nwGUI.docEditor, c, delay=keyDelay) 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=keyDelay) 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=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) # Add a World File nwGUI.setFocus(1) nwGUI.treeView.clearSelection() nwGUI.treeView._getTreeItem("811786ad1ae74").setSelected(True) nwGUI.treeView.newTreeItem(nwItemType.FILE, None) assert nwGUI.openSelectedItem() # Type something into the document nwGUI.setFocus(2) for c in "# Main Location": qtbot.keyClick(nwGUI.docEditor, c, delay=keyDelay) 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=keyDelay) 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=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) # Select the 'New Scene' file nwGUI.setFocus(1) nwGUI.treeView.clearSelection() nwGUI.treeView._getTreeItem("73475cb40a568").setExpanded(True) nwGUI.treeView._getTreeItem("25fc0e7096fc6").setExpanded(True) nwGUI.treeView._getTreeItem("31489056e0916").setSelected(True) assert nwGUI.openSelectedItem() # Type something into the document nwGUI.setFocus(2) for c in "# Novel": qtbot.keyClick(nwGUI.docEditor, c, delay=keyDelay) 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=keyDelay) 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=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@plot: MainPlot": qtbot.keyClick(nwGUI.docEditor, c, delay=keyDelay) 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=keyDelay) 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=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@pov: Jane": qtbot.keyClick(nwGUI.docEditor, c, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@plot: MainPlot": qtbot.keyClick(nwGUI.docEditor, c, delay=keyDelay) qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay) for c in "@location: Home": qtbot.keyClick(nwGUI.docEditor, c, delay=keyDelay) 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=keyDelay) 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=keyDelay) 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=keyDelay) 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 very very dumb dummy text! ": qtbot.keyClick(nwGUI.docEditor, c, delay=keyDelay) for c in "We can also try replacing \"quotes\", even single's quotes are replaced. ": qtbot.keyClick(nwGUI.docEditor, c, delay=keyDelay) for c in "We can hyphen-ate, make dashes -- and even longer dashes --- if we want. ": qtbot.keyClick(nwGUI.docEditor, c, delay=keyDelay) for c in "Ellipsis? Not a problem either ... ": qtbot.keyClick(nwGUI.docEditor, c, delay=keyDelay) 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.setFocus(3) assert nwGUI.openDocument("31489056e0916") assert nwGUI.viewDocument("31489056e0916") qtbot.wait(stepDelay) assert nwGUI.saveProject() assert nwGUI.closeDocViewer() qtbot.wait(stepDelay) # Check the files refFile = path.join(nwTempGUI, "nwProject.nwx") assert cmpFiles(refFile, path.join(nwRef, "gui", "1_nwProject.nwx"), [2]) refFile = path.join(nwTempGUI, "data_0", "2d20bbd7e394_main.nwd") assert cmpFiles(refFile, path.join(nwRef, "gui", "1_2d20bbd7e394_main.nwd")) refFile = path.join(nwTempGUI, "data_2", "fca346db6561_main.nwd") assert cmpFiles(refFile, path.join(nwRef, "gui", "1_fca346db6561_main.nwd")) refFile = path.join(nwTempGUI, "data_3", "1489056e0916_main.nwd") assert cmpFiles(refFile, path.join(nwRef, "gui", "1_1489056e0916_main.nwd")) refFile = path.join(nwTempGUI, "data_7", "688b6ef52555_main.nwd") assert cmpFiles(refFile, path.join(nwRef, "gui", "1_688b6ef52555_main.nwd")) if sys.version_info[0] >= 3 and sys.version_info[1] >= 6: refFile = path.join(nwTempGUI, "meta", "tagsIndex.json") assert cmpFiles(refFile, path.join(nwRef, "gui", "1_tagsIndex.json")) nwGUI.closeMain()