예제 #1
0
def testGuiAbout_Dialog(qtbot, monkeypatch, nwGUI):
    """Test the full about dialogs.
    """
    # 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.pageNotes.document().characterCount() > 100
    assert msgAbout.pageLicense.document().characterCount() > 100

    msgAbout.mainConf.assetPath = "whatever"

    msgAbout._fillNotesPage()
    assert msgAbout.pageNotes.toPlainText(
    ) == "Error loading release notes text ..."

    msgAbout._fillLicensePage()
    assert msgAbout.pageLicense.toPlainText(
    ) == "Error loading license text ..."

    msgAbout.showReleaseNotes()
    assert msgAbout.tabBox.currentWidget() == msgAbout.pageNotes

    # Qt About
    monkeypatch.setattr(QMessageBox, "aboutQt", lambda *args, **kwargs: None)
    nwGUI.mainMenu.aAboutQt.activate(QAction.Trigger)

    # qtbot.stopForInteraction()
    msgAbout._doClose()
예제 #2
0
def testToolProjectWizard_Handling(qtbot, monkeypatch, nwGUI, nwMinimal):
    """Test the launch of the project wizard.
    Disabled for macOS because the test segfaults on QWizard.show()
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Yes)

    ##
    #  Test New Project Function
    ##

    # New with a project open should cause an error
    assert nwGUI.openProject(nwMinimal)
    with monkeypatch.context() as mp:
        mp.setattr(nwGUI, "closeProject", lambda *a: False)
        assert nwGUI.newProject() is False

    # Close project, but call with invalid path
    assert nwGUI.closeProject()
    with monkeypatch.context() as mp:
        mp.setattr(nwGUI, "showNewProjectDialog", lambda *a: None)
        assert nwGUI.newProject() is False

        # Now, with an empty dictionary
        mp.setattr(nwGUI, "showNewProjectDialog", lambda *a: {})
        assert nwGUI.newProject() is False

        # Now, with a non-empty folder
        mp.setattr(nwGUI, "showNewProjectDialog", lambda *a: {"projPath": nwMinimal})
        assert nwGUI.newProject() is False

    ##
    #  Test the Wizard Launching
    ##

    nwGUI.mainConf.lastPath = " "
    monkeypatch.setattr(GuiProjectWizard, "exec_", lambda *a: None)

    result = nwGUI.showNewProjectDialog()
    qtbot.waitUntil(lambda: getGuiItem("GuiProjectWizard") is not None, timeout=1000)

    nwWiz = getGuiItem("GuiProjectWizard")
    assert isinstance(nwWiz, GuiProjectWizard)
    nwWiz.show()

    qtbot.wait(stepDelay)
    qtbot.mouseClick(nwWiz.button(QWizard.CancelButton), Qt.LeftButton)
    assert result is None

    with monkeypatch.context() as mp:
        mp.setattr(GuiProjectWizard, "result", lambda *a: QDialog.Accepted)
        result = nwGUI.showNewProjectDialog()
        nwWiz.button(QWizard.CancelButton).click()
        assert isinstance(result, dict)

    nwWiz.reject()
    nwWiz.close()
예제 #3
0
def testDlgItemEditor_Dialog(qtbot, monkeypatch, nwGUI, fncProj):
    """Test launching the item editor dialog from GuiMain.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)

    # Block Dialog exec_
    monkeypatch.setattr(GuiItemEditor, "exec_", lambda *a: None)

    # Open Editor wo/Project
    assert nwGUI.editItem() is False

    # Create and Open Project
    nwGUI.theProject.projTree.setSeed(42)
    assert nwGUI.newProject({"projPath": fncProj})

    # No Selection
    nwGUI.treeView.clearSelection()
    assert nwGUI.editItem() is False

    # Force opening from editor
    assert nwGUI.openDocument("0e17daca5f3e1")
    nwGUI.isFocusMode = True

    # Block Tree Lookup
    with monkeypatch.context() as mp:
        mp.setattr(NWTree, "__getitem__", lambda *a: None)
        assert nwGUI.editItem() is False

    # Invalid Type
    nwGUI.theProject.projTree["0e17daca5f3e1"]._type = nwItemType.NO_TYPE
    assert nwGUI.editItem() is False
    nwGUI.theProject.projTree["0e17daca5f3e1"]._type = nwItemType.FILE

    # Open Properly
    assert nwGUI.editItem() is True
    qtbot.waitUntil(lambda: getGuiItem("GuiItemEditor") is not None, timeout=1000)
    itemEdit = getGuiItem("GuiItemEditor")
    assert itemEdit is not None
    itemEdit.close()

    # Open Via Menu
    with monkeypatch.context() as mp:
        mp.setattr(GuiItemEditor, "result", lambda *a: QDialog.Accepted)
        nwGUI.mainMenu.aEditItem.activate(QAction.Trigger)
        qtbot.waitUntil(lambda: getGuiItem("GuiItemEditor") is not None, timeout=1000)
        itemEdit = getGuiItem("GuiItemEditor")
        assert itemEdit is not None
        itemEdit.close()

    nwGUI.isFocusMode = False
예제 #4
0
def testToolLipsum_Main(qtbot, monkeypatch, nwGUI, fncProj):
    """Test the Lorem Ipsum tool.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)

    # Check that we cannot open when there is no project
    nwGUI.mainMenu.aLipsumText.activate(QAction.Trigger)
    assert getGuiItem("GuiLipsum") is None

    # Create a new project
    nwGUI.theProject.projTree.setSeed(42)
    assert nwGUI.newProject({"projPath": fncProj}) is True
    assert nwGUI.openDocument("0e17daca5f3e1") is True
    assert len(nwGUI.docEditor.getText()) == 15

    # Open the tool
    nwGUI.mainMenu.aLipsumText.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiLipsum") is not None, timeout=1000)

    nwLipsum = getGuiItem("GuiLipsum")
    assert isinstance(nwLipsum, GuiLipsum)

    # Insert paragraphs
    nwGUI.docEditor.setCursorPosition(100)  # End of document
    nwLipsum.paraCount.setValue(2)
    nwLipsum._doInsert()
    theText = nwGUI.docEditor.getText()
    assert "Lorem ipsum" in theText
    assert len(theText) == 965

    # Insert random paragraph
    nwGUI.docEditor.setCursorPosition(1000)  # End of document
    nwLipsum.randSwitch.setChecked(True)
    nwLipsum.paraCount.setValue(1)
    nwLipsum._doInsert()
    theText = nwGUI.docEditor.getText()
    assert len(theText) > 965

    # Close
    nwLipsum._doClose()
예제 #5
0
def testDlgAbout_NWDialog(qtbot, monkeypatch, nwGUI):
    """Test the novelWriter about dialogs.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)

    # NW About
    nwGUI.mainTheme.themeName = "A Theme"
    nwGUI.mainTheme.themeAuthor = "An Author"
    assert nwGUI.showAboutNWDialog(showNotes=True) is True

    qtbot.waitUntil(lambda: getGuiItem("GuiAbout") is not None, timeout=1000)
    msgAbout = getGuiItem("GuiAbout")
    assert isinstance(msgAbout, GuiAbout)

    assert msgAbout.pageAbout.document().characterCount() > 100
    assert msgAbout.pageNotes.document().characterCount() > 100
    assert msgAbout.pageLicense.document().characterCount() > 100

    msgAbout.mainConf.assetPath = "whatever"

    msgAbout._fillNotesPage()
    assert msgAbout.pageNotes.toPlainText(
    ) == "Error loading release notes text ..."

    msgAbout._fillLicensePage()
    assert msgAbout.pageLicense.toPlainText(
    ) == "Error loading licence text ..."

    msgAbout.showReleaseNotes()
    assert msgAbout.tabBox.currentWidget() == msgAbout.pageNotes
    msgAbout._doClose()

    # Open Again from Menu
    nwGUI.mainMenu.aAboutNW.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiAbout") is not None, timeout=1000)
    msgAbout = getGuiItem("GuiAbout")
    assert msgAbout is not None
    msgAbout._doClose()
