def testConfigSetPanePos(tmpConf, nwTemp, nwRef): refConf = os.path.join(nwRef, "novelwriter.conf") testConf = os.path.join(tmpConf.confPath, "novelwriter.conf") assert tmpConf.confPath == nwTemp tmpConf.guiScale = 2.0 assert tmpConf.setMainPanePos([200, 700]) assert tmpConf.mainPanePos == [100, 350] assert tmpConf.getMainPanePos() == [200, 700] assert tmpConf.setDocPanePos([300, 300]) assert tmpConf.docPanePos == [150, 150] assert tmpConf.getDocPanePos() == [300, 300] assert tmpConf.setViewPanePos([400, 250]) assert tmpConf.viewPanePos == [200, 125] assert tmpConf.getViewPanePos() == [400, 250] assert tmpConf.setOutlinePanePos([400, 250]) assert tmpConf.outlnPanePos == [200, 125] assert tmpConf.getOutlinePanePos() == [400, 250] tmpConf.guiScale = 1.0 assert tmpConf.setMainPanePos([300, 800]) assert tmpConf.setDocPanePos([400, 400]) assert tmpConf.setViewPanePos([500, 150]) assert tmpConf.setOutlinePanePos([500, 150]) assert tmpConf.confChanged assert tmpConf.saveConfig() assert cmpFiles(testConf, refConf, [2]) assert not tmpConf.confChanged
def testProjectNewFile(nwFuncTemp, nwTempProj, nwRef, nwDummy): """Check that new files can be added to the project. """ projFile = os.path.join(nwFuncTemp, "nwProject.nwx") testFile = os.path.join(nwTempProj, "3_nwProject.nwx") refFile = os.path.join(nwRef, "proj", "3_nwProject.nwx") theProject = NWProject(nwDummy) theProject.projTree.setSeed(42) assert theProject.newProject({"projPath": nwFuncTemp}) assert theProject.setProjectPath(nwFuncTemp) 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, refFile, [2, 6, 7, 8]) assert not theProject.projChanged
def testProjectNewRoot(nwFuncTemp, nwTempProj, nwRef, nwDummy): """Check that new root folders can be added to the project. """ projFile = os.path.join(nwFuncTemp, "nwProject.nwx") testFile = os.path.join(nwTempProj, "2_nwProject.nwx") refFile = os.path.join(nwRef, "proj", "2_nwProject.nwx") theProject = NWProject(nwDummy) theProject.projTree.setSeed(42) assert theProject.newProject({"projPath": nwFuncTemp}) assert theProject.setProjectPath(nwFuncTemp) 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, refFile, [2, 6, 7, 8]) assert not theProject.projChanged
def testProjectNewOpenSave(nwFuncTemp, nwTempProj, nwRef, nwTemp, nwDummy): """Test that a basic project can be created, and opened and saved. """ projFile = os.path.join(nwFuncTemp, "nwProject.nwx") testFile = os.path.join(nwTempProj, "1_nwProject.nwx") refFile = os.path.join(nwRef, "proj", "1_nwProject.nwx") theProject = NWProject(nwDummy) theProject.projTree.setSeed(42) # Setting no data should fail assert not theProject.newProject({}) # Try again with a proper path assert theProject.newProject({"projPath": nwFuncTemp}) assert theProject.setProjectPath(nwFuncTemp) assert theProject.saveProject() assert theProject.closeProject() # Creating the project once more should fail assert not theProject.newProject({"projPath": nwFuncTemp}) # Check the new project copyfile(projFile, testFile) assert cmpFiles(testFile, refFile, [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, refFile, [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, refFile, [2, 6, 7, 8])
def testConfigCore(tmpConf, nwTemp, nwRef): refConf = os.path.join(nwRef, "novelwriter.conf") testConf = os.path.join(tmpConf.confPath, "novelwriter.conf") assert tmpConf.confPath == nwTemp assert tmpConf.saveConfig() assert cmpFiles(testConf, refConf, [2]) assert not tmpConf.confChanged assert tmpConf.loadConfig() assert not tmpConf.confChanged
def testConfigSetWinSize(tmpConf, nwTemp, nwRef): refConf = os.path.join(nwRef, "novelwriter.conf") testConf = os.path.join(tmpConf.confPath, "novelwriter.conf") tmpConf.guiScale = 1.0 assert tmpConf.confPath == nwTemp assert tmpConf.setWinSize(1105, 655) assert not tmpConf.confChanged assert tmpConf.setWinSize(70, 70) assert tmpConf.confChanged assert tmpConf.setWinSize(1100, 650) assert tmpConf.saveConfig() assert cmpFiles(testConf, refConf, [2]) assert not tmpConf.confChanged
def testProjectBackup(nwDummy, nwMinimal, nwTemp): """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(nwDummy) assert theProject.openProject(nwMinimal) # Test faulty settings # Invalid path theProject.mainConf.backupPath = None assert not theProject.zipIt(doNotify=False) # Missing project name theProject.mainConf.backupPath = nwTemp theProject.projName = "" assert not theProject.zipIt(doNotify=False) # Non-existent folder theProject.mainConf.backupPath = os.path.join(nwTemp, "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) # Test correct settings theProject.mainConf.backupPath = nwTemp assert theProject.zipIt(doNotify=False) theFiles = os.listdir(os.path.join(nwTemp, "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(nwTemp, "Test Minimal", theZip), "r") as inZip: inZip.extractall(os.path.join(nwTemp, "extract")) # Check that the main project file was restored assert cmpFiles( os.path.join(nwMinimal, "nwProject.nwx"), os.path.join(nwTemp, "extract", "nwProject.nwx") )
def testConfigSetTreeColWidths(tmpConf, nwTemp, nwRef): refConf = os.path.join(nwRef, "novelwriter.conf") testConf = os.path.join(tmpConf.confPath, "novelwriter.conf") assert tmpConf.confPath == nwTemp tmpConf.guiScale = 1.0 assert tmpConf.setTreeColWidths([10, 20, 30]) assert tmpConf.treeColWidth == [10, 20, 30] assert tmpConf.setTreeColWidths([120, 30, 50]) assert tmpConf.setProjColWidths([10, 20, 30]) assert tmpConf.projColWidth == [10, 20, 30] assert tmpConf.setProjColWidths([140, 55, 140]) assert tmpConf.confChanged assert tmpConf.saveConfig() assert cmpFiles(testConf, refConf, [2]) assert not tmpConf.confChanged
def testConfigFlags(tmpConf, nwTemp, nwRef): refConf = os.path.join(nwRef, "novelwriter.conf") testConf = os.path.join(tmpConf.confPath, "novelwriter.conf") assert tmpConf.confPath == nwTemp assert not tmpConf.setShowRefPanel(False) 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) assert tmpConf.confChanged assert tmpConf.saveConfig() assert cmpFiles(testConf, refConf, [2]) assert not tmpConf.confChanged
def testProjectNewCustomB(nwFuncTemp, nwTempProj, nwRef, nwDummy): """Create a new project from a project wizard dictionary. Custom type without chapters, but with scenes. """ projFile = os.path.join(nwFuncTemp, "nwProject.nwx") testFile = os.path.join(nwTempProj, "5_nwProject.nwx") refFile = os.path.join(nwRef, "proj", "5_nwProject.nwx") projData = { "projName": "Test Custom", "projTitle": "Test Novel", "projAuthors": "Jane Doe\nJohn Doh\n", "projPath": nwFuncTemp, "popSample": False, "popMinimal": False, "popCustom": True, "addRoots": [ nwItemClass.PLOT, nwItemClass.CHARACTER, nwItemClass.WORLD, nwItemClass.TIMELINE, nwItemClass.OBJECT, nwItemClass.ENTITY, ], "numChapters": 0, "numScenes": 6, "chFolders": True, } theProject = NWProject(nwDummy) theProject.projTree.setSeed(42) assert theProject.newProject(projData) assert theProject.saveProject() assert theProject.closeProject() copyfile(projFile, testFile) assert cmpFiles(testFile, refFile, [2, 6, 7, 8])
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()
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 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()
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 testIndexBuildCheck(monkeypatch, nwLipsum, nwDummy, nwTempProj, nwRef): """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(nwTempProj, "1_tagsIndex.json") refFile = os.path.join(nwRef, "proj", "1_tagsIndex.json") theProject = NWProject(nwDummy) theProject.projTree.setSeed(42) assert theProject.openProject(nwLipsum) monkeypatch.setattr("nw.core.index.time", lambda: 123.4) theIndex = NWIndex(theProject, nwDummy) 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, refFile)