예제 #6
0
def testGuiLoadProject_Main(qtbot, monkeypatch, nwGUI, nwMinimal):
    """Test the load project wizard.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)

    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

    nwLoad.close()
예제 #7
0
def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI, fncDir, fncProj,
                               outDir, refDir):
    """Test the full project settings dialog.
    """
    projFile = os.path.join(fncProj, "nwProject.nwx")
    testFile = os.path.join(outDir, "guiProjSettings_Dialog_nwProject.nwx")
    compFile = os.path.join(refDir, "guiProjSettings_Dialog_nwProject.nwx")

    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "critical", lambda *args: QMessageBox.Yes)

    # Check that we cannot open when there is no project
    nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger)
    assert getGuiItem("GuiProjectSettings") is None

    # Create new project
    nwGUI.theProject.projTree.setSeed(42)
    assert nwGUI.newProject({"projPath": fncProj})
    nwGUI.mainConf.backupPath = fncDir

    nwGUI.theProject.setSpellLang("en")
    nwGUI.theProject.setBookAuthors("Jane Smith\nJohn Smith")
    nwGUI.theProject.setAutoReplace({"A": "B", "C": "D"})

    # Get the dialog object
    monkeypatch.setattr(GuiProjectSettings, "exec_", lambda *args: None)
    monkeypatch.setattr(GuiProjectSettings, "result",
                        lambda *args: QDialog.Accepted)
    nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiProjectSettings") is not None,
                    timeout=1000)

    projEdit = getGuiItem("GuiProjectSettings")
    assert isinstance(projEdit, GuiProjectSettings)
    projEdit.show()
    qtbot.addWidget(projEdit)

    # Settings Tab
    # ============

    assert projEdit.tabMain.editName.text() == "New Project"
    assert projEdit.tabMain.editTitle.text() == ""
    assert projEdit.tabMain.editAuthors.toPlainText(
    ) == "Jane Smith\nJohn Smith"
    assert projEdit.tabMain.spellLang.currentData() == "en"
    assert projEdit.tabMain.doBackup.isChecked() is False

    qtbot.wait(stepDelay)
    projEdit.tabMain.editName.setText("")
    for c in "Project Name":
        qtbot.keyClick(projEdit.tabMain.editName, c, delay=typeDelay)
    for c in "Project Title":
        qtbot.keyClick(projEdit.tabMain.editTitle, c, delay=typeDelay)

    projEdit.tabMain.editAuthors.clear()
    for c in "Jane Doe":
        qtbot.keyClick(projEdit.tabMain.editAuthors, c, delay=typeDelay)
    qtbot.keyClick(projEdit.tabMain.editAuthors, Qt.Key_Return, delay=keyDelay)
    for c in "John Doh":
        qtbot.keyClick(projEdit.tabMain.editAuthors, c, delay=typeDelay)
    qtbot.keyClick(projEdit.tabMain.editAuthors, Qt.Key_Return, delay=keyDelay)

    qtbot.wait(stepDelay)
    assert projEdit.tabMain.editName.text() == "Project Name"
    assert projEdit.tabMain.editTitle.text() == "Project Title"
    assert projEdit.tabMain.editAuthors.toPlainText() == "Jane Doe\nJohn Doh\n"

    # Status Tab
    # ==========

    projEdit._tabBox.setCurrentWidget(projEdit.tabStatus)

    assert projEdit.tabStatus.colChanged is False
    assert projEdit.tabStatus.getNewList() is None
    assert projEdit.tabStatus.listBox.topLevelItemCount() == 4

    # Fake drag'n'drop should change changed status
    projEdit.tabStatus._rowsMoved()
    assert projEdit.tabStatus.colChanged is True
    projEdit.tabStatus.colChanged = False

    projEdit.tabStatus.listBox.clearSelection()
    assert projEdit.tabStatus._getSelectedItem() is None
    projEdit.tabStatus.listBox.topLevelItem(0).setSelected(True)
    assert isinstance(projEdit.tabStatus._getSelectedItem(), QTreeWidgetItem)

    # Can't delete the first item (it's in use)
    projEdit.tabStatus.listBox.clearSelection()
    projEdit.tabStatus.listBox.topLevelItem(0).setSelected(True)
    qtbot.mouseClick(projEdit.tabStatus.delButton, Qt.LeftButton)
    assert projEdit.tabStatus.listBox.topLevelItemCount() == 4

    # Can delete the third item
    projEdit.tabStatus.listBox.clearSelection()
    projEdit.tabStatus.listBox.topLevelItem(2).setSelected(True)
    qtbot.mouseClick(projEdit.tabStatus.delButton, Qt.LeftButton)
    assert projEdit.tabStatus.listBox.topLevelItemCount() == 3

    # Add a new item
    monkeypatch.setattr(QColorDialog, "getColor",
                        lambda *args: QColor(20, 30, 40))
    qtbot.mouseClick(projEdit.tabStatus.addButton, Qt.LeftButton)
    projEdit.tabStatus.listBox.topLevelItem(3).setSelected(True)
    for n in range(8):
        qtbot.keyClick(projEdit.tabStatus.editName,
                       Qt.Key_Backspace,
                       delay=typeDelay)
    for c in "Final":
        qtbot.keyClick(projEdit.tabStatus.editName, c, delay=typeDelay)
    qtbot.mouseClick(projEdit.tabStatus.colButton, Qt.LeftButton)
    qtbot.mouseClick(projEdit.tabStatus.saveButton, Qt.LeftButton)
    assert projEdit.tabStatus.listBox.topLevelItemCount() == 4
    qtbot.wait(stepDelay)

    assert projEdit.tabStatus.colChanged is True
    assert projEdit.tabStatus.getNewList() == [("New", 100, 100, 100, "New"),
                                               ("Note", 200, 50, 0, "Note"),
                                               ("Finished", 50, 200, 0,
                                                "Finished"),
                                               ("Final", 20, 30, 40, None)]

    # Importance Tab
    # ==============

    projEdit._tabBox.setCurrentWidget(projEdit.tabImport)
    projEdit.tabStatus.listBox.clearSelection()
    projEdit.tabImport.listBox.topLevelItem(3).setSelected(True)
    qtbot.mouseClick(projEdit.tabImport.delButton, Qt.LeftButton)
    qtbot.mouseClick(projEdit.tabImport.addButton, Qt.LeftButton)
    projEdit.tabStatus.listBox.clearSelection()
    projEdit.tabImport.listBox.topLevelItem(3).setSelected(True)
    for n in range(8):
        qtbot.keyClick(projEdit.tabImport.editName,
                       Qt.Key_Backspace,
                       delay=typeDelay)
    for c in "Final":
        qtbot.keyClick(projEdit.tabImport.editName, c, delay=typeDelay)
    qtbot.mouseClick(projEdit.tabImport.saveButton, Qt.LeftButton)
    qtbot.wait(stepDelay)

    # Auto-Replace Tab
    # ================

    qtbot.wait(stepDelay)
    projEdit._tabBox.setCurrentWidget(projEdit.tabReplace)

    assert projEdit.tabReplace.listBox.topLevelItem(0).text(0) == "<A>"
    assert projEdit.tabReplace.listBox.topLevelItem(0).text(1) == "B"
    assert projEdit.tabReplace.listBox.topLevelItem(1).text(0) == "<C>"
    assert projEdit.tabReplace.listBox.topLevelItem(1).text(1) == "D"

    qtbot.mouseClick(projEdit.tabReplace.addButton, Qt.LeftButton)
    projEdit.tabReplace.listBox.topLevelItem(2).setSelected(True)
    projEdit.tabReplace.editKey.setText("")
    for c in "Th is ":
        qtbot.keyClick(projEdit.tabReplace.editKey, c, delay=typeDelay)
    projEdit.tabReplace.editValue.setText("")
    for c in "With This Stuff ":
        qtbot.keyClick(projEdit.tabReplace.editValue, c, delay=typeDelay)
    qtbot.mouseClick(projEdit.tabReplace.saveButton, Qt.LeftButton)

    qtbot.wait(stepDelay)
    projEdit.tabReplace.listBox.clearSelection()
    assert not projEdit.tabReplace._saveEntry()
    assert not projEdit.tabReplace._delEntry()
    qtbot.mouseClick(projEdit.tabReplace.addButton, Qt.LeftButton)

    newIdx = -1
    for i in range(projEdit.tabReplace.listBox.topLevelItemCount()):
        if projEdit.tabReplace.listBox.topLevelItem(i).text(0) == "<keyword4>":
            newIdx = i
            break

    assert newIdx >= 0
    newItem = projEdit.tabReplace.listBox.topLevelItem(newIdx)
    projEdit.tabReplace.listBox.setCurrentItem(newItem)
    qtbot.mouseClick(projEdit.tabReplace.delButton, Qt.LeftButton)
    qtbot.wait(stepDelay)

    # Save & Check
    # ============

    projEdit._doSave()

    # Open again, and check project settings
    nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiProjectSettings") is not None,
                    timeout=1000)

    projEdit = getGuiItem("GuiProjectSettings")
    assert isinstance(projEdit, GuiProjectSettings)

    qtbot.addWidget(projEdit)
    assert projEdit.tabMain.editName.text() == "Project Name"
    assert projEdit.tabMain.editTitle.text() == "Project Title"
    theAuth = projEdit.tabMain.editAuthors.toPlainText().strip().splitlines()
    assert len(theAuth) == 2
    assert theAuth[0] == "Jane Doe"
    assert theAuth[1] == "John Doh"

    projEdit._doClose()
    qtbot.wait(stepDelay)

    assert nwGUI.saveProject()
    qtbot.wait(stepDelay)

    # Check the files
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [2, 8, 9, 10])
예제 #8
0
def testDlgItemEditor_Dialog(qtbot, monkeypatch, nwGUI, fncDir, fncProj,
                             refDir, outDir):
    """Test the full item editor dialog.
    """
    projFile = os.path.join(fncProj, "nwProject.nwx")
    testFile = os.path.join(outDir, "guiItemEditor_Dialog_nwProject.nwx")
    compFile = os.path.join(refDir, "guiItemEditor_Dialog_nwProject.nwx")

    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
    monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *args: True)

    # Create new, save, open project
    nwGUI.theProject.projTree.setSeed(42)
    assert nwGUI.newProject({"projPath": fncProj})
    assert nwGUI.openDocument("0e17daca5f3e1")
    assert nwGUI.treeView.setSelectedHandle("0e17daca5f3e1", doScroll=True)

    monkeypatch.setattr(GuiItemEditor, "exec_", lambda *args: None)
    nwGUI.mainMenu.aEditItem.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiItemEditor") is not None,
                    timeout=1000)

    itemEdit = getGuiItem("GuiItemEditor")
    assert isinstance(itemEdit, GuiItemEditor)
    itemEdit.show()

    qtbot.addWidget(itemEdit)

    assert itemEdit.editName.text() == "New Scene"
    assert itemEdit.editStatus.currentData() == "New"
    assert itemEdit.editLayout.currentData() == nwItemLayout.SCENE

    for c in "Just a Page":
        qtbot.keyClick(itemEdit.editName, c, delay=typeDelay)
    itemEdit.editStatus.setCurrentIndex(1)
    layoutIdx = itemEdit.editLayout.findData(nwItemLayout.PAGE)
    itemEdit.editLayout.setCurrentIndex(layoutIdx)

    itemEdit.editExport.setChecked(False)
    assert not itemEdit.editExport.isChecked()
    itemEdit._doSave()

    nwGUI.mainMenu.aEditItem.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiItemEditor") is not None,
                    timeout=1000)

    itemEdit = getGuiItem("GuiItemEditor")
    assert isinstance(itemEdit, GuiItemEditor)
    itemEdit.show()

    qtbot.addWidget(itemEdit)
    assert itemEdit.editName.text() == "Just a Page"
    assert itemEdit.editStatus.currentData() == "Note"
    assert itemEdit.editLayout.currentData() == nwItemLayout.PAGE
    itemEdit._doClose()

    # Check that the header is updated
    nwGUI.docEditor.updateDocInfo("0e17daca5f3e1")
    assert nwGUI.docEditor.docHeader.theTitle.text(
    ) == "Novel  ›  New Chapter  ›  Just a Page"
    assert not nwGUI.docEditor.setCursorLine("where?")
    assert nwGUI.docEditor.setCursorLine(2)
    qtbot.wait(stepDelay)
    assert nwGUI.docEditor.getCursorPosition() == 15

    qtbot.wait(stepDelay)
    assert nwGUI.saveProject()
    qtbot.wait(stepDelay)

    # Check the files
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
예제 #9
0
def testToolBuild_Main(qtbot, monkeypatch, nwGUI, nwLipsum, refDir, outDir):
    """Test the build tool.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "information", lambda *args: QMessageBox.Yes)
    monkeypatch.setattr(QFileDialog, "getSaveFileName", lambda a, b, c, **kwargs: (c, None))

    # Check that we cannot open when there is no project
    nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger)
    assert getGuiItem("GuiBuildNovel") is None

    # Open a project
    assert nwGUI.openProject(nwLipsum)

    # Open the tool
    nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiBuildNovel") is not None, timeout=1000)

    nwBuild = getGuiItem("GuiBuildNovel")
    assert isinstance(nwBuild, GuiBuildNovel)

    nwBuild.textFont.setText("DejaVu Sans")
    nwBuild.textSize.setValue(11)

    # Test Save
    # =========

    # Invalid file format
    assert not nwBuild._saveDocument(-1)

    # Non-existent path
    with monkeypatch.context() as mp:
        mp.setattr("os.path.expanduser", lambda *args, **kwargs: nwLipsum)
        assert nwGUI.mainConf.lastPath != nwLipsum
        nwGUI.mainConf.lastPath = "no_such_path"
        assert nwBuild._saveDocument(nwBuild.FMT_NWD)
        assert nwGUI.mainConf.lastPath == nwLipsum

    # No path selected
    with monkeypatch.context() as mp:
        mp.setattr(QFileDialog, "getSaveFileName", lambda *args, **kwargs: ("", ""))
        assert not nwBuild._saveDocument(nwBuild.FMT_NWD)

    # Default Settings
    nwGUI.mainConf.lastPath = nwLipsum
    qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)

    assert nwBuild._saveDocument(nwBuild.FMT_NWD)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step1_Lorem_Ipsum.nwd")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step1_Lorem_Ipsum.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    assert nwBuild._saveDocument(nwBuild.FMT_HTM)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step1_Lorem_Ipsum.htm")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step1_Lorem_Ipsum.htm")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    assert nwBuild._saveDocument(nwBuild.FMT_MD)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.md")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step1_Lorem_Ipsum.md")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step1_Lorem_Ipsum.md")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    assert nwBuild._saveDocument(nwBuild.FMT_GH)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.md")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step1G_Lorem_Ipsum.md")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step1G_Lorem_Ipsum.md")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    assert nwBuild._saveDocument(nwBuild.FMT_FODT)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.fodt")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step1_Lorem_Ipsum.fodt")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step1_Lorem_Ipsum.fodt")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [4, 5])

    # Change Title Formats and Flip Switches
    nwBuild.fmtChapter.setText(r"Chapter %chw%: %title%")
    qtbot.wait(stepDelay)
    nwBuild.fmtScene.setText(r"Scene %ch%.%sc%: %title%")
    qtbot.wait(stepDelay)
    nwBuild.fmtSection.setText(r"%ch%.%sc%.1: %title%")
    qtbot.wait(stepDelay)

    qtbot.mouseClick(nwBuild.justifyText, Qt.LeftButton)
    qtbot.wait(stepDelay)
    qtbot.mouseClick(nwBuild.includeSynopsis, Qt.LeftButton)
    qtbot.wait(stepDelay)
    qtbot.mouseClick(nwBuild.includeComments, Qt.LeftButton)
    qtbot.wait(stepDelay)
    qtbot.mouseClick(nwBuild.includeKeywords, Qt.LeftButton)
    qtbot.wait(stepDelay)
    qtbot.mouseClick(nwBuild.replaceUCode, Qt.LeftButton)
    qtbot.wait(stepDelay)

    qtbot.mouseClick(nwBuild.noteFiles, Qt.LeftButton)
    qtbot.wait(stepDelay)
    qtbot.mouseClick(nwBuild.ignoreFlag, Qt.LeftButton)
    qtbot.wait(stepDelay)

    qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)

    assert nwBuild._saveDocument(nwBuild.FMT_NWD)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step2_Lorem_Ipsum.nwd")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step2_Lorem_Ipsum.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    assert nwBuild._saveDocument(nwBuild.FMT_HTM)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step2_Lorem_Ipsum.htm")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step2_Lorem_Ipsum.htm")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    assert nwBuild._saveDocument(nwBuild.FMT_MD)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.md")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step2_Lorem_Ipsum.md")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step2_Lorem_Ipsum.md")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    assert nwBuild._saveDocument(nwBuild.FMT_FODT)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.fodt")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step2_Lorem_Ipsum.fodt")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step2_Lorem_Ipsum.fodt")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [4, 5])

    # Replace Tabs with Spaces
    qtbot.mouseClick(nwBuild.replaceTabs, Qt.LeftButton)
    qtbot.wait(stepDelay)

    qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)

    # Save files that can be compared
    assert nwBuild._saveDocument(nwBuild.FMT_NWD)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step3_Lorem_Ipsum.nwd")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step3_Lorem_Ipsum.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    assert nwBuild._saveDocument(nwBuild.FMT_HTM)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step3_Lorem_Ipsum.htm")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step3_Lorem_Ipsum.htm")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    assert nwBuild._saveDocument(nwBuild.FMT_MD)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.md")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step3_Lorem_Ipsum.md")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step3_Lorem_Ipsum.md")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    assert nwBuild._saveDocument(nwBuild.FMT_FODT)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.fodt")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step3_Lorem_Ipsum.fodt")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step3_Lorem_Ipsum.fodt")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [4, 5])

    # Putline Mode
    nwBuild.fmtChapter.setText(r"Chapter %chw%: %title%")
    qtbot.wait(stepDelay)
    nwBuild.fmtScene.setText(r"Scene %sca%: %title%")
    qtbot.wait(stepDelay)
    nwBuild.fmtSection.setText(r"Section: %title%")
    qtbot.wait(stepDelay)

    qtbot.mouseClick(nwBuild.includeComments, Qt.LeftButton)
    qtbot.wait(stepDelay)
    qtbot.mouseClick(nwBuild.noteFiles, Qt.LeftButton)
    qtbot.wait(stepDelay)
    qtbot.mouseClick(nwBuild.ignoreFlag, Qt.LeftButton)
    qtbot.wait(stepDelay)
    qtbot.mouseClick(nwBuild.includeBody, Qt.LeftButton)
    qtbot.wait(stepDelay)

    qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)

    # Save files that can be compared
    assert nwBuild._saveDocument(nwBuild.FMT_NWD)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step4_Lorem_Ipsum.nwd")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step4_Lorem_Ipsum.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    assert nwBuild._saveDocument(nwBuild.FMT_HTM)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step4_Lorem_Ipsum.htm")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step4_Lorem_Ipsum.htm")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    # Check the JSON files too at this stage
    assert nwBuild._saveDocument(nwBuild.FMT_JSON_H)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.json")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step4H_Lorem_Ipsum.json")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step4H_Lorem_Ipsum.json")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [8])

    assert nwBuild._saveDocument(nwBuild.FMT_JSON_M)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.json")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step4M_Lorem_Ipsum.json")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step4M_Lorem_Ipsum.json")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [8])

    # Since odt and fodt is built by the same code, we don't check the
    # output. but just that the different format can be written as well
    assert nwBuild._saveDocument(nwBuild.FMT_ODT)
    assert os.path.isfile(os.path.join(nwLipsum, "Lorem Ipsum.odt"))

    # Print to PDF
    if not nwGUI.mainConf.osDarwin:
        assert nwBuild._saveDocument(nwBuild.FMT_PDF)
        assert os.path.isfile(os.path.join(nwLipsum, "Lorem Ipsum.pdf"))

    # Close the build tool
    htmlText  = nwBuild.htmlText
    htmlStyle = nwBuild.htmlStyle
    buildTime = nwBuild.buildTime
    nwBuild._doClose()

    # Re-open build dialog from cahce
    nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiBuildNovel") is not None, timeout=1000)

    nwBuild = getGuiItem("GuiBuildNovel")
    assert isinstance(nwBuild, GuiBuildNovel)

    assert nwBuild.viewCachedDoc()
    assert nwBuild.htmlText  == htmlText
    assert nwBuild.htmlStyle == htmlStyle
    assert nwBuild.buildTime == buildTime

    nwBuild._doClose()
예제 #10
0
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 testGuiWritingStats_Dialog(qtbot, monkeypatch, nwGUI, fncDir, fncProj):
    """Test the full writing stats tool.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "information",
                        lambda *args: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "warning", lambda *args: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "critical", lambda *args: QMessageBox.Yes)

    # Create a project to work on
    assert nwGUI.newProject({"projPath": fncProj})
    qtbot.wait(100)
    assert nwGUI.saveProject()
    sessFile = os.path.join(fncProj, "meta", nwFiles.SESS_STATS)

    # Open the Writing Stats dialog
    nwGUI.mainConf.lastPath = ""
    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)

    # Test Loading
    # ============

    # No initial logfile
    assert not os.path.isfile(sessFile)
    assert not sessLog._loadLogFile()

    # Make a test log file
    writeFile(
        sessFile,
        ("# Offset 123\n"
         "# 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"))
    assert os.path.isfile(sessFile)
    assert sessLog._loadLogFile()
    assert sessLog.wordOffset == 123
    assert len(sessLog.logData) == 4

    # Make sure a faulty file can still be read
    writeFile(sessFile,
              ("# Offset abc123\n"
               "# 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\n"))
    assert sessLog._loadLogFile()
    assert sessLog.wordOffset == 0
    assert len(sessLog.logData) == 3

    # Test Exporting
    # ==============

    writeFile(
        sessFile,
        ("# 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"
         "2020-01-08 21:00:00  2020-01-08 21:00:10       120         5\n"))
    sessLog.populateGUI()

    # Make the saving fail
    monkeypatch.setattr(QFileDialog, "getSaveFileName", lambda *args, **kwargs:
                        ("", ""))
    assert not sessLog._saveData(sessLog.FMT_CSV)
    assert not sessLog._saveData(sessLog.FMT_JSON)
    assert not sessLog._saveData(None)

    # Make the save succeed
    monkeypatch.setattr("os.path.expanduser", lambda *args: fncDir)
    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)

    assert nwGUI.mainConf.lastPath == fncDir

    # Check the exported files
    jsonStats = os.path.join(fncDir, "sessionStats.json")
    with open(jsonStats, mode="r", encoding="utf-8") as inFile:
        jsonData = json.load(inFile)

    assert len(jsonData) == 4
    assert jsonData[1]["length"] >= 14.0
    assert jsonData[1]["newWords"] == 119
    assert jsonData[1]["novelWords"] == 125
    assert jsonData[1]["noteWords"] == 0

    # Test Filters
    # ============

    # No Novel Files
    qtbot.mouseClick(sessLog.incNovel, Qt.LeftButton)
    qtbot.wait(stepDelay)
    assert sessLog._saveData(sessLog.FMT_JSON)
    qtbot.wait(stepDelay)

    assert sessLog.novelWords.text() == "{:n}".format(120)
    assert sessLog.notesWords.text() == "{:n}".format(5)
    assert sessLog.totalWords.text() == "{:n}".format(125)

    jsonStats = os.path.join(fncDir, "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(fncDir, "sessionStats.json")
    with open(jsonStats, mode="r", encoding="utf-8") as inFile:
        jsonData = json.load(inFile)

    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 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(fncDir, "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(fncDir, "sessionStats.json")
    with open(jsonStats, mode="r", encoding="utf-8") as inFile:
        jsonData = json.load(inFile)

    assert len(jsonData) == 5

    # 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(fncDir, "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) == 4

    # IOError
    # =======
    monkeypatch.setattr("builtins.open", causeOSError)
    assert not sessLog._loadLogFile()
    assert not sessLog._saveData(sessLog.FMT_CSV)

    # qtbot.stopForInteraction()

    sessLog._doClose()
    assert nwGUI.closeProject()
    qtbot.wait(stepDelay)

    monkeypatch.undo()
def testGuiMergeSplit_Tools(qtbot, monkeypatch, nwGUI, nwLipsum, refDir,
                            outDir):
    """Test the full merge and split tools.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)

    nwGUI.theProject.projTree.setSeed(42)
    assert nwGUI.openProject(nwLipsum)
    qtbot.wait(stepDelay)

    assert nwGUI.treeView.setSelectedHandle("45e6b01ca35c1")
    qtbot.wait(stepDelay)

    monkeypatch.setattr(GuiDocMerge, "exec_", lambda *args: None)
    nwGUI.mainMenu.aMergeDocs.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiDocMerge") is not None,
                    timeout=1000)

    nwMerge = getGuiItem("GuiDocMerge")
    assert isinstance(nwMerge, GuiDocMerge)
    nwMerge.show()
    qtbot.wait(stepDelay)

    nwMerge._doMerge()
    qtbot.wait(stepDelay)

    assert nwGUI.theProject.projTree["73475cb40a568"] is not None

    projFile = os.path.join(nwLipsum, "content", "73475cb40a568.nwd")
    testFile = os.path.join(outDir, "guiMerge_73475cb40a568.nwd")
    compFile = os.path.join(refDir, "guiMerge_73475cb40a568.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    # Split By Chapter
    assert nwGUI.treeView.setSelectedHandle("73475cb40a568")
    qtbot.wait(stepDelay)

    monkeypatch.setattr(GuiDocSplit, "exec_", lambda *args: None)
    nwGUI.mainMenu.aSplitDoc.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiDocSplit") is not None,
                    timeout=1000)

    nwSplit = getGuiItem("GuiDocSplit")
    assert isinstance(nwSplit, GuiDocSplit)
    nwSplit.show()
    qtbot.wait(stepDelay)

    nwSplit.splitLevel.setCurrentIndex(1)
    qtbot.wait(stepDelay)

    nwSplit._doSplit()
    assert nwGUI.theProject.projTree["71ee45a3c0db9"] is not None

    # This should give us back the file as it was before
    projFile = os.path.join(nwLipsum, "content", "71ee45a3c0db9.nwd")
    testFile = os.path.join(outDir, "guiMerge_71ee45a3c0db9.nwd")
    compFile = os.path.join(refDir, "guiMerge_73475cb40a568.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [1, 2, 3])

    # Split By Scene
    assert nwGUI.treeView.setSelectedHandle("73475cb40a568")
    qtbot.wait(stepDelay)
    nwGUI.mainMenu.aSplitDoc.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiDocSplit") is not None,
                    timeout=1000)

    nwSplit = getGuiItem("GuiDocSplit")
    assert isinstance(nwSplit, GuiDocSplit)
    qtbot.wait(stepDelay)
    nwSplit.splitLevel.setCurrentIndex(2)
    qtbot.wait(stepDelay)

    nwSplit._doSplit()

    assert nwGUI.theProject.projTree["25fc0e7096fc6"] is not None
    assert nwGUI.theProject.projTree["31489056e0916"] is not None
    assert nwGUI.theProject.projTree["98010bd9270f9"] is not None

    projFile = os.path.join(nwLipsum, "content", "25fc0e7096fc6.nwd")
    testFile = os.path.join(outDir, "guiSplit_25fc0e7096fc6.nwd")
    compFile = os.path.join(refDir, "guiSplit_25fc0e7096fc6.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    projFile = os.path.join(nwLipsum, "content", "31489056e0916.nwd")
    testFile = os.path.join(outDir, "guiSplit_31489056e0916.nwd")
    compFile = os.path.join(refDir, "guiSplit_31489056e0916.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    projFile = os.path.join(nwLipsum, "content", "98010bd9270f9.nwd")
    testFile = os.path.join(outDir, "guiSplit_98010bd9270f9.nwd")
    compFile = os.path.join(refDir, "guiSplit_98010bd9270f9.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    # Split By Section
    assert nwGUI.treeView.setSelectedHandle("73475cb40a568")
    qtbot.wait(stepDelay)
    nwGUI.mainMenu.aSplitDoc.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiDocSplit") is not None,
                    timeout=1000)

    nwSplit = getGuiItem("GuiDocSplit")
    assert isinstance(nwSplit, GuiDocSplit)
    qtbot.wait(stepDelay)
    nwSplit.splitLevel.setCurrentIndex(3)
    qtbot.wait(stepDelay)

    nwSplit._doSplit()

    assert nwGUI.theProject.projTree["1a6562590ef19"] is not None
    assert nwGUI.theProject.projTree["031b4af5197ec"] is not None
    assert nwGUI.theProject.projTree["41cfc0d1f2d12"] is not None
    assert nwGUI.theProject.projTree["2858dcd1057d3"] is not None
    assert nwGUI.theProject.projTree["2fca346db6561"] is not None

    projFile = os.path.join(nwLipsum, "content", "1a6562590ef19.nwd")
    testFile = os.path.join(outDir, "guiSplit_1a6562590ef19.nwd")
    compFile = os.path.join(refDir, "guiSplit_25fc0e7096fc6.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [1, 2, 3])

    projFile = os.path.join(nwLipsum, "content", "031b4af5197ec.nwd")
    testFile = os.path.join(outDir, "guiSplit_031b4af5197ec.nwd")
    compFile = os.path.join(refDir, "guiSplit_031b4af5197ec.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    projFile = os.path.join(nwLipsum, "content", "41cfc0d1f2d12.nwd")
    testFile = os.path.join(outDir, "guiSplit_41cfc0d1f2d12.nwd")
    compFile = os.path.join(refDir, "guiSplit_41cfc0d1f2d12.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    projFile = os.path.join(nwLipsum, "content", "2858dcd1057d3.nwd")
    testFile = os.path.join(outDir, "guiSplit_2858dcd1057d3.nwd")
    compFile = os.path.join(refDir, "guiSplit_2858dcd1057d3.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    projFile = os.path.join(nwLipsum, "content", "2fca346db6561.nwd")
    testFile = os.path.join(outDir, "guiSplit_2fca346db6561.nwd")
    compFile = os.path.join(refDir, "guiSplit_2fca346db6561.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)
def testGuiProjDetails_Dialog(qtbot, monkeypatch, nwGUI, nwLipsum):
    """Test the project details dialog.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "information",
                        lambda *args: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "warning", lambda *args: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "critical", lambda *args: QMessageBox.Yes)

    # Create a project to work on
    assert nwGUI.openProject(nwLipsum)
    assert nwGUI.rebuildIndex(beQuiet=True)
    qtbot.wait(100)

    # Open the Writing Stats dialog
    nwGUI.mainConf.lastPath = ""
    nwGUI.mainMenu.aProjectDetails.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiProjectDetails") is not None,
                    timeout=1000)

    projDet = getGuiItem("GuiProjectDetails")
    assert isinstance(projDet, GuiProjectDetails)
    qtbot.wait(stepDelay)

    # Overview Page
    # =============

    assert projDet.tabMain.bookTitle.text() == "Lorem Ipsum"
    assert projDet.tabMain.projName.text()[-11:] == "Lorem Ipsum"
    assert projDet.tabMain.bookAuthors.text()[-10:] == "lipsum.com"

    assert projDet.tabMain.wordCountVal.text() == f"{3000:n}"
    assert projDet.tabMain.chapCountVal.text() == f"{3:n}"
    assert projDet.tabMain.sceneCountVal.text() == f"{5:n}"
    assert projDet.tabMain.revCountVal.text(
    ) == f"{nwGUI.theProject.saveCount:n}"

    assert projDet.tabMain.projPathVal.text() == nwLipsum

    # Contents Page
    # =============

    tocTab = projDet.tabContents
    tocTree = tocTab.tocTree
    assert tocTree.topLevelItemCount() == 7
    assert tocTree.topLevelItem(0).text(tocTab.C_TITLE) == "Lorem Ipsum"
    assert tocTree.topLevelItem(2).text(tocTab.C_TITLE) == "Prologue"
    assert tocTree.topLevelItem(3).text(tocTab.C_TITLE) == "Act One"
    assert tocTree.topLevelItem(4).text(tocTab.C_TITLE) == "Chapter One"
    assert tocTree.topLevelItem(5).text(tocTab.C_TITLE) == "Chapter Two"
    assert tocTree.topLevelItem(6).text(tocTab.C_TITLE) == "END"

    # Count Pages
    tocTab.wpValue.setValue(100)
    tocTab.poValue.setValue(4)
    tocTab.dblValue.setChecked(False)
    tocTab._populateTree()

    thePages = ["1", "2", "1", "1", "11", "17", "0"]
    thePage = ["i", "ii", "1", "2", "3", "14", "31"]
    for i in range(7):
        assert tocTree.topLevelItem(i).text(tocTab.C_PAGES) == thePages[i]
        assert tocTree.topLevelItem(i).text(tocTab.C_PAGE) == thePage[i]

    tocTab.poValue.setValue(5)
    tocTab.dblValue.setChecked(True)
    tocTab._populateTree()

    thePages = ["2", "2", "2", "2", "12", "18", "0"]
    thePage = ["i", "iii", "1", "3", "5", "17", "35"]
    for i in range(7):
        assert tocTree.topLevelItem(i).text(tocTab.C_PAGES) == thePages[i]
        assert tocTree.topLevelItem(i).text(tocTab.C_PAGE) == thePage[i]

    # qtbot.stopForInteraction()

    # Clean Up
    projDet._doClose()
    nwGUI.closeMain()
    monkeypatch.undo()
예제 #14
0
def testGuiBuild_Tool(qtbot, monkeypatch, nwGUI, nwLipsum, refDir, outDir):
    """Test the build tool.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "information",
                        lambda *args: QMessageBox.Yes)
    monkeypatch.setattr(QFileDialog, "getSaveFileName",
                        lambda a, b, c, **kwargs: (c, None))

    # Check that we cannot open when there is no project
    nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger)
    assert getGuiItem("GuiBuildNovel") is None

    # Open a project
    assert nwGUI.openProject(nwLipsum)
    nwGUI.mainConf.lastPath = nwLipsum

    # Open the tool
    nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiBuildNovel") is not None,
                    timeout=1000)

    nwBuild = getGuiItem("GuiBuildNovel")
    assert isinstance(nwBuild, GuiBuildNovel)

    # Default Settings
    qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)

    assert nwBuild._saveDocument(nwBuild.FMT_NWD)
    assert nwBuild._saveDocument(nwBuild.FMT_HTM)

    projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step1_Lorem_Ipsum.nwd")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step1_Lorem_Ipsum.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step1_Lorem_Ipsum.htm")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step1_Lorem_Ipsum.htm")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    # Change Title Formats and Flip Switches
    nwBuild.fmtChapter.setText(r"Chapter %chw%: %title%")
    qtbot.wait(stepDelay)
    nwBuild.fmtScene.setText(r"Scene %ch%.%sc%: %title%")
    qtbot.wait(stepDelay)
    nwBuild.fmtSection.setText(r"%ch%.%sc%.1: %title%")
    qtbot.wait(stepDelay)

    qtbot.mouseClick(nwBuild.justifyText, Qt.LeftButton)
    qtbot.wait(stepDelay)
    qtbot.mouseClick(nwBuild.includeSynopsis, Qt.LeftButton)
    qtbot.wait(stepDelay)
    qtbot.mouseClick(nwBuild.includeComments, Qt.LeftButton)
    qtbot.wait(stepDelay)
    qtbot.mouseClick(nwBuild.includeKeywords, Qt.LeftButton)
    qtbot.wait(stepDelay)

    qtbot.mouseClick(nwBuild.noteFiles, Qt.LeftButton)
    qtbot.wait(stepDelay)
    qtbot.mouseClick(nwBuild.ignoreFlag, Qt.LeftButton)
    qtbot.wait(stepDelay)

    qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)

    assert nwBuild._saveDocument(nwBuild.FMT_NWD)
    assert nwBuild._saveDocument(nwBuild.FMT_HTM)

    projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step2_Lorem_Ipsum.nwd")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step2_Lorem_Ipsum.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step2_Lorem_Ipsum.htm")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step2_Lorem_Ipsum.htm")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    # Replace Tabs with Spaces
    qtbot.mouseClick(nwBuild.replaceTabs, Qt.LeftButton)
    qtbot.wait(stepDelay)

    qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)

    # Save files that can be compared
    assert nwBuild._saveDocument(nwBuild.FMT_NWD)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step3_Lorem_Ipsum.nwd")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step3_Lorem_Ipsum.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    assert nwBuild._saveDocument(nwBuild.FMT_HTM)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step3_Lorem_Ipsum.htm")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step3_Lorem_Ipsum.htm")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    # Putline Mode
    nwBuild.fmtChapter.setText(r"Chapter %chw%: %title%")
    qtbot.wait(stepDelay)
    nwBuild.fmtScene.setText(r"Scene %sca%: %title%")
    qtbot.wait(stepDelay)
    nwBuild.fmtSection.setText(r"Section: %title%")
    qtbot.wait(stepDelay)

    qtbot.mouseClick(nwBuild.includeComments, Qt.LeftButton)
    qtbot.wait(stepDelay)
    qtbot.mouseClick(nwBuild.noteFiles, Qt.LeftButton)
    qtbot.wait(stepDelay)
    qtbot.mouseClick(nwBuild.ignoreFlag, Qt.LeftButton)
    qtbot.wait(stepDelay)
    qtbot.mouseClick(nwBuild.includeBody, Qt.LeftButton)
    qtbot.wait(stepDelay)

    qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)

    # Save files that can be compared
    assert nwBuild._saveDocument(nwBuild.FMT_NWD)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step4_Lorem_Ipsum.nwd")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step4_Lorem_Ipsum.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    assert nwBuild._saveDocument(nwBuild.FMT_HTM)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step4_Lorem_Ipsum.htm")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step4_Lorem_Ipsum.htm")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    # Check the JSON files too at this stage
    assert nwBuild._saveDocument(nwBuild.FMT_JSON_H)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.json")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step4H_Lorem_Ipsum.json")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step4H_Lorem_Ipsum.json")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [8])

    assert nwBuild._saveDocument(nwBuild.FMT_JSON_M)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.json")
    testFile = os.path.join(outDir, "guiBuild_Tool_Step4M_Lorem_Ipsum.json")
    compFile = os.path.join(refDir, "guiBuild_Tool_Step4M_Lorem_Ipsum.json")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [8])

    # Save other file types handled by Qt
    # We assume the export itself by the Qt library works, so we just
    # check that novelWriter successfully writes the files.
    assert nwBuild._saveDocument(nwBuild.FMT_ODT)
    assert os.path.isfile(os.path.join(nwLipsum, "Lorem Ipsum.odt"))

    if not nwGUI.mainConf.osDarwin:
        assert nwBuild._saveDocument(nwBuild.FMT_PDF)
        assert os.path.isfile(os.path.join(nwLipsum, "Lorem Ipsum.pdf"))

    assert nwBuild._saveDocument(nwBuild.FMT_MD)
    assert os.path.isfile(os.path.join(nwLipsum, "Lorem Ipsum.md"))

    assert nwBuild._saveDocument(nwBuild.FMT_TXT)
    assert os.path.isfile(os.path.join(nwLipsum, "Lorem Ipsum.txt"))

    # Close the build tool
    htmlText = nwBuild.htmlText
    htmlStyle = nwBuild.htmlStyle
    nwdText = nwBuild.nwdText
    buildTime = nwBuild.buildTime
    nwBuild._doClose()

    # Re-open build dialog from cahce
    nwGUI.mainMenu.aBuildProject.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiBuildNovel") is not None,
                    timeout=1000)

    nwBuild = getGuiItem("GuiBuildNovel")
    assert isinstance(nwBuild, GuiBuildNovel)

    assert nwBuild.viewCachedDoc()
    assert nwBuild.htmlText == htmlText
    assert nwBuild.htmlStyle == htmlStyle
    assert nwBuild.nwdText == nwdText
    assert nwBuild.buildTime == buildTime

    nwBuild._doClose()
예제 #15
0
def testToolProjectWizard_Main(qtbot, monkeypatch, nwGUI, nwMinimal):
    """Test the new project wizard.
    Disabled for macOS because the test segfaults on QWizard.show()
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Yes)

    ##
    #  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()
    with monkeypatch.context() as mp:
        mp.setattr(nwGUI, "showNewProjectDialog", lambda *a: None)
        assert not nwGUI.newProject()

        # Now, with an empty dictionary
        mp.setattr(nwGUI, "showNewProjectDialog", lambda *a: {})
        assert not nwGUI.newProject()

        # Now, with a non-empty folder
        mp.setattr(nwGUI, "showNewProjectDialog",
                   lambda *a: {"projPath": nwMinimal})
        assert not nwGUI.newProject()

    ##
    #  Test the Wizard
    ##

    monkeypatch.setattr(GuiProjectWizard, "exec_", lambda *a: 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()
예제 #16
0
def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
    """Test the merge documents tool.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Ok)
    monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))

    # Create a new project
    buildTestProject(nwGUI, fncProj)

    # Handles for new objects
    hNovelRoot  = "0000000000008"
    hChapterDir = "000000000000d"
    hChapterOne = "000000000000e"
    hSceneOne   = "000000000000f"
    hSceneTwo   = "0000000000010"
    hSceneThree = "0000000000011"
    hSceneFour  = "0000000000012"
    hMergedDoc  = "0000000000023"

    # Add Project Content
    nwGUI.switchFocus(nwWidget.TREE)
    nwGUI.projView.projTree.clearSelection()
    nwGUI.projView.projTree._getTreeItem(hChapterDir).setSelected(True)
    nwGUI.projView.projTree.newTreeItem(nwItemType.FILE)
    nwGUI.projView.projTree.newTreeItem(nwItemType.FILE)
    nwGUI.projView.projTree.newTreeItem(nwItemType.FILE)

    assert nwGUI.saveProject() is True
    assert nwGUI.closeProject() is True

    tChapterOne = "## Chapter One\n\n% Chapter one comment\n"
    tSceneOne   = "### Scene One\n\nThere once was a man from Nantucket"
    tSceneTwo   = "### Scene Two\n\nWho kept all his cash in a bucket."
    tSceneThree = "### Scene Three\n\n\tBut his daughter, named Nan,  \n\tRan away with a man"
    tSceneFour  = "### Scene Four\n\nAnd as for the bucket, Nantucket."

    contentDir = os.path.join(fncProj, "content")
    writeFile(os.path.join(contentDir, hChapterOne+".nwd"), tChapterOne)
    writeFile(os.path.join(contentDir, hSceneOne+".nwd"), tSceneOne)
    writeFile(os.path.join(contentDir, hSceneTwo+".nwd"), tSceneTwo)
    writeFile(os.path.join(contentDir, hSceneThree+".nwd"), tSceneThree)
    writeFile(os.path.join(contentDir, hSceneFour+".nwd"), tSceneFour)

    assert nwGUI.openProject(fncProj) is True

    # Open the Merge tool
    nwGUI.switchFocus(nwWidget.TREE)
    nwGUI.projView.projTree.clearSelection()
    nwGUI.projView.projTree._getTreeItem(hChapterDir).setSelected(True)

    monkeypatch.setattr(GuiDocMerge, "exec_", lambda *a: None)
    nwGUI.mainMenu.aMergeDocs.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiDocMerge") is not None, timeout=1000)

    nwMerge = getGuiItem("GuiDocMerge")
    assert isinstance(nwMerge, GuiDocMerge)
    nwMerge.show()
    qtbot.wait(50)

    # Populate List
    # =============

    nwMerge.listBox.clear()
    assert nwMerge.listBox.count() == 0

    # No item selected
    nwGUI.projView.projTree.clearSelection()
    assert nwMerge._populateList() is False
    assert nwMerge.listBox.count() == 0

    # Non-existing item
    with monkeypatch.context() as mp:
        mp.setattr(NWTree, "__getitem__", lambda *a: None)
        nwGUI.projView.projTree.clearSelection()
        nwGUI.projView.projTree._getTreeItem(hChapterDir).setSelected(True)
        assert nwMerge._populateList() is False
        assert nwMerge.listBox.count() == 0

    # Select a non-folder
    nwGUI.projView.projTree.clearSelection()
    nwGUI.projView.projTree._getTreeItem(hChapterOne).setSelected(True)
    assert nwMerge._populateList() is False
    assert nwMerge.listBox.count() == 0

    # Select the chapter folder
    nwGUI.projView.projTree.clearSelection()
    nwGUI.projView.projTree._getTreeItem(hChapterDir).setSelected(True)
    assert nwMerge._populateList() is True
    assert nwMerge.listBox.count() == 5

    # Merge Documents
    # ===============

    # First, a successful merge
    with monkeypatch.context() as mp:
        mp.setattr(GuiDocMerge, "_doClose", lambda *a: None)
        assert nwMerge._doMerge() is True
        assert nwGUI.saveProject() is True
        mergedFile = os.path.join(contentDir, hMergedDoc+".nwd")
        assert os.path.isfile(mergedFile)
        assert readFile(mergedFile) == (
            "%%%%~name: New Chapter\n"
            "%%%%~path: %s/%s\n"
            "%%%%~kind: NOVEL/DOCUMENT\n"
            "%s\n\n"
            "%s\n\n"
            "%s\n\n"
            "%s\n\n"
            "%s\n\n"
        ) % (
            hNovelRoot,
            hMergedDoc,
            tChapterOne.strip(),
            tSceneOne.strip(),
            tSceneTwo.strip(),
            tSceneThree.strip(),
            tSceneFour.strip(),
        )

    # OS error
    with monkeypatch.context() as mp:
        mp.setattr("builtins.open", causeOSError)
        assert nwMerge._doMerge() is False

    # Can't find the source item
    with monkeypatch.context() as mp:
        mp.setattr(NWTree, "__getitem__", lambda *a: None)
        assert nwMerge._doMerge() is False

    # No source handle set
    nwMerge.sourceItem = None
    assert nwMerge._doMerge() is False

    # No documents to merge
    nwMerge.listBox.clear()
    assert nwMerge._doMerge() is False

    # Close up
    nwMerge._doClose()
예제 #17
0
def testDlgWordList_Dialog(qtbot, monkeypatch, nwGUI, nwMinimal):
    """test the word list editor.
    """
    monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Yes)
    monkeypatch.setattr(GuiWordList, "exec_", lambda *a: None)
    monkeypatch.setattr(GuiWordList, "result", lambda *a: QDialog.Accepted)
    monkeypatch.setattr(GuiWordList, "accept", lambda *a: None)

    # Open project
    nwGUI.openProject(nwMinimal)
    qtbot.wait(stepDelay)
    dictFile = os.path.join(nwMinimal, "meta", nwFiles.PROJ_DICT)

    # Load the dialog
    nwGUI.mainMenu.aEditWordList.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiWordList") is not None,
                    timeout=1000)

    wList = getGuiItem("GuiWordList")
    assert isinstance(wList, GuiWordList)
    wList.show()
    qtbot.wait(stepDelay)

    # List should be blank
    assert wList.listBox.count() == 0

    # Add words
    writeFile(
        dictFile,
        (
            "word_a\n"
            "word_c\n"
            "word_g\n"
            "      \n"  # Should be ignored
            "word_f\n"
            "word_b\n"))
    qtbot.wait(stepDelay)
    assert wList._loadWordList()

    # Check that the content was loaded
    assert wList.listBox.item(0).text() == "word_a"
    assert wList.listBox.item(1).text() == "word_b"
    assert wList.listBox.item(2).text() == "word_c"
    assert wList.listBox.item(3).text() == "word_f"
    assert wList.listBox.item(4).text() == "word_g"

    # Add a blank word
    wList.newEntry.setText("   ")
    assert not wList._doAdd()

    # Add an existing word
    wList.newEntry.setText("word_c")
    assert not wList._doAdd()

    # Add a new word
    wList.newEntry.setText("word_d")
    assert wList._doAdd()

    # Check that the content now
    assert wList.listBox.item(0).text() == "word_a"
    assert wList.listBox.item(1).text() == "word_b"
    assert wList.listBox.item(2).text() == "word_c"
    assert wList.listBox.item(3).text() == "word_d"
    assert wList.listBox.item(4).text() == "word_f"
    assert wList.listBox.item(5).text() == "word_g"

    # Delete a word
    wList.newEntry.setText("delete_me")
    assert wList._doAdd()
    assert wList.listBox.item(0).text() == "delete_me"

    delItem = wList.listBox.findItems("delete_me", Qt.MatchExactly)[0]
    assert delItem.text() == "delete_me"
    delItem.setSelected(True)
    wList._doDelete()
    assert wList.listBox.findItems("delete_me", Qt.MatchExactly) == []
    assert wList.listBox.item(0).text() == "word_a"

    # Save files
    assert wList._doSave()
    assert readFile(dictFile) == ("word_a\n"
                                  "word_b\n"
                                  "word_c\n"
                                  "word_d\n"
                                  "word_f\n"
                                  "word_g\n")

    # Save again and make it fail
    monkeypatch.setattr("builtins.open", causeOSError)
    assert not wList._doSave()

    # qtbot.stopForInteraction()
    wList._doClose()
예제 #18
0
def testDlgPreferences_Main(qtbot, monkeypatch, fncDir, outDir, refDir):
    """Test the load project wizard.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "warning", lambda *a: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)

    # Must create a clean config and GUI object as the test-wide
    # novelwriter.CONFIG object is created on import an can be tainted by other tests
    confFile = os.path.join(fncDir, "novelwriter.conf")
    if os.path.isfile(confFile):
        os.unlink(confFile)
    theConf = Config()
    theConf.initConfig(fncDir, fncDir)
    theConf.setLastPath("")
    origConf = novelwriter.CONFIG
    novelwriter.CONFIG = theConf

    nwGUI = novelwriter.main(
        ["--testmode",
         "--config=%s" % fncDir,
         "--data=%s" % fncDir])
    qtbot.addWidget(nwGUI)
    nwGUI.show()
    qtbot.wait(stepDelay)

    theConf = nwGUI.mainConf
    assert theConf.confPath == fncDir

    monkeypatch.setattr(GuiPreferences, "exec_", lambda *a: None)
    monkeypatch.setattr(GuiPreferences, "result", lambda *a: QDialog.Accepted)
    monkeypatch.setattr(nwGUI.docEditor.spEnchant, "listDictionaries",
                        lambda: [("en", "none")])

    nwGUI.mainMenu.aPreferences.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiPreferences") is not None,
                    timeout=1000)

    nwPrefs = getGuiItem("GuiPreferences")
    assert isinstance(nwPrefs, GuiPreferences)
    nwPrefs.show()
    assert nwPrefs.mainConf.confPath == fncDir

    # General Settings
    qtbot.wait(keyDelay)
    tabGeneral = nwPrefs.tabGeneral
    nwPrefs._tabBox.setCurrentWidget(tabGeneral)

    qtbot.wait(keyDelay)
    assert tabGeneral.showFullPath.isChecked()
    qtbot.mouseClick(tabGeneral.showFullPath, Qt.LeftButton)
    assert not tabGeneral.showFullPath.isChecked()

    qtbot.wait(keyDelay)
    assert not tabGeneral.hideVScroll.isChecked()
    qtbot.mouseClick(tabGeneral.hideVScroll, Qt.LeftButton)
    assert tabGeneral.hideVScroll.isChecked()

    qtbot.wait(keyDelay)
    assert not tabGeneral.hideHScroll.isChecked()
    qtbot.mouseClick(tabGeneral.hideHScroll, Qt.LeftButton)
    assert tabGeneral.hideHScroll.isChecked()

    # Check font button
    monkeypatch.setattr(QFontDialog, "getFont", lambda font, obj: (font, True))
    qtbot.mouseClick(tabGeneral.fontButton, Qt.LeftButton)

    qtbot.wait(keyDelay)
    tabGeneral.guiFontSize.setValue(12)

    # Projects Settings
    qtbot.wait(keyDelay)
    tabProjects = nwPrefs.tabProjects
    nwPrefs._tabBox.setCurrentWidget(tabProjects)
    tabProjects.backupPath = "no/where"

    qtbot.wait(keyDelay)
    assert not tabProjects.backupOnClose.isChecked()
    qtbot.mouseClick(tabProjects.backupOnClose, Qt.LeftButton)
    assert tabProjects.backupOnClose.isChecked()

    # qtbot.stopForInteraction()

    # Check Browse button
    monkeypatch.setattr(QFileDialog, "getExistingDirectory",
                        lambda *a, **k: "")
    assert not tabProjects._backupFolder()
    monkeypatch.setattr(QFileDialog, "getExistingDirectory",
                        lambda *a, **k: "some/dir")
    qtbot.mouseClick(tabProjects.backupGetPath, Qt.LeftButton)

    qtbot.wait(keyDelay)
    tabProjects.autoSaveDoc.setValue(20)
    tabProjects.autoSaveProj.setValue(40)

    # Document Settings
    qtbot.wait(keyDelay)
    tabDocs = nwPrefs.tabDocs
    nwPrefs._tabBox.setCurrentWidget(tabDocs)

    qtbot.wait(keyDelay)
    qtbot.mouseClick(tabDocs.fontButton, Qt.LeftButton)

    qtbot.wait(keyDelay)
    tabDocs.textSize.setValue(13)
    tabDocs.textWidth.setValue(700)
    tabDocs.focusWidth.setValue(900)
    tabDocs.textMargin.setValue(45)
    tabDocs.tabWidth.setValue(45)

    qtbot.wait(keyDelay)
    assert not tabDocs.hideFocusFooter.isChecked()
    qtbot.mouseClick(tabDocs.hideFocusFooter, Qt.LeftButton)
    assert tabDocs.hideFocusFooter.isChecked()

    qtbot.wait(keyDelay)
    assert not tabDocs.doJustify.isChecked()
    qtbot.mouseClick(tabDocs.doJustify, Qt.LeftButton)
    assert tabDocs.doJustify.isChecked()

    # Editor Settings
    qtbot.wait(keyDelay)
    tabEditor = nwPrefs.tabEditor
    nwPrefs._tabBox.setCurrentWidget(tabEditor)

    qtbot.wait(keyDelay)
    assert not tabEditor.showTabsNSpaces.isChecked()
    qtbot.mouseClick(tabEditor.showTabsNSpaces, Qt.LeftButton)
    assert tabEditor.showTabsNSpaces.isChecked()

    qtbot.wait(keyDelay)
    assert not tabEditor.showLineEndings.isChecked()
    qtbot.mouseClick(tabEditor.showLineEndings, Qt.LeftButton)
    assert tabEditor.showLineEndings.isChecked()

    qtbot.wait(keyDelay)
    assert not tabEditor.autoScroll.isChecked()
    qtbot.mouseClick(tabEditor.autoScroll, Qt.LeftButton)
    assert tabEditor.autoScroll.isChecked()

    qtbot.wait(keyDelay)
    tabEditor.scrollPastEnd.setValue(0)

    qtbot.wait(keyDelay)
    tabEditor.bigDocLimit.setValue(500)

    # Syntax Settings
    qtbot.wait(keyDelay)
    tabSyntax = nwPrefs.tabSyntax
    nwPrefs._tabBox.setCurrentWidget(tabSyntax)

    qtbot.wait(keyDelay)
    assert tabSyntax.highlightQuotes.isChecked()
    qtbot.mouseClick(tabSyntax.highlightQuotes, Qt.LeftButton)
    assert not tabSyntax.highlightQuotes.isChecked()

    qtbot.wait(keyDelay)
    assert tabSyntax.highlightEmph.isChecked()
    qtbot.mouseClick(tabSyntax.highlightEmph, Qt.LeftButton)
    assert not tabSyntax.highlightEmph.isChecked()

    # Automation Settings
    qtbot.wait(keyDelay)
    tabAuto = nwPrefs.tabAuto
    nwPrefs._tabBox.setCurrentWidget(tabAuto)

    qtbot.wait(keyDelay)
    assert tabAuto.autoSelect.isChecked()
    qtbot.mouseClick(tabAuto.autoSelect, Qt.LeftButton)
    assert not tabAuto.autoSelect.isChecked()

    qtbot.wait(keyDelay)
    assert tabAuto.doReplace.isChecked()
    qtbot.mouseClick(tabAuto.doReplace, Qt.LeftButton)
    assert not tabAuto.doReplace.isChecked()

    qtbot.wait(keyDelay)
    assert not tabAuto.doReplaceSQuote.isEnabled()
    assert not tabAuto.doReplaceDQuote.isEnabled()
    assert not tabAuto.doReplaceDash.isEnabled()
    assert not tabAuto.doReplaceDots.isEnabled()

    # Quotation Style
    qtbot.wait(keyDelay)
    tabQuote = nwPrefs.tabQuote
    nwPrefs._tabBox.setCurrentWidget(tabQuote)

    monkeypatch.setattr(GuiQuoteSelect, "selectedQuote", "'")
    monkeypatch.setattr(GuiQuoteSelect, "exec_",
                        lambda *args: QDialog.Accepted)
    qtbot.mouseClick(tabQuote.btnDoubleStyleC, Qt.LeftButton)

    # Save and Check Config
    qtbot.mouseClick(nwPrefs.buttonBox.button(QDialogButtonBox.Ok),
                     Qt.LeftButton)
    nwPrefs._doClose()

    assert theConf.confChanged
    theConf.lastPath = ""

    assert nwGUI.mainConf.saveConfig()
    projFile = os.path.join(fncDir, "novelwriter.conf")
    testFile = os.path.join(outDir, "guiPreferences_novelwriter.conf")
    compFile = os.path.join(refDir, "guiPreferences_novelwriter.conf")
    copyfile(projFile, testFile)
    ignTuple = ("timestamp", "guifont", "lastnotes", "guilang", "geometry",
                "preferences", "treecols", "novelcols", "projcols", "mainpane",
                "docpane", "viewpane", "outlinepane", "textfont", "textsize")
    assert cmpFiles(testFile, compFile, ignoreStart=ignTuple)

    # Clean up
    novelwriter.CONFIG = origConf
    nwGUI.closeMain()
예제 #19
0
def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncProj):
    """Test the merge documents tool.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Ok)

    # Create a new project
    nwGUI.theProject.projTree.setSeed(42)
    assert nwGUI.newProject({"projPath": fncProj})

    # Handles for new objects
    hChapterDir = "31489056e0916"
    hChapterOne = "98010bd9270f9"
    hSceneOne   = "0e17daca5f3e1"
    hSceneTwo   = "1a6562590ef19"
    hSceneThree = "031b4af5197ec"
    hSceneFour  = "41cfc0d1f2d12"
    hMergedDoc  = "2858dcd1057d3"

    # Add Project Content
    monkeypatch.setattr(GuiItemEditor, "exec_", lambda *a: QDialog.Accepted)
    nwGUI.switchFocus(nwWidget.TREE)
    nwGUI.treeView.clearSelection()
    nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True)
    nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
    nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
    nwGUI.treeView.newTreeItem(nwItemType.FILE, None)

    assert nwGUI.saveProject() is True
    assert nwGUI.closeProject() is True

    tChapterOne = "## Chapter One\n\n% Chapter one comment\n"
    tSceneOne   = "### Scene One\n\nThere once was a man from Nantucket"
    tSceneTwo   = "### Scene Two\n\nWho kept all his cash in a bucket."
    tSceneThree = "### Scene Three\n\n\tBut his daughter, named Nan,  \n\tRan away with a man"
    tSceneFour  = "### Scene Four\n\nAnd as for the bucket, Nantucket."

    contentDir = os.path.join(fncProj, "content")
    writeFile(os.path.join(contentDir, hChapterOne+".nwd"), tChapterOne)
    writeFile(os.path.join(contentDir, hSceneOne+".nwd"), tSceneOne)
    writeFile(os.path.join(contentDir, hSceneTwo+".nwd"), tSceneTwo)
    writeFile(os.path.join(contentDir, hSceneThree+".nwd"), tSceneThree)
    writeFile(os.path.join(contentDir, hSceneFour+".nwd"), tSceneFour)

    assert nwGUI.openProject(fncProj) is True

    # Open the Merge tool
    nwGUI.switchFocus(nwWidget.TREE)
    nwGUI.treeView.clearSelection()
    nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True)

    monkeypatch.setattr(GuiDocMerge, "exec_", lambda *a: None)
    nwGUI.mainMenu.aMergeDocs.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiDocMerge") is not None, timeout=1000)

    nwMerge = getGuiItem("GuiDocMerge")
    assert isinstance(nwMerge, GuiDocMerge)
    nwMerge.show()
    qtbot.wait(50)

    # Populate List
    # =============

    nwMerge.listBox.clear()
    assert nwMerge.listBox.count() == 0

    # No item selected
    nwGUI.treeView.clearSelection()
    assert nwMerge._populateList() is False
    assert nwMerge.listBox.count() == 0

    # Non-existing item
    with monkeypatch.context() as mp:
        mp.setattr(NWTree, "__getitem__", lambda *a: None)
        nwGUI.treeView.clearSelection()
        nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True)
        assert nwMerge._populateList() is False
        assert nwMerge.listBox.count() == 0

    # Select a non-folder
    nwGUI.treeView.clearSelection()
    nwGUI.treeView._getTreeItem(hChapterOne).setSelected(True)
    assert nwMerge._populateList() is False
    assert nwMerge.listBox.count() == 0

    # Select the chapter folder
    nwGUI.treeView.clearSelection()
    nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True)
    assert nwMerge._populateList() is True
    assert nwMerge.listBox.count() == 5

    # Merge Documents
    # ===============

    # First, a successful merge
    with monkeypatch.context() as mp:
        mp.setattr(GuiDocMerge, "_doClose", lambda *a: None)
        assert nwMerge._doMerge() is True
        assert nwGUI.saveProject() is True
        mergedFile = os.path.join(contentDir, hMergedDoc+".nwd")
        assert os.path.isfile(mergedFile)
        assert readFile(mergedFile) == (
            "%%%%~name: New Chapter\n"
            "%%%%~path: 73475cb40a568/2858dcd1057d3\n"
            "%%%%~kind: NOVEL/DOCUMENT\n"
            "%s\n\n"
            "%s\n\n"
            "%s\n\n"
            "%s\n\n"
            "%s\n\n"
        ) % (
            tChapterOne.strip(),
            tSceneOne.strip(),
            tSceneTwo.strip(),
            tSceneThree.strip(),
            tSceneFour.strip(),
        )

    # OS error
    with monkeypatch.context() as mp:
        mp.setattr("builtins.open", causeOSError)
        assert nwMerge._doMerge() is False

    # Can't find the source item
    with monkeypatch.context() as mp:
        mp.setattr(NWTree, "__getitem__", lambda *a: None)
        assert nwMerge._doMerge() is False

    # No source handle set
    nwMerge.sourceItem = None
    assert nwMerge._doMerge() is False

    # No documents to merge
    nwMerge.listBox.clear()
    assert nwMerge._doMerge() is False

    # Close up
    nwMerge._doClose()
예제 #20
0
def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj):
    """Test the full writing stats tool.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "warning", lambda *a: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Yes)

    # Create a project to work on
    assert nwGUI.newProject({"projPath": fncProj})
    qtbot.wait(100)
    assert nwGUI.saveProject()
    sessFile = os.path.join(fncProj, "meta", nwFiles.SESS_STATS)

    # Open the Writing Stats dialog
    nwGUI.mainConf.lastPath = ""
    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)

    # Test Loading
    # ============

    # No initial logfile
    assert not os.path.isfile(sessFile)
    assert not sessLog._loadLogFile()

    # Make a test log file
    writeFile(sessFile, (
        "# Offset 123\n"
        "# Start Time         End Time                Novel     Notes      Idle\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"))
    assert os.path.isfile(sessFile)
    assert sessLog._loadLogFile()
    assert sessLog.wordOffset == 123
    assert len(sessLog.logData) == 4

    # Make sure a faulty file can still be read
    writeFile(sessFile, (
        "# Offset abc123\n"
        "# Start Time         End Time                Novel     Notes      Idle\n"
        "2020-01-01 21:00:00  2020-01-01 21:00:05         6         0        50\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\n"))
    assert sessLog._loadLogFile()
    assert sessLog.wordOffset == 0
    assert len(sessLog.logData) == 3

    # Test Exporting
    # ==============

    writeFile(sessFile, (
        "# Offset 1075\n"
        "# Start Time         End Time                Novel     Notes      Idle\n"
        "2021-01-31 19:00:00  2021-01-31 19:30:00       700       375         0\n"
        "2021-02-01 19:00:00  2021-02-01 19:30:00       700       375        10\n"
        "2021-02-01 20:00:00  2021-02-01 20:30:00       600       275        20\n"
        "2021-02-02 19:00:00  2021-02-02 19:30:00       750       425        30\n"
        "2021-02-02 20:00:00  2021-02-02 20:30:00       690       365        40\n"
        "2021-02-03 19:00:00  2021-02-03 19:30:00       680       355        50\n"
        "2021-02-04 19:00:00  2021-02-04 19:30:00       700       375        60\n"
        "2021-02-05 19:00:00  2021-02-05 19:30:00       500       175        70\n"
        "2021-02-06 19:00:00  2021-02-06 19:30:00       600       275        80\n"
        "2021-02-07 19:00:00  2021-02-07 19:30:00       600       275        90\n"
    ))
    sessLog.populateGUI()

    # Make the saving fail
    monkeypatch.setattr(QFileDialog, "getSaveFileName", lambda *a, **k:
                        ("", ""))
    assert not sessLog._saveData(sessLog.FMT_CSV)
    assert not sessLog._saveData(sessLog.FMT_JSON)
    assert not sessLog._saveData(None)

    # Make the save succeed
    monkeypatch.setattr("os.path.expanduser", lambda *a: fncDir)
    monkeypatch.setattr(QFileDialog, "getSaveFileName",
                        lambda ss, tt, pp, options: (pp, ""))

    sessLog.listBox.sortByColumn(sessLog.C_TIME, 0)

    assert sessLog.novelWords.text() == "{:n}".format(600)
    assert sessLog.notesWords.text() == "{:n}".format(275)
    assert sessLog.totalWords.text() == "{:n}".format(875)

    assert sessLog.listBox.topLevelItem(0).text(
        sessLog.C_COUNT) == "{:n}".format(1)
    assert sessLog.listBox.topLevelItem(1).text(
        sessLog.C_COUNT) == "{:n}".format(-200)
    assert sessLog.listBox.topLevelItem(2).text(
        sessLog.C_COUNT) == "{:n}".format(300)
    assert sessLog.listBox.topLevelItem(3).text(
        sessLog.C_COUNT) == "{:n}".format(-120)
    assert sessLog.listBox.topLevelItem(4).text(
        sessLog.C_COUNT) == "{:n}".format(-20)
    assert sessLog.listBox.topLevelItem(5).text(
        sessLog.C_COUNT) == "{:n}".format(40)
    assert sessLog.listBox.topLevelItem(6).text(
        sessLog.C_COUNT) == "{:n}".format(-400)
    assert sessLog.listBox.topLevelItem(7).text(
        sessLog.C_COUNT) == "{:n}".format(200)

    assert sessLog._saveData(sessLog.FMT_CSV)
    qtbot.wait(100)

    assert sessLog._saveData(sessLog.FMT_JSON)
    qtbot.wait(100)

    assert nwGUI.mainConf.lastPath == fncDir

    # Check the exported files
    jsonStats = os.path.join(fncDir, "sessionStats.json")
    with open(jsonStats, mode="r", encoding="utf-8") as inFile:
        jsonData = json.load(inFile)

    assert jsonData == [{
        "date": "2021-01-31 19:00:00",
        "length": 1800.0,
        "newWords": 1,
        "novelWords": 700,
        "noteWords": 375,
        "idleTime": 0
    }, {
        "date": "2021-02-01 20:00:00",
        "length": 1800.0,
        "newWords": -200,
        "novelWords": 600,
        "noteWords": 275,
        "idleTime": 20
    }, {
        "date": "2021-02-02 19:00:00",
        "length": 1800.0,
        "newWords": 300,
        "novelWords": 750,
        "noteWords": 425,
        "idleTime": 30
    }, {
        "date": "2021-02-02 20:00:00",
        "length": 1800.0,
        "newWords": -120,
        "novelWords": 690,
        "noteWords": 365,
        "idleTime": 40
    }, {
        "date": "2021-02-03 19:00:00",
        "length": 1800.0,
        "newWords": -20,
        "novelWords": 680,
        "noteWords": 355,
        "idleTime": 50
    }, {
        "date": "2021-02-04 19:00:00",
        "length": 1800.0,
        "newWords": 40,
        "novelWords": 700,
        "noteWords": 375,
        "idleTime": 60
    }, {
        "date": "2021-02-05 19:00:00",
        "length": 1800.0,
        "newWords": -400,
        "novelWords": 500,
        "noteWords": 175,
        "idleTime": 70
    }, {
        "date": "2021-02-06 19:00:00",
        "length": 1800.0,
        "newWords": 200,
        "novelWords": 600,
        "noteWords": 275,
        "idleTime": 80
    }]

    # Test Filters
    # ============

    # 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(fncDir, "sessionStats.json")
    with open(jsonStats, mode="r", encoding="utf-8") as inFile:
        jsonData = json.loads(inFile.read())

    assert sessLog.listBox.topLevelItem(0).text(
        sessLog.C_COUNT) == "{:n}".format(1)
    assert sessLog.listBox.topLevelItem(1).text(
        sessLog.C_COUNT) == "{:n}".format(-100)
    assert sessLog.listBox.topLevelItem(2).text(
        sessLog.C_COUNT) == "{:n}".format(150)
    assert sessLog.listBox.topLevelItem(3).text(
        sessLog.C_COUNT) == "{:n}".format(-60)
    assert sessLog.listBox.topLevelItem(4).text(
        sessLog.C_COUNT) == "{:n}".format(-10)
    assert sessLog.listBox.topLevelItem(5).text(
        sessLog.C_COUNT) == "{:n}".format(20)
    assert sessLog.listBox.topLevelItem(6).text(
        sessLog.C_COUNT) == "{:n}".format(-200)
    assert sessLog.listBox.topLevelItem(7).text(
        sessLog.C_COUNT) == "{:n}".format(100)

    assert jsonData == [{
        "date": "2021-01-31 19:00:00",
        "length": 1800.0,
        "newWords": 1,
        "novelWords": 700,
        "noteWords": 375,
        "idleTime": 0
    }, {
        "date": "2021-02-01 20:00:00",
        "length": 1800.0,
        "newWords": -100,
        "novelWords": 600,
        "noteWords": 275,
        "idleTime": 20
    }, {
        "date": "2021-02-02 19:00:00",
        "length": 1800.0,
        "newWords": 150,
        "novelWords": 750,
        "noteWords": 425,
        "idleTime": 30
    }, {
        "date": "2021-02-02 20:00:00",
        "length": 1800.0,
        "newWords": -60,
        "novelWords": 690,
        "noteWords": 365,
        "idleTime": 40
    }, {
        "date": "2021-02-03 19:00:00",
        "length": 1800.0,
        "newWords": -10,
        "novelWords": 680,
        "noteWords": 355,
        "idleTime": 50
    }, {
        "date": "2021-02-04 19:00:00",
        "length": 1800.0,
        "newWords": 20,
        "novelWords": 700,
        "noteWords": 375,
        "idleTime": 60
    }, {
        "date": "2021-02-05 19:00:00",
        "length": 1800.0,
        "newWords": -200,
        "novelWords": 500,
        "noteWords": 175,
        "idleTime": 70
    }, {
        "date": "2021-02-06 19:00:00",
        "length": 1800.0,
        "newWords": 100,
        "novelWords": 600,
        "noteWords": 275,
        "idleTime": 80
    }]

    # 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(fncDir, "sessionStats.json")
    with open(jsonStats, mode="r", encoding="utf-8") as inFile:
        jsonData = json.load(inFile)

    assert sessLog.listBox.topLevelItem(0).text(
        sessLog.C_COUNT) == "{:n}".format(1)
    assert sessLog.listBox.topLevelItem(1).text(
        sessLog.C_COUNT) == "{:n}".format(-100)
    assert sessLog.listBox.topLevelItem(2).text(
        sessLog.C_COUNT) == "{:n}".format(150)
    assert sessLog.listBox.topLevelItem(3).text(
        sessLog.C_COUNT) == "{:n}".format(-60)
    assert sessLog.listBox.topLevelItem(4).text(
        sessLog.C_COUNT) == "{:n}".format(-10)
    assert sessLog.listBox.topLevelItem(5).text(
        sessLog.C_COUNT) == "{:n}".format(20)
    assert sessLog.listBox.topLevelItem(6).text(
        sessLog.C_COUNT) == "{:n}".format(-200)
    assert sessLog.listBox.topLevelItem(7).text(
        sessLog.C_COUNT) == "{:n}".format(100)

    assert jsonData == [{
        "date": "2021-01-31 19:00:00",
        "length": 1800.0,
        "newWords": 1,
        "novelWords": 700,
        "noteWords": 375,
        "idleTime": 0
    }, {
        "date": "2021-02-01 20:00:00",
        "length": 1800.0,
        "newWords": -100,
        "novelWords": 600,
        "noteWords": 275,
        "idleTime": 20
    }, {
        "date": "2021-02-02 19:00:00",
        "length": 1800.0,
        "newWords": 150,
        "novelWords": 750,
        "noteWords": 425,
        "idleTime": 30
    }, {
        "date": "2021-02-02 20:00:00",
        "length": 1800.0,
        "newWords": -60,
        "novelWords": 690,
        "noteWords": 365,
        "idleTime": 40
    }, {
        "date": "2021-02-03 19:00:00",
        "length": 1800.0,
        "newWords": -10,
        "novelWords": 680,
        "noteWords": 355,
        "idleTime": 50
    }, {
        "date": "2021-02-04 19:00:00",
        "length": 1800.0,
        "newWords": 20,
        "novelWords": 700,
        "noteWords": 375,
        "idleTime": 60
    }, {
        "date": "2021-02-05 19:00:00",
        "length": 1800.0,
        "newWords": -200,
        "novelWords": 500,
        "noteWords": 175,
        "idleTime": 70
    }, {
        "date": "2021-02-06 19:00:00",
        "length": 1800.0,
        "newWords": 100,
        "novelWords": 600,
        "noteWords": 275,
        "idleTime": 80
    }]

    # 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)

    # qtbot.stopForInteraction()

    jsonStats = os.path.join(fncDir, "sessionStats.json")
    with open(jsonStats, mode="r", encoding="utf-8") as inFile:
        jsonData = json.load(inFile)

    assert sessLog.listBox.topLevelItem(0).text(
        sessLog.C_COUNT) == "{:n}".format(1)
    assert sessLog.listBox.topLevelItem(1).text(
        sessLog.C_COUNT) == "{:n}".format(300)
    assert sessLog.listBox.topLevelItem(2).text(
        sessLog.C_COUNT) == "{:n}".format(40)
    assert sessLog.listBox.topLevelItem(3).text(
        sessLog.C_COUNT) == "{:n}".format(200)

    assert jsonData == [{
        "date": "2021-01-31 19:00:00",
        "length": 1800.0,
        "newWords": 1,
        "novelWords": 700,
        "noteWords": 375,
        "idleTime": 0
    }, {
        "date": "2021-02-02 19:00:00",
        "length": 1800.0,
        "newWords": 300,
        "novelWords": 750,
        "noteWords": 425,
        "idleTime": 30
    }, {
        "date": "2021-02-04 19:00:00",
        "length": 1800.0,
        "newWords": 40,
        "novelWords": 700,
        "noteWords": 375,
        "idleTime": 60
    }, {
        "date": "2021-02-06 19:00:00",
        "length": 1800.0,
        "newWords": 200,
        "novelWords": 600,
        "noteWords": 275,
        "idleTime": 80
    }]

    # 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(fncDir, "sessionStats.json")
    with open(jsonStats, mode="r", encoding="utf-8") as inFile:
        jsonData = json.load(inFile)

    assert sessLog.listBox.topLevelItem(0).text(
        sessLog.C_COUNT) == "{:n}".format(1)
    assert sessLog.listBox.topLevelItem(1).text(
        sessLog.C_COUNT) == "{:n}".format(0)
    assert sessLog.listBox.topLevelItem(2).text(
        sessLog.C_COUNT) == "{:n}".format(-200)
    assert sessLog.listBox.topLevelItem(3).text(
        sessLog.C_COUNT) == "{:n}".format(300)
    assert sessLog.listBox.topLevelItem(4).text(
        sessLog.C_COUNT) == "{:n}".format(-120)
    assert sessLog.listBox.topLevelItem(5).text(
        sessLog.C_COUNT) == "{:n}".format(-20)
    assert sessLog.listBox.topLevelItem(6).text(
        sessLog.C_COUNT) == "{:n}".format(40)
    assert sessLog.listBox.topLevelItem(7).text(
        sessLog.C_COUNT) == "{:n}".format(-400)
    assert sessLog.listBox.topLevelItem(8).text(
        sessLog.C_COUNT) == "{:n}".format(200)
    assert sessLog.listBox.topLevelItem(9).text(
        sessLog.C_COUNT) == "{:n}".format(0)

    assert jsonData == [{
        "date": "2021-01-31 19:00:00",
        "length": 1800.0,
        "newWords": 1,
        "novelWords": 700,
        "noteWords": 375,
        "idleTime": 0
    }, {
        "date": "2021-02-01 19:00:00",
        "length": 1800.0,
        "newWords": 0,
        "novelWords": 700,
        "noteWords": 375,
        "idleTime": 10
    }, {
        "date": "2021-02-01 20:00:00",
        "length": 1800.0,
        "newWords": -200,
        "novelWords": 600,
        "noteWords": 275,
        "idleTime": 20
    }, {
        "date": "2021-02-02 19:00:00",
        "length": 1800.0,
        "newWords": 300,
        "novelWords": 750,
        "noteWords": 425,
        "idleTime": 30
    }, {
        "date": "2021-02-02 20:00:00",
        "length": 1800.0,
        "newWords": -120,
        "novelWords": 690,
        "noteWords": 365,
        "idleTime": 40
    }, {
        "date": "2021-02-03 19:00:00",
        "length": 1800.0,
        "newWords": -20,
        "novelWords": 680,
        "noteWords": 355,
        "idleTime": 50
    }, {
        "date": "2021-02-04 19:00:00",
        "length": 1800.0,
        "newWords": 40,
        "novelWords": 700,
        "noteWords": 375,
        "idleTime": 60
    }, {
        "date": "2021-02-05 19:00:00",
        "length": 1800.0,
        "newWords": -400,
        "novelWords": 500,
        "noteWords": 175,
        "idleTime": 70
    }, {
        "date": "2021-02-06 19:00:00",
        "length": 1800.0,
        "newWords": 200,
        "novelWords": 600,
        "noteWords": 275,
        "idleTime": 80
    }, {
        "date": "2021-02-07 19:00:00",
        "length": 1800.0,
        "newWords": 0,
        "novelWords": 600,
        "noteWords": 275,
        "idleTime": 90
    }]

    # 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(fncDir, "sessionStats.json")
    with open(jsonStats, mode="r", encoding="utf-8") as inFile:
        jsonData = json.load(inFile)

    assert sessLog.listBox.topLevelItem(0).text(
        sessLog.C_COUNT) == "{:n}".format(1)
    assert sessLog.listBox.topLevelItem(1).text(
        sessLog.C_COUNT) == "{:n}".format(-200)
    assert sessLog.listBox.topLevelItem(2).text(
        sessLog.C_COUNT) == "{:n}".format(180)
    assert sessLog.listBox.topLevelItem(3).text(
        sessLog.C_COUNT) == "{:n}".format(-20)
    assert sessLog.listBox.topLevelItem(4).text(
        sessLog.C_COUNT) == "{:n}".format(40)
    assert sessLog.listBox.topLevelItem(5).text(
        sessLog.C_COUNT) == "{:n}".format(-400)
    assert sessLog.listBox.topLevelItem(6).text(
        sessLog.C_COUNT) == "{:n}".format(200)
    assert sessLog.listBox.topLevelItem(7).text(
        sessLog.C_COUNT) == "{:n}".format(0)

    assert jsonData == [{
        "date": "2021-01-31",
        "length": 1800.0,
        "newWords": 1,
        "novelWords": 700,
        "noteWords": 375,
        "idleTime": 0
    }, {
        "date": "2021-02-01",
        "length": 3600.0,
        "newWords": -200,
        "novelWords": 600,
        "noteWords": 275,
        "idleTime": 30
    }, {
        "date": "2021-02-02",
        "length": 3600.0,
        "newWords": 180,
        "novelWords": 690,
        "noteWords": 365,
        "idleTime": 70
    }, {
        "date": "2021-02-03",
        "length": 1800.0,
        "newWords": -20,
        "novelWords": 680,
        "noteWords": 355,
        "idleTime": 50
    }, {
        "date": "2021-02-04",
        "length": 1800.0,
        "newWords": 40,
        "novelWords": 700,
        "noteWords": 375,
        "idleTime": 60
    }, {
        "date": "2021-02-05",
        "length": 1800.0,
        "newWords": -400,
        "novelWords": 500,
        "noteWords": 175,
        "idleTime": 70
    }, {
        "date": "2021-02-06",
        "length": 1800.0,
        "newWords": 200,
        "novelWords": 600,
        "noteWords": 275,
        "idleTime": 80
    }, {
        "date": "2021-02-07",
        "length": 1800.0,
        "newWords": 0,
        "novelWords": 600,
        "noteWords": 275,
        "idleTime": 90
    }]

    # IOError
    # =======
    monkeypatch.setattr("builtins.open", causeOSError)
    assert not sessLog._loadLogFile()
    assert not sessLog._saveData(sessLog.FMT_CSV)

    # qtbot.stopForInteraction()

    sessLog._doClose()
    assert nwGUI.closeProject()
    qtbot.wait(stepDelay)
예제 #21
0
def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, fncProj):
    """Test the split document tool.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Ok)

    # Create a new project
    nwGUI.theProject.projTree.setSeed(42)
    assert nwGUI.newProject({"projPath": fncProj}) is True

    # Handles for new objects
    hNovelRoot  = "73475cb40a568"
    hChapterDir = "31489056e0916"
    hToSplit    = "1a6562590ef19"
    hPartition  = "41cfc0d1f2d12"
    hChapterOne = "2858dcd1057d3"
    hSceneOne   = "2fca346db6561"
    hSceneTwo   = "02d20bbd7e394"
    hSceneThree = "7688b6ef52555"
    hSceneFour  = "c837649cce43f"
    hSceneFive  = "6208ef0f7750c"

    # Add Project Content
    monkeypatch.setattr(GuiItemEditor, "exec_", lambda *a: QDialog.Accepted)
    nwGUI.switchFocus(nwWidget.TREE)
    nwGUI.treeView.clearSelection()
    nwGUI.treeView._getTreeItem(hNovelRoot).setSelected(True)
    nwGUI.treeView.newTreeItem(nwItemType.FILE, None)

    assert nwGUI.saveProject() is True
    assert nwGUI.closeProject() is True

    tPartition  = "# Nantucket"
    tChapterOne = "## Chapter One\n\n% Chapter one comment"
    tSceneOne   = "### Scene One\n\nThere once was a man from Nantucket"
    tSceneTwo   = "### Scene Two\n\nWho kept all his cash in a bucket."
    tSceneThree = "### Scene Three\n\n\tBut his daughter, named Nan,  \n\tRan away with a man"
    tSceneFour  = "### Scene Four\n\nAnd as for the bucket, Nantucket."
    tSceneFive  = "#### The End\n\nend"

    tToSplit = (
        f"{tPartition}\n\n{tChapterOne}\n\n"
        f"{tSceneOne}\n\n{tSceneTwo}\n\n"
        f"{tSceneThree}\n\n{tSceneFour}\n\n"
        f"{tSceneFive}\n\n"
    )

    contentDir = os.path.join(fncProj, "content")
    writeFile(os.path.join(contentDir, hToSplit+".nwd"), tToSplit)

    assert nwGUI.openProject(fncProj) is True

    # Open the Split tool
    nwGUI.switchFocus(nwWidget.TREE)
    nwGUI.treeView.clearSelection()
    nwGUI.treeView._getTreeItem(hToSplit).setSelected(True)

    monkeypatch.setattr(GuiDocSplit, "exec_", lambda *a: None)
    nwGUI.mainMenu.aSplitDoc.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiDocSplit") is not None, timeout=1000)

    nwSplit = getGuiItem("GuiDocSplit")
    assert isinstance(nwSplit, GuiDocSplit)
    nwSplit.show()
    qtbot.wait(50)

    # Populate List
    # =============

    nwSplit.listBox.clear()
    assert nwSplit.listBox.count() == 0

    # No item selected
    nwSplit.sourceItem = None
    nwGUI.treeView.clearSelection()
    assert nwSplit._populateList() is False
    assert nwSplit.listBox.count() == 0

    # Non-existing item
    with monkeypatch.context() as mp:
        mp.setattr(NWTree, "__getitem__", lambda *a: None)
        nwSplit.sourceItem = None
        nwGUI.treeView.clearSelection()
        nwGUI.treeView._getTreeItem(hToSplit).setSelected(True)
        assert nwSplit._populateList() is False
        assert nwSplit.listBox.count() == 0

    # Select a non-file
    nwSplit.sourceItem = None
    nwGUI.treeView.clearSelection()
    nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True)
    assert nwSplit._populateList() is False
    assert nwSplit.listBox.count() == 0

    # Error when reading documents
    with monkeypatch.context() as mp:
        mp.setattr(NWDoc, "readDocument", lambda *a: None)
        nwSplit.sourceItem = hToSplit
        assert nwSplit._populateList() is False
        assert nwSplit.listBox.count() == 0

    # Read properly, and check split levels

    # Level 1
    nwSplit.splitLevel.setCurrentIndex(0)
    nwSplit.sourceItem = hToSplit
    assert nwSplit._populateList() is True
    assert nwSplit.listBox.count() == 1

    # Level 2
    nwSplit.splitLevel.setCurrentIndex(1)
    nwSplit.sourceItem = hToSplit
    assert nwSplit._populateList() is True
    assert nwSplit.listBox.count() == 2

    # Level 3
    nwSplit.splitLevel.setCurrentIndex(2)
    nwSplit.sourceItem = hToSplit
    assert nwSplit._populateList() is True
    assert nwSplit.listBox.count() == 6

    # Level 4
    nwSplit.splitLevel.setCurrentIndex(3)
    nwSplit.sourceItem = hToSplit
    assert nwSplit._populateList() is True
    assert nwSplit.listBox.count() == 7

    # Split Document
    # ==============

    # Test a proper split first
    with monkeypatch.context() as mp:
        mp.setattr(GuiDocSplit, "_doClose", lambda *a: None)
        assert nwSplit._doSplit() is True
        assert nwGUI.saveProject()

        assert readFile(os.path.join(contentDir, hPartition+".nwd")) == (
            "%%%%~name: Nantucket\n"
            "%%%%~path: 031b4af5197ec/%s\n"
            "%%%%~kind: NOVEL/DOCUMENT\n"
            "%s\n\n"
        ) % (hPartition, tPartition)

        assert readFile(os.path.join(contentDir, hChapterOne+".nwd")) == (
            "%%%%~name: Chapter One\n"
            "%%%%~path: 031b4af5197ec/%s\n"
            "%%%%~kind: NOVEL/DOCUMENT\n"
            "%s\n\n"
        ) % (hChapterOne, tChapterOne)

        assert readFile(os.path.join(contentDir, hSceneOne+".nwd")) == (
            "%%%%~name: Scene One\n"
            "%%%%~path: 031b4af5197ec/%s\n"
            "%%%%~kind: NOVEL/DOCUMENT\n"
            "%s\n\n"
        ) % (hSceneOne, tSceneOne)

        assert readFile(os.path.join(contentDir, hSceneTwo+".nwd")) == (
            "%%%%~name: Scene Two\n"
            "%%%%~path: 031b4af5197ec/%s\n"
            "%%%%~kind: NOVEL/DOCUMENT\n"
            "%s\n\n"
        ) % (hSceneTwo, tSceneTwo)

        assert readFile(os.path.join(contentDir, hSceneThree+".nwd")) == (
            "%%%%~name: Scene Three\n"
            "%%%%~path: 031b4af5197ec/%s\n"
            "%%%%~kind: NOVEL/DOCUMENT\n"
            "%s\n\n"
        ) % (hSceneThree, tSceneThree)

        assert readFile(os.path.join(contentDir, hSceneFour+".nwd")) == (
            "%%%%~name: Scene Four\n"
            "%%%%~path: 031b4af5197ec/%s\n"
            "%%%%~kind: NOVEL/DOCUMENT\n"
            "%s\n\n"
        ) % (hSceneFour, tSceneFour)

        assert readFile(os.path.join(contentDir, hSceneFive+".nwd")) == (
            "%%%%~name: The End\n"
            "%%%%~path: 031b4af5197ec/%s\n"
            "%%%%~kind: NOVEL/DOCUMENT\n"
            "%s\n\n"
        ) % (hSceneFive, tSceneFive)

    # OS error
    with monkeypatch.context() as mp:
        mp.setattr("builtins.open", causeOSError)
        assert nwSplit._doSplit() is False

    # Select to not split
    with monkeypatch.context() as mp:
        mp.setattr(QMessageBox, "question", lambda *a: QMessageBox.No)
        assert nwSplit._doSplit() is False

    # Block folder creation by returning that the folder has a depth
    # of 50 items in the tree
    with monkeypatch.context() as mp:
        mp.setattr(NWTree, "getItemPath", lambda *a: [""]*50)
        assert nwSplit._doSplit() is False

    # Clear the list
    nwSplit.listBox.clear()
    assert nwSplit._doSplit() is False

    # Can't find sourcv item
    with monkeypatch.context() as mp:
        mp.setattr(NWTree, "__getitem__", lambda *a: None)
        assert nwSplit._doSplit() is False

    # No source item set
    nwSplit.sourceItem = None
    assert nwSplit._doSplit() is False

    # Close
    nwSplit._doClose()
예제 #22
0
def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
    """Test the split document tool.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Ok)
    monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text:
                        (text, True))

    # Create a new project
    buildTestProject(nwGUI, fncProj)

    # Handles for new objects
    hNovelRoot = "0000000000008"
    hChapterDir = "000000000000d"
    hToSplit = "0000000000010"
    hNewFolder = "0000000000021"
    hPartition = "0000000000022"
    hChapterOne = "0000000000023"
    hSceneOne = "0000000000024"
    hSceneTwo = "0000000000025"
    hSceneThree = "0000000000026"
    hSceneFour = "0000000000027"
    hSceneFive = "0000000000028"

    # Add Project Content
    nwGUI.switchFocus(nwWidget.TREE)
    nwGUI.projView.projTree.clearSelection()
    nwGUI.projView.projTree._getTreeItem(hNovelRoot).setSelected(True)
    nwGUI.projView.projTree.newTreeItem(nwItemType.FILE)

    assert nwGUI.saveProject() is True
    assert nwGUI.closeProject() is True

    tPartition = "# Nantucket"
    tChapterOne = "## Chapter One\n\n% Chapter one comment"
    tSceneOne = "### Scene One\n\nThere once was a man from Nantucket"
    tSceneTwo = "### Scene Two\n\nWho kept all his cash in a bucket."
    tSceneThree = "### Scene Three\n\n\tBut his daughter, named Nan,  \n\tRan away with a man"
    tSceneFour = "### Scene Four\n\nAnd as for the bucket, Nantucket."
    tSceneFive = "#### The End\n\nend"

    tToSplit = (f"{tPartition}\n\n{tChapterOne}\n\n"
                f"{tSceneOne}\n\n{tSceneTwo}\n\n"
                f"{tSceneThree}\n\n{tSceneFour}\n\n"
                f"{tSceneFive}\n\n")

    contentDir = os.path.join(fncProj, "content")
    writeFile(os.path.join(contentDir, hToSplit + ".nwd"), tToSplit)

    assert nwGUI.openProject(fncProj) is True

    # Open the Split tool
    nwGUI.switchFocus(nwWidget.TREE)
    nwGUI.projView.projTree.clearSelection()
    nwGUI.projView.projTree._getTreeItem(hToSplit).setSelected(True)

    monkeypatch.setattr(GuiDocSplit, "exec_", lambda *a: None)
    nwGUI.mainMenu.aSplitDoc.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiDocSplit") is not None,
                    timeout=1000)

    nwSplit = getGuiItem("GuiDocSplit")
    assert isinstance(nwSplit, GuiDocSplit)
    nwSplit.show()
    qtbot.wait(50)

    # Populate List
    # =============

    nwSplit.listBox.clear()
    assert nwSplit.listBox.count() == 0

    # No item selected
    nwSplit.sourceItem = None
    nwGUI.projView.projTree.clearSelection()
    assert nwSplit._populateList() is False
    assert nwSplit.listBox.count() == 0

    # Non-existing item
    with monkeypatch.context() as mp:
        mp.setattr(NWTree, "__getitem__", lambda *a: None)
        nwSplit.sourceItem = None
        nwGUI.projView.projTree.clearSelection()
        nwGUI.projView.projTree._getTreeItem(hToSplit).setSelected(True)
        assert nwSplit._populateList() is False
        assert nwSplit.listBox.count() == 0

    # Select a non-file
    nwSplit.sourceItem = None
    nwGUI.projView.projTree.clearSelection()
    nwGUI.projView.projTree._getTreeItem(hChapterDir).setSelected(True)
    assert nwSplit._populateList() is False
    assert nwSplit.listBox.count() == 0

    # Error when reading documents
    with monkeypatch.context() as mp:
        mp.setattr(NWDoc, "readDocument", lambda *a: None)
        nwSplit.sourceItem = hToSplit
        assert nwSplit._populateList() is False
        assert nwSplit.listBox.count() == 0

    # Read properly, and check split levels

    # Level 1
    nwSplit.splitLevel.setCurrentIndex(0)
    nwSplit.sourceItem = hToSplit
    assert nwSplit._populateList() is True
    assert nwSplit.listBox.count() == 1

    # Level 2
    nwSplit.splitLevel.setCurrentIndex(1)
    nwSplit.sourceItem = hToSplit
    assert nwSplit._populateList() is True
    assert nwSplit.listBox.count() == 2

    # Level 3
    nwSplit.splitLevel.setCurrentIndex(2)
    nwSplit.sourceItem = hToSplit
    assert nwSplit._populateList() is True
    assert nwSplit.listBox.count() == 6

    # Level 4
    nwSplit.splitLevel.setCurrentIndex(3)
    nwSplit.sourceItem = hToSplit
    assert nwSplit._populateList() is True
    assert nwSplit.listBox.count() == 7

    # Split Document
    # ==============

    # Test a proper split first
    with monkeypatch.context() as mp:
        mp.setattr(GuiDocSplit, "_doClose", lambda *a: None)
        assert nwSplit._doSplit() is True
        assert nwGUI.saveProject()

        assert readFile(os.path.join(
            contentDir, hPartition +
            ".nwd")) == ("%%%%~name: Nantucket\n"
                         "%%%%~path: %s/%s\n"
                         "%%%%~kind: NOVEL/DOCUMENT\n"
                         "%s\n\n") % (hNewFolder, hPartition, tPartition)

        assert readFile(os.path.join(
            contentDir, hChapterOne +
            ".nwd")) == ("%%%%~name: Chapter One\n"
                         "%%%%~path: %s/%s\n"
                         "%%%%~kind: NOVEL/DOCUMENT\n"
                         "%s\n\n") % (hNewFolder, hChapterOne, tChapterOne)

        assert readFile(os.path.join(
            contentDir, hSceneOne +
            ".nwd")) == ("%%%%~name: Scene One\n"
                         "%%%%~path: %s/%s\n"
                         "%%%%~kind: NOVEL/DOCUMENT\n"
                         "%s\n\n") % (hNewFolder, hSceneOne, tSceneOne)

        assert readFile(os.path.join(
            contentDir, hSceneTwo +
            ".nwd")) == ("%%%%~name: Scene Two\n"
                         "%%%%~path: %s/%s\n"
                         "%%%%~kind: NOVEL/DOCUMENT\n"
                         "%s\n\n") % (hNewFolder, hSceneTwo, tSceneTwo)

        assert readFile(os.path.join(
            contentDir, hSceneThree +
            ".nwd")) == ("%%%%~name: Scene Three\n"
                         "%%%%~path: %s/%s\n"
                         "%%%%~kind: NOVEL/DOCUMENT\n"
                         "%s\n\n") % (hNewFolder, hSceneThree, tSceneThree)

        assert readFile(os.path.join(
            contentDir, hSceneFour +
            ".nwd")) == ("%%%%~name: Scene Four\n"
                         "%%%%~path: %s/%s\n"
                         "%%%%~kind: NOVEL/DOCUMENT\n"
                         "%s\n\n") % (hNewFolder, hSceneFour, tSceneFour)

        assert readFile(os.path.join(
            contentDir, hSceneFive +
            ".nwd")) == ("%%%%~name: The End\n"
                         "%%%%~path: %s/%s\n"
                         "%%%%~kind: NOVEL/DOCUMENT\n"
                         "%s\n\n") % (hNewFolder, hSceneFive, tSceneFive)

    # OS error
    with monkeypatch.context() as mp:
        mp.setattr("builtins.open", causeOSError)
        assert nwSplit._doSplit() is False

    # Select to not split
    with monkeypatch.context() as mp:
        mp.setattr(QMessageBox, "question", lambda *a: QMessageBox.No)
        assert nwSplit._doSplit() is False

    # Clear the list
    nwSplit.listBox.clear()
    assert nwSplit._doSplit() is False

    # Can't find sourcv item
    with monkeypatch.context() as mp:
        mp.setattr(NWTree, "__getitem__", lambda *a: None)
        assert nwSplit._doSplit() is False

    # No source item set
    nwSplit.sourceItem = None
    assert nwSplit._doSplit() is False

    # Close
    nwSplit._doClose()