示例#1
0
def testCoreProject_Save(monkeypatch, nwMinimal, mockGUI, refDir):
    """Test saving a project.
    """
    theProject = NWProject(mockGUI)
    testFile = os.path.join(nwMinimal, "nwProject.nwx")
    backFile = os.path.join(nwMinimal, "nwProject.bak")
    compFile = os.path.join(refDir, os.path.pardir, "minimal", "nwProject.nwx")

    # Nothing to save
    assert theProject.saveProject() is False

    # Open test project
    assert theProject.openProject(nwMinimal)

    # Fail on folder structure check
    with monkeypatch.context() as mp:
        mp.setattr("os.path.isdir", lambda *a: False)
        assert theProject.saveProject() is False

    # Fail on open file
    with monkeypatch.context() as mp:
        mp.setattr("builtins.open", causeOSError)
        assert theProject.saveProject() is False

    # Fail on creating .bak file
    with monkeypatch.context() as mp:
        mp.setattr("os.replace", causeOSError)
        assert theProject.saveProject() is False
        assert os.path.isfile(backFile) is False

    # Successful save
    saveCount = theProject.saveCount
    autoCount = theProject.autoCount
    assert theProject.saveProject() is True
    assert theProject.saveCount == saveCount + 1
    assert theProject.autoCount == autoCount
    assert cmpFiles(testFile, compFile, [2, 6, 7, 8, 9])

    # Check that a second save creates a .bak file
    assert os.path.isfile(backFile) is True

    # Successful autosave
    saveCount = theProject.saveCount
    autoCount = theProject.autoCount
    assert theProject.saveProject(autoSave=True) is True
    assert theProject.saveCount == saveCount
    assert theProject.autoCount == autoCount + 1
    assert cmpFiles(testFile, compFile, [2, 6, 7, 8, 9])

    # Close test project
    assert theProject.closeProject()
示例#2
0
def testCoreProject_NewRoot(fncDir, outDir, refDir, dummyGUI):
    """Check that new root folders can be added to the project.
    """
    projFile = os.path.join(fncDir, "nwProject.nwx")
    testFile = os.path.join(outDir, "coreProject_NewRoot_nwProject.nwx")
    compFile = os.path.join(refDir, "coreProject_NewRoot_nwProject.nwx")

    theProject = NWProject(dummyGUI)
    theProject.projTree.setSeed(42)

    assert theProject.newProject({"projPath": fncDir})
    assert theProject.setProjectPath(fncDir)
    assert theProject.saveProject()
    assert theProject.closeProject()
    assert theProject.openProject(projFile)

    assert isinstance(theProject.newRoot("Novel",     nwItemClass.NOVEL),     type(None))
    assert isinstance(theProject.newRoot("Plot",      nwItemClass.PLOT),      type(None))
    assert isinstance(theProject.newRoot("Character", nwItemClass.CHARACTER), type(None))
    assert isinstance(theProject.newRoot("World",     nwItemClass.WORLD),     type(None))
    assert isinstance(theProject.newRoot("Timeline",  nwItemClass.TIMELINE),  str)
    assert isinstance(theProject.newRoot("Object",    nwItemClass.OBJECT),    str)
    assert isinstance(theProject.newRoot("Custom1",   nwItemClass.CUSTOM),    str)
    assert isinstance(theProject.newRoot("Custom2",   nwItemClass.CUSTOM),    str)

    assert theProject.projChanged
    assert theProject.saveProject()
    assert theProject.closeProject()

    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
    assert not theProject.projChanged
示例#3
0
def testCoreToOdt_SaveFlat(mockGUI, fncDir, outDir, refDir):
    """Test the document save functions.
    """
    theProject = NWProject(mockGUI)

    theDoc = ToOdt(theProject, isFlat=True)
    theDoc._isNovel = True
    assert theDoc.setLanguage(None) is False
    assert theDoc.setLanguage("nb_NO") is True
    theDoc.setColourHeaders(True)

    theDoc._theText = ("## Chapter One\n\n"
                       "Text\n\n"
                       "## Chapter Two\n\n"
                       "Text\n\n")
    theDoc.tokenizeText()
    theDoc.initDocument()
    theDoc.doConvert()
    theDoc.closeDocument()

    flatFile = os.path.join(fncDir, "document.fodt")
    testFile = os.path.join(outDir, "coreToOdt_SaveFlat_document.fodt")
    compFile = os.path.join(refDir, "coreToOdt_SaveFlat_document.fodt")

    theDoc.saveFlatXML(flatFile)
    assert os.path.isfile(flatFile)

    copyfile(flatFile, testFile)
    assert cmpFiles(testFile, compFile, [4, 5])
示例#4
0
def testCoreProject_NewFile(fncDir, outDir, refDir, dummyGUI):
    """Check that new files can be added to the project.
    """
    projFile = os.path.join(fncDir, "nwProject.nwx")
    testFile = os.path.join(outDir, "coreProject_NewFile_nwProject.nwx")
    compFile = os.path.join(refDir, "coreProject_NewFile_nwProject.nwx")

    theProject = NWProject(dummyGUI)
    theProject.projTree.setSeed(42)

    assert theProject.newProject({"projPath": fncDir})
    assert theProject.setProjectPath(fncDir)
    assert theProject.saveProject()
    assert theProject.closeProject()
    assert theProject.openProject(projFile)

    assert isinstance(
        theProject.newFile("Hello", nwItemClass.NOVEL, "31489056e0916"), str)
    assert isinstance(
        theProject.newFile("Jane", nwItemClass.CHARACTER, "71ee45a3c0db9"),
        str)
    assert theProject.projChanged
    assert theProject.saveProject()
    assert theProject.closeProject()

    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
    assert not theProject.projChanged
示例#5
0
def testCoreProject_NewMinimal(fncDir, outDir, refDir, tmpDir, dummyGUI):
    """Create a new project from a project wizard dictionary. With
    default setting, creating a Minimal project.
    """
    projFile = os.path.join(fncDir, "nwProject.nwx")
    testFile = os.path.join(outDir, "coreProject_NewMinimal_nwProject.nwx")
    compFile = os.path.join(refDir, "coreProject_NewMinimal_nwProject.nwx")

    theProject = NWProject(dummyGUI)
    theProject.projTree.setSeed(42)

    # Setting no data should fail
    assert not theProject.newProject({})

    # Try again with a proper path
    assert theProject.newProject({"projPath": fncDir})
    assert theProject.saveProject()
    assert theProject.closeProject()

    # Creating the project once more should fail
    assert not theProject.newProject({"projPath": fncDir})

    # Check the new project
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [2, 6, 7, 8])

    # Open again
    assert theProject.openProject(projFile)

    # Save and close
    assert theProject.saveProject()
    assert theProject.closeProject()
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
    assert not theProject.projChanged

    # Open a second time
    assert theProject.openProject(projFile)
    assert not theProject.openProject(projFile)
    assert theProject.openProject(projFile, overrideLock=True)
    assert theProject.saveProject()
    assert theProject.closeProject()
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
示例#6
0
def testCoreProject_Save(monkeypatch, nwMinimal, dummyGUI, refDir):
    """Test saving a project.
    """
    theProject = NWProject(dummyGUI)
    testFile = os.path.join(nwMinimal, "nwProject.nwx")
    compFile = os.path.join(refDir, os.path.pardir, "minimal", "nwProject.nwx")

    # Nothing to save
    assert theProject.saveProject() is False

    # Open test project
    assert theProject.openProject(nwMinimal)

    # Fail on folder structure check
    monkeypatch.setattr("os.path.isdir", lambda *args: False)
    assert theProject.saveProject() is False
    monkeypatch.undo()

    # Fail on open file
    monkeypatch.setattr("builtins.open", causeOSError)
    assert theProject.saveProject() is False
    monkeypatch.undo()

    # Successful save
    saveCount = theProject.saveCount
    autoCount = theProject.autoCount
    assert theProject.saveProject() is True
    assert theProject.saveCount == saveCount + 1
    assert theProject.autoCount == autoCount
    assert cmpFiles(testFile, compFile, [2, 6, 7, 8, 9])

    # Successful autosave
    saveCount = theProject.saveCount
    autoCount = theProject.autoCount
    assert theProject.saveProject(autoSave=True) is True
    assert theProject.saveCount == saveCount
    assert theProject.autoCount == autoCount + 1
    assert cmpFiles(testFile, compFile, [2, 6, 7, 8, 9])

    # Close test project
    assert theProject.closeProject()
示例#7
0
def testCoreProject_NewCustomA(fncDir, outDir, refDir, dummyGUI):
    """Create a new project from a project wizard dictionary.
    Custom type with chapters and scenes.
    """
    projFile = os.path.join(fncDir, "nwProject.nwx")
    testFile = os.path.join(outDir, "coreProject_NewCustomA_nwProject.nwx")
    compFile = os.path.join(refDir, "coreProject_NewCustomA_nwProject.nwx")

    projData = {
        "projName":
        "Test Custom",
        "projTitle":
        "Test Novel",
        "projAuthors":
        "Jane Doe\nJohn Doh\n",
        "projPath":
        fncDir,
        "popSample":
        False,
        "popMinimal":
        False,
        "popCustom":
        True,
        "addRoots": [
            nwItemClass.PLOT,
            nwItemClass.CHARACTER,
            nwItemClass.WORLD,
            nwItemClass.TIMELINE,
            nwItemClass.OBJECT,
            nwItemClass.ENTITY,
        ],
        "numChapters":
        3,
        "numScenes":
        3,
        "chFolders":
        True,
    }
    theProject = NWProject(dummyGUI)
    theProject.projTree.setSeed(42)

    assert theProject.newProject(projData)
    assert theProject.saveProject()
    assert theProject.closeProject()

    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
示例#8
0
def testCoreIndex_LoadSave(monkeypatch, nwLipsum, mockGUI, outDir, refDir):
    """Test core functionality of scaning, saving, loading and checking
    the index cache file.
    """
    projFile = os.path.join(nwLipsum, "meta", "tagsIndex.json")
    testFile = os.path.join(outDir, "coreIndex_LoadSave_tagsIndex.json")
    compFile = os.path.join(refDir, "coreIndex_LoadSave_tagsIndex.json")

    theProject = NWProject(mockGUI)
    theProject.projTree.setSeed(42)
    assert theProject.openProject(nwLipsum)

    theIndex = NWIndex(theProject)
    notIndexable = {
        "b3643d0f92e32": False,  # Novel ROOT
        "45e6b01ca35c1": False,  # Chapter One FOLDER
        "6bd935d2490cd": False,  # Chapter Two FOLDER
        "67a8707f2f249": False,  # Character ROOT
        "6c6afb1247750": False,  # Plot ROOT
        "60bdf227455cc": False,  # World ROOT
    }
    for tItem in theProject.projTree:
        assert theIndex.reIndexHandle(tItem.itemHandle) is notIndexable.get(
            tItem.itemHandle, True)

    assert theIndex.reIndexHandle(None) is False

    # Make the save fail
    with monkeypatch.context() as mp:
        mp.setattr("builtins.open", causeException)
        assert theIndex.saveIndex() is False

    # Make the save pass
    assert theIndex.saveIndex() is True

    # Take a copy of the index
    tagIndex = str(theIndex._tagIndex)
    refIndex = str(theIndex._refIndex)
    fileIndex = str(theIndex._fileIndex)
    textCounts = str(theIndex._fileMeta)

    # Delete a handle
    assert theIndex._tagIndex.get("Bod", None) is not None
    assert theIndex._refIndex.get("4c4f28287af27", None) is not None
    assert theIndex._fileIndex.get("4c4f28287af27", None) is not None
    assert theIndex._fileMeta.get("4c4f28287af27", None) is not None
    theIndex.deleteHandle("4c4f28287af27")
    assert theIndex._tagIndex.get("Bod", None) is None
    assert theIndex._refIndex.get("4c4f28287af27", None) is None
    assert theIndex._fileIndex.get("4c4f28287af27", None) is None
    assert theIndex._fileMeta.get("4c4f28287af27", None) is None

    # Clear the index
    theIndex.clearIndex()
    assert theIndex._tagIndex == {}
    assert theIndex._refIndex == {}
    assert theIndex._fileIndex == {}
    assert theIndex._fileMeta == {}

    # Make the load fail
    with monkeypatch.context() as mp:
        mp.setattr(json, "load", causeException)
        assert theIndex.loadIndex() is False

    # Make the load pass
    assert theIndex.loadIndex() is True

    assert str(theIndex._tagIndex) == tagIndex
    assert str(theIndex._refIndex) == refIndex
    assert str(theIndex._fileIndex) == fileIndex
    assert str(theIndex._fileMeta) == textCounts

    # Break the index and check that we notice
    assert theIndex.indexBroken is False
    theIndex._tagIndex["Bod"].append("Stuff")
    theIndex._checkIndex()
    assert theIndex.indexBroken is True

    # Finalise
    assert theProject.closeProject() is True

    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)
示例#9
0
def testCoreProject_Backup(monkeypatch, dummyGUI, nwMinimal, tmpDir):
    """Test the automated backup feature of the project class. The test
    creates a backup of the Minimal test project, and then unzips the
    backupd file and checks that the project XML file is identical to
    the original file.
    """
    theProject = NWProject(dummyGUI)
    assert theProject.openProject(nwMinimal)

    # Test faulty settings

    # No project
    dummyGUI.hasProject = False
    assert not theProject.zipIt(doNotify=False)
    dummyGUI.hasProject = True

    # Invalid path
    theProject.mainConf.backupPath = None
    assert not theProject.zipIt(doNotify=False)

    # Missing project name
    theProject.mainConf.backupPath = tmpDir
    theProject.projName = ""
    assert not theProject.zipIt(doNotify=False)

    # Non-existent folder
    theProject.mainConf.backupPath = os.path.join(tmpDir, "nonexistent")
    theProject.projName = "Test Minimal"
    assert not theProject.zipIt(doNotify=False)

    # Same folder as project (causes infinite loop in zipping)
    theProject.mainConf.backupPath = nwMinimal
    assert not theProject.zipIt(doNotify=False)

    # Set a valid folder
    theProject.mainConf.backupPath = tmpDir

    # Can't make folder
    monkeypatch.setattr("os.mkdir", causeOSError)
    assert not theProject.zipIt(doNotify=False)
    monkeypatch.undo()

    # Can't write archive
    monkeypatch.setattr("shutil.make_archive", causeOSError)
    assert not theProject.zipIt(doNotify=False)
    monkeypatch.undo()

    # Test correct settings
    assert theProject.zipIt(doNotify=True)

    theFiles = os.listdir(os.path.join(tmpDir, "Test Minimal"))
    assert len(theFiles) == 1

    theZip = theFiles[0]
    assert theZip[:12] == "Backup from "
    assert theZip[-4:] == ".zip"

    # Extract the archive
    with ZipFile(os.path.join(tmpDir, "Test Minimal", theZip), "r") as inZip:
        inZip.extractall(os.path.join(tmpDir, "extract"))

    # Check that the main project file was restored
    assert cmpFiles(os.path.join(nwMinimal, "nwProject.nwx"),
                    os.path.join(tmpDir, "extract", "nwProject.nwx"))
示例#10
0
def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir,
                        mockRnd):
    """Test the document editor.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
    monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
    monkeypatch.setattr(GuiDocEditor, "hasFocus", lambda *a: True)
    monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
    monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text:
                        (text, True))

    # Create new, save, close project
    buildTestProject(nwGUI, fncProj)
    assert nwGUI.saveProject()
    assert nwGUI.closeProject()

    assert len(nwGUI.theProject.tree) == 0
    assert len(nwGUI.theProject.tree._treeOrder) == 0
    assert len(nwGUI.theProject.tree._treeRoots) == 0
    assert nwGUI.theProject.tree.trashRoot() is None
    assert nwGUI.theProject.projPath is None
    assert nwGUI.theProject.projMeta is None
    assert nwGUI.theProject.projFile == "nwProject.nwx"
    assert nwGUI.theProject.projName == ""
    assert nwGUI.theProject.bookTitle == ""
    assert len(nwGUI.theProject.bookAuthors) == 0
    assert not nwGUI.theProject.spellCheck

    # Check the files
    projFile = os.path.join(fncProj, "nwProject.nwx")
    testFile = os.path.join(outDir, "guiEditor_Main_Initial_nwProject.nwx")
    compFile = os.path.join(refDir, "guiEditor_Main_Initial_nwProject.nwx")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE)
    qtbot.wait(stepDelay)

    # qtbot.stopForInteraction()

    # Re-open project
    assert nwGUI.openProject(fncProj)
    qtbot.wait(stepDelay)

    # Check that we loaded the data
    assert len(nwGUI.theProject.tree) == 8
    assert len(nwGUI.theProject.tree._treeOrder) == 8
    assert len(nwGUI.theProject.tree._treeRoots) == 4
    assert nwGUI.theProject.tree.trashRoot() is None
    assert nwGUI.theProject.projPath == fncProj
    assert nwGUI.theProject.projMeta == os.path.join(fncProj, "meta")
    assert nwGUI.theProject.projFile == "nwProject.nwx"
    assert nwGUI.theProject.projName == "New Project"
    assert nwGUI.theProject.bookTitle == "New Novel"
    assert len(nwGUI.theProject.bookAuthors) == 1
    assert nwGUI.theProject.spellCheck is False

    # Check that tree items have been created
    assert nwGUI.projView.projTree._getTreeItem("0000000000008") is not None
    assert nwGUI.projView.projTree._getTreeItem("0000000000009") is not None
    assert nwGUI.projView.projTree._getTreeItem("000000000000a") is not None
    assert nwGUI.projView.projTree._getTreeItem("000000000000b") is not None
    assert nwGUI.projView.projTree._getTreeItem("000000000000c") is not None
    assert nwGUI.projView.projTree._getTreeItem("000000000000d") is not None
    assert nwGUI.projView.projTree._getTreeItem("000000000000e") is not None
    assert nwGUI.projView.projTree._getTreeItem("000000000000f") is not None

    nwGUI.mainMenu.aSpellCheck.setChecked(True)
    assert nwGUI.mainMenu._toggleSpellCheck()

    # Change some settings
    nwGUI.mainConf.hideHScroll = True
    nwGUI.mainConf.hideVScroll = True
    nwGUI.mainConf.autoScrollPos = 80
    nwGUI.mainConf.autoScroll = True

    # Add a Character File
    nwGUI.switchFocus(nwWidget.TREE)
    nwGUI.projView.projTree.clearSelection()
    nwGUI.projView.projTree._getTreeItem("000000000000a").setSelected(True)
    nwGUI.projView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True)
    assert nwGUI.openSelectedItem()

    # Type something into the document
    nwGUI.switchFocus(nwWidget.EDITOR)
    qtbot.keyClick(nwGUI.docEditor,
                   "a",
                   modifier=Qt.ControlModifier,
                   delay=keyDelay)
    for c in "# Jane Doe":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "@tag: Jane":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "This is a file about Jane.":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    # Add a Plot File
    nwGUI.switchFocus(nwWidget.TREE)
    nwGUI.projView.projTree.clearSelection()
    nwGUI.projView.projTree._getTreeItem("0000000000009").setSelected(True)
    nwGUI.projView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True)
    assert nwGUI.openSelectedItem()

    # Type something into the document
    nwGUI.switchFocus(nwWidget.EDITOR)
    qtbot.keyClick(nwGUI.docEditor,
                   "a",
                   modifier=Qt.ControlModifier,
                   delay=keyDelay)
    for c in "# Main Plot":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "@tag: MainPlot":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "This is a file detailing the main plot.":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    # Add a World File
    nwGUI.switchFocus(nwWidget.TREE)
    nwGUI.projView.projTree.clearSelection()
    nwGUI.projView.projTree._getTreeItem("000000000000b").setSelected(True)
    nwGUI.projView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True)
    assert nwGUI.openSelectedItem()

    # Add Some Text
    nwGUI.docEditor.replaceText("Hello World!")
    assert nwGUI.docEditor.getText() == "Hello World!"
    nwGUI.docEditor.replaceText("")

    # Type something into the document
    nwGUI.switchFocus(nwWidget.EDITOR)
    qtbot.keyClick(nwGUI.docEditor,
                   "a",
                   modifier=Qt.ControlModifier,
                   delay=keyDelay)
    for c in "# Main Location":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "@tag: Home":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "This is a file describing Jane's home.":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    # Trigger autosaves before making more changes
    nwGUI._autoSaveDocument()
    nwGUI._autoSaveProject()

    # Select the 'New Scene' file
    nwGUI.switchFocus(nwWidget.TREE)
    nwGUI.projView.projTree.clearSelection()
    nwGUI.projView.projTree._getTreeItem("0000000000008").setExpanded(True)
    nwGUI.projView.projTree._getTreeItem("000000000000d").setExpanded(True)
    nwGUI.projView.projTree._getTreeItem("000000000000f").setSelected(True)
    assert nwGUI.openSelectedItem()

    # Type something into the document
    nwGUI.switchFocus(nwWidget.EDITOR)
    qtbot.keyClick(nwGUI.docEditor,
                   "a",
                   modifier=Qt.ControlModifier,
                   delay=keyDelay)
    for c in "# Novel":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "## Chapter":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "@pov: Jane":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "@plot: MainPlot":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "### Scene":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "% How about a comment?":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "@pov: Jane":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "@plot: MainPlot":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "@location: Home":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "#### Some Section":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "@char: Jane":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "This is a paragraph of nonsense text.":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in ("This is another paragraph of much longer nonsense text. "
              "It is in fact 1 very very NONSENSICAL nonsense text! "):
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    for c in "We can also try replacing \"quotes\", even single 'quotes' are replaced. ":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    for c in "Isn't that nice? ":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    for c in "We can hyphen-ate, make dashes -- and even longer dashes --- if we want. ":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    for c in "Ellipsis? Not a problem either ... ":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    for c in "How about three hyphens - -":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Left, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Backspace, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Right, delay=keyDelay)
    for c in "- for long dash? It works too.":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "\"Full line double quoted text.\"":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "'Full line single quoted text.'":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "\t\"Tab-indented text\"":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in ">\"Paragraph-indented text\"":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in ">>\"Right-aligned text\"":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "\t'Tab-indented text'":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in ">'Paragraph-indented text'":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in ">>'Right-aligned text'":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    qtbot.wait(stepDelay)
    nwGUI.docEditor.wCounterDoc.run()
    qtbot.wait(stepDelay)

    # Save the document
    assert nwGUI.docEditor.docChanged()
    assert nwGUI.saveDocument()
    assert not nwGUI.docEditor.docChanged()
    qtbot.wait(stepDelay)
    nwGUI.rebuildIndex()
    qtbot.wait(stepDelay)

    # Open and view the edited document
    nwGUI.switchFocus(nwWidget.VIEWER)
    assert nwGUI.openDocument("000000000000f")
    assert nwGUI.viewDocument("000000000000f")
    qtbot.wait(stepDelay)
    assert nwGUI.saveProject()
    assert nwGUI.closeDocViewer()
    qtbot.wait(stepDelay)

    # Check a Quick Create and Delete
    assert nwGUI.projView.projTree.newTreeItem(nwItemType.FILE, None)
    newHandle = nwGUI.projView.getSelectedHandle()
    assert nwGUI.theProject.tree["0000000000020"] is not None
    assert nwGUI.projView.deleteItem()
    assert nwGUI.projView.setSelectedHandle(newHandle)
    assert nwGUI.projView.deleteItem()
    assert nwGUI.theProject.tree["0000000000024"] is not None  # Trash
    assert nwGUI.saveProject()

    # Check the files
    projFile = os.path.join(fncProj, "nwProject.nwx")
    testFile = os.path.join(outDir, "guiEditor_Main_Final_nwProject.nwx")
    compFile = os.path.join(refDir, "guiEditor_Main_Final_nwProject.nwx")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE)

    projFile = os.path.join(fncProj, "content", "000000000000f.nwd")
    testFile = os.path.join(outDir, "guiEditor_Main_Final_000000000000f.nwd")
    compFile = os.path.join(refDir, "guiEditor_Main_Final_000000000000f.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    projFile = os.path.join(fncProj, "content", "0000000000020.nwd")
    testFile = os.path.join(outDir, "guiEditor_Main_Final_0000000000020.nwd")
    compFile = os.path.join(refDir, "guiEditor_Main_Final_0000000000020.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    projFile = os.path.join(fncProj, "content", "0000000000021.nwd")
    testFile = os.path.join(outDir, "guiEditor_Main_Final_0000000000021.nwd")
    compFile = os.path.join(refDir, "guiEditor_Main_Final_0000000000021.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    projFile = os.path.join(fncProj, "content", "0000000000022.nwd")
    testFile = os.path.join(outDir, "guiEditor_Main_Final_0000000000022.nwd")
    compFile = os.path.join(refDir, "guiEditor_Main_Final_0000000000022.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)
示例#11
0
def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir):
    """Test config intialisation.
    """
    tstConf = Config()

    confFile = os.path.join(tmpDir, "novelwriter.conf")
    testFile = os.path.join(outDir, "baseConfig_novelwriter.conf")
    compFile = os.path.join(refDir, "baseConfig_novelwriter.conf")

    # Make sure we don't have any old conf file
    if os.path.isfile(confFile):
        os.unlink(confFile)

    # Let the config class figure out the path
    monkeypatch.setattr("PyQt5.QtCore.QStandardPaths.writableLocation", lambda *args: fncDir)
    tstConf.verQtValue = 50600
    tstConf.initConfig()
    assert tstConf.confPath == os.path.join(fncDir, tstConf.appHandle)
    assert tstConf.dataPath == os.path.join(fncDir, tstConf.appHandle)
    assert not os.path.isfile(confFile)
    tstConf.verQtValue = 50000
    tstConf.initConfig()
    assert tstConf.confPath == os.path.join(fncDir, tstConf.appHandle)
    assert tstConf.dataPath == os.path.join(fncDir, tstConf.appHandle)
    assert not os.path.isfile(confFile)
    monkeypatch.undo()

    # Fail to make folders
    monkeypatch.setattr("os.mkdir", causeOSError)

    tstConfDir = os.path.join(fncDir, "test_conf")
    tstConf.initConfig(confPath=tstConfDir, dataPath=tmpDir)
    assert tstConf.confPath is None
    assert tstConf.dataPath == tmpDir
    assert not os.path.isfile(confFile)

    tstDataDir = os.path.join(fncDir, "test_data")
    tstConf.initConfig(confPath=tmpDir, dataPath=tstDataDir)
    assert tstConf.confPath == tmpDir
    assert tstConf.dataPath is None
    assert os.path.isfile(confFile)
    os.unlink(confFile)

    monkeypatch.undo()

    # Test load/save with no path
    tstConf.confPath = None
    assert not tstConf.loadConfig()
    assert not tstConf.saveConfig()

    # Run again and set the paths directly and correctly
    # This should create a config file as well
    monkeypatch.setattr("os.path.expanduser", lambda *args: "")
    tstConf.spellTool = nwConst.SP_INTERNAL
    tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir)
    assert tstConf.confPath == tmpDir
    assert tstConf.dataPath == tmpDir
    assert os.path.isfile(confFile)

    copyfile(confFile, testFile)
    assert cmpFiles(testFile, compFile, [2, 9])
    monkeypatch.undo()

    # Load and save with OSError
    monkeypatch.setattr("builtins.open", causeOSError)

    assert not tstConf.loadConfig()
    assert tstConf.hasError is True
    assert tstConf.errData != []
    assert tstConf.getErrData().startswith("Could not")
    assert tstConf.hasError is False
    assert tstConf.errData == []

    assert not tstConf.saveConfig()
    assert tstConf.hasError is True
    assert tstConf.errData != []
    assert tstConf.getErrData().startswith("Could not")
    assert tstConf.hasError is False
    assert tstConf.errData == []

    monkeypatch.undo()

    assert tstConf.loadConfig()
    assert tstConf.saveConfig()

    copyfile(confFile, testFile)
    assert cmpFiles(testFile, compFile, [2, 9])
示例#12
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])
示例#13
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])
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()
示例#15
0
def testBaseConfig_SettersGetters(tmpConf, tmpDir, outDir, refDir):
    """Set various sizes and positions
    """
    confFile = os.path.join(tmpDir, "novelwriter.conf")
    testFile = os.path.join(outDir, "baseConfig_novelwriter.conf")
    compFile = os.path.join(refDir, "baseConfig_novelwriter.conf")

    # GUI Scaling
    # ===========
    tmpConf.guiScale = 1.0
    assert tmpConf.pxInt(10) == 10
    assert tmpConf.pxInt(13) == 13
    assert tmpConf.rpxInt(10) == 10
    assert tmpConf.rpxInt(13) == 13

    tmpConf.guiScale = 2.0
    assert tmpConf.pxInt(10) == 20
    assert tmpConf.pxInt(13) == 26
    assert tmpConf.rpxInt(10) == 5
    assert tmpConf.rpxInt(13) == 6

    # Setter + Getter Combos
    # ======================

    # Window Size
    tmpConf.guiScale = 1.0
    assert tmpConf.setWinSize(1205, 655)
    assert not tmpConf.confChanged

    tmpConf.guiScale = 2.0
    assert tmpConf.setWinSize(70, 70)
    assert tmpConf.getWinSize() == [70, 70]
    assert tmpConf.winGeometry == [35, 35]

    tmpConf.guiScale = 1.0
    assert tmpConf.setWinSize(70, 70)
    assert tmpConf.getWinSize() == [70, 70]
    assert tmpConf.winGeometry == [70, 70]

    assert tmpConf.setWinSize(1200, 650)

    # Project Tree Columns
    tmpConf.guiScale = 2.0
    assert tmpConf.setTreeColWidths([10, 20, 25])
    assert tmpConf.getTreeColWidths() == [10, 20, 24]
    assert tmpConf.treeColWidth == [5, 10, 12]

    tmpConf.guiScale = 1.0
    assert tmpConf.setTreeColWidths([10, 20, 25])
    assert tmpConf.getTreeColWidths() == [10, 20, 25]
    assert tmpConf.treeColWidth == [10, 20, 25]

    assert tmpConf.setTreeColWidths([200, 50, 30])

    # Novel Tree Columns
    tmpConf.guiScale = 2.0
    assert tmpConf.setNovelColWidths([10, 20])
    assert tmpConf.getNovelColWidths() == [10, 20]
    assert tmpConf.novelColWidth == [5, 10]

    tmpConf.guiScale = 1.0
    assert tmpConf.setNovelColWidths([10, 20])
    assert tmpConf.getNovelColWidths() == [10, 20]
    assert tmpConf.novelColWidth == [10, 20]

    assert tmpConf.setNovelColWidths([200, 50])

    # Project Settings Tree Columns
    tmpConf.guiScale = 2.0
    assert tmpConf.setProjColWidths([10, 20, 30])
    assert tmpConf.getProjColWidths() == [10, 20, 30]
    assert tmpConf.projColWidth == [5, 10, 15]

    tmpConf.guiScale = 1.0
    assert tmpConf.setProjColWidths([10, 20, 30])
    assert tmpConf.getProjColWidths() == [10, 20, 30]
    assert tmpConf.projColWidth == [10, 20, 30]

    assert tmpConf.setProjColWidths([200, 60, 140])

    # Main Pane Splitter
    tmpConf.guiScale = 2.0
    assert tmpConf.setMainPanePos([200, 700])
    assert tmpConf.getMainPanePos() == [200, 700]
    assert tmpConf.mainPanePos == [100, 350]

    tmpConf.guiScale = 1.0
    assert tmpConf.setMainPanePos([200, 700])
    assert tmpConf.getMainPanePos() == [200, 700]
    assert tmpConf.mainPanePos == [200, 700]

    assert tmpConf.setMainPanePos([300, 800])

    # Doc Pane Splitter
    tmpConf.guiScale = 2.0
    assert tmpConf.setDocPanePos([300, 300])
    assert tmpConf.getDocPanePos() == [300, 300]
    assert tmpConf.docPanePos == [150, 150]

    tmpConf.guiScale = 1.0
    assert tmpConf.setDocPanePos([300, 300])
    assert tmpConf.getDocPanePos() == [300, 300]
    assert tmpConf.docPanePos == [300, 300]

    assert tmpConf.setDocPanePos([400, 400])

    # View Pane Splitter
    tmpConf.guiScale = 2.0
    assert tmpConf.setViewPanePos([400, 250])
    assert tmpConf.getViewPanePos() == [400, 250]
    assert tmpConf.viewPanePos == [200, 125]

    tmpConf.guiScale = 1.0
    assert tmpConf.setViewPanePos([400, 250])
    assert tmpConf.getViewPanePos() == [400, 250]
    assert tmpConf.viewPanePos == [400, 250]

    assert tmpConf.setViewPanePos([500, 150])

    # Outline Pane Splitter
    tmpConf.guiScale = 2.0
    assert tmpConf.setOutlinePanePos([400, 250])
    assert tmpConf.getOutlinePanePos() == [400, 250]
    assert tmpConf.outlnPanePos == [200, 125]

    tmpConf.guiScale = 1.0
    assert tmpConf.setOutlinePanePos([400, 250])
    assert tmpConf.getOutlinePanePos() == [400, 250]
    assert tmpConf.outlnPanePos == [400, 250]

    assert tmpConf.setOutlinePanePos([500, 150])

    # Getters Only
    # ============
    tmpConf.guiScale = 1.0
    assert tmpConf.getTextWidth() == 600
    assert tmpConf.getTextMargin() == 40
    assert tmpConf.getTabWidth() == 40
    assert tmpConf.getFocusWidth() == 800

    tmpConf.guiScale = 2.0
    assert tmpConf.getTextWidth() == 1200
    assert tmpConf.getTextMargin() == 80
    assert tmpConf.getTabWidth() == 80
    assert tmpConf.getFocusWidth() == 1600

    # Flag Setters
    # ============
    assert not tmpConf.setShowRefPanel(False)
    assert not tmpConf.showRefPanel
    assert tmpConf.setShowRefPanel(True)

    assert not tmpConf.setViewComments(False)
    assert not tmpConf.viewComments
    assert tmpConf.setViewComments(True)

    assert not tmpConf.setViewSynopsis(False)
    assert not tmpConf.viewSynopsis
    assert tmpConf.setViewSynopsis(True)

    # Check Final File
    # ================

    assert tmpConf.confChanged
    assert tmpConf.saveConfig()
    assert not tmpConf.confChanged

    copyfile(confFile, testFile)
    assert cmpFiles(testFile, compFile, [2, 9, 10])
示例#16
0
def testCoreIndex_LoadSave(monkeypatch, nwLipsum, dummyGUI, outDir, refDir):
    """Test core functionality of scaning, saving, loading and checking
    the index cache file.
    """
    projFile = os.path.join(nwLipsum, "meta", "tagsIndex.json")
    testFile = os.path.join(outDir, "coreIndex_LoadSave_tagsIndex.json")
    compFile = os.path.join(refDir, "coreIndex_LoadSave_tagsIndex.json")

    theProject = NWProject(dummyGUI)
    theProject.projTree.setSeed(42)
    assert theProject.openProject(nwLipsum)

    monkeypatch.setattr("nw.core.index.time", lambda: 123.4)

    theIndex = NWIndex(theProject, dummyGUI)
    notIndexable = {
        "b3643d0f92e32": False,  # Novel ROOT
        "45e6b01ca35c1": False,  # Chapter One FOLDER
        "6bd935d2490cd": False,  # Chapter Two FOLDER
        "67a8707f2f249": False,  # Character ROOT
        "6c6afb1247750": False,  # Plot ROOT
        "60bdf227455cc": False,  # World ROOT
    }
    for tItem in theProject.projTree:
        assert theIndex.reIndexHandle(tItem.itemHandle) is notIndexable.get(
            tItem.itemHandle, True)

    assert not theIndex.reIndexHandle(None)

    # Dummy exception function
    def doPanic(*arg, **kwargs):
        raise Exception

    # Make the save fail
    monkeypatch.setattr(json, "dump", doPanic)
    assert not theIndex.saveIndex()

    # Make the save pass
    monkeypatch.undo()
    assert theIndex.saveIndex()

    # Take a copy of the index
    tagIndex = str(theIndex.tagIndex)
    refIndex = str(theIndex.refIndex)
    novelIndex = str(theIndex.novelIndex)
    noteIndex = str(theIndex.noteIndex)
    textCounts = str(theIndex.textCounts)

    # Delete a handle
    assert theIndex.tagIndex.get("Bod", None) is not None
    assert theIndex.refIndex.get("4c4f28287af27", None) is not None
    assert theIndex.noteIndex.get("4c4f28287af27", None) is not None
    assert theIndex.textCounts.get("4c4f28287af27", None) is not None
    theIndex.deleteHandle("4c4f28287af27")
    assert theIndex.tagIndex.get("Bod", None) is None
    assert theIndex.refIndex.get("4c4f28287af27", None) is None
    assert theIndex.noteIndex.get("4c4f28287af27", None) is None
    assert theIndex.textCounts.get("4c4f28287af27", None) is None

    # Clear the index
    theIndex.clearIndex()
    assert not theIndex.tagIndex
    assert not theIndex.refIndex
    assert not theIndex.novelIndex
    assert not theIndex.noteIndex
    assert not theIndex.textCounts

    # Make the load fail
    monkeypatch.setattr(json, "load", doPanic)
    assert not theIndex.loadIndex()

    # Make the load pass
    monkeypatch.undo()
    assert theIndex.loadIndex()

    assert str(theIndex.tagIndex) == tagIndex
    assert str(theIndex.refIndex) == refIndex
    assert str(theIndex.novelIndex) == novelIndex
    assert str(theIndex.noteIndex) == noteIndex
    assert str(theIndex.textCounts) == textCounts

    # Break the index and check that we notice
    assert not theIndex.indexBroken
    theIndex.tagIndex["Bod"].append("Stuff")  # No longer len() == 4
    theIndex.checkIndex()
    assert theIndex.indexBroken

    assert theIndex.loadIndex()
    assert not theIndex.indexBroken
    theIndex.refIndex["fb609cd8319dc"]["T000001"]["tags"].append(
        "Stuff")  # No longer len() == 3
    theIndex.checkIndex()
    assert theIndex.indexBroken

    assert theIndex.loadIndex()
    assert not theIndex.indexBroken
    theIndex.novelIndex["7a992350f3eb6"]["T000001"][
        "Stuff"] = ""  # No longer len(keys()) == 8
    theIndex.checkIndex()
    assert theIndex.indexBroken

    assert theIndex.loadIndex()
    assert not theIndex.indexBroken
    theIndex.noteIndex["4c4f28287af27"]["T000001"][
        "Stuff"] = ""  # No longer len(keys()) == 8
    theIndex.checkIndex()
    assert theIndex.indexBroken

    assert theIndex.loadIndex()
    assert not theIndex.indexBroken
    theIndex.textCounts["7a992350f3eb6"].append(
        "Stuff")  # No longer len() == 3
    theIndex.checkIndex()
    assert theIndex.indexBroken

    # Make the try/except trigger as well
    assert theIndex.loadIndex()
    assert not theIndex.indexBroken
    theIndex.refIndex["fb609cd8319dc"]["T000001"] = {
        "tagssss": []
    }  # Wrong key name
    theIndex.checkIndex()
    assert theIndex.indexBroken

    # Finalise
    assert theProject.closeProject()

    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)
示例#17
0
def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir, filesDir):
    """Test config intialisation.
    """
    tstConf = Config()

    confFile = os.path.join(tmpDir, "novelwriter.conf")
    testFile = os.path.join(outDir, "baseConfig_novelwriter.conf")
    compFile = os.path.join(refDir, "baseConfig_novelwriter.conf")

    # Make sure we don't have any old conf file
    if os.path.isfile(confFile):
        os.unlink(confFile)

    # Let the config class figure out the path
    with monkeypatch.context() as mp:
        mp.setattr("PyQt5.QtCore.QStandardPaths.writableLocation",
                   lambda *a: fncDir)
        tstConf.verQtValue = 50600
        tstConf.initConfig()
        assert tstConf.confPath == os.path.join(fncDir, tstConf.appHandle)
        assert tstConf.dataPath == os.path.join(fncDir, tstConf.appHandle)
        assert not os.path.isfile(confFile)
        tstConf.verQtValue = 50000
        tstConf.initConfig()
        assert tstConf.confPath == os.path.join(fncDir, tstConf.appHandle)
        assert tstConf.dataPath == os.path.join(fncDir, tstConf.appHandle)
        assert not os.path.isfile(confFile)

    # Fail to make folders
    with monkeypatch.context() as mp:
        mp.setattr("os.mkdir", causeOSError)

        tstConfDir = os.path.join(fncDir, "test_conf")
        tstConf.initConfig(confPath=tstConfDir, dataPath=tmpDir)
        assert tstConf.confPath is None
        assert tstConf.dataPath == tmpDir
        assert not os.path.isfile(confFile)

        tstDataDir = os.path.join(fncDir, "test_data")
        tstConf.initConfig(confPath=tmpDir, dataPath=tstDataDir)
        assert tstConf.confPath == tmpDir
        assert tstConf.dataPath is None
        assert os.path.isfile(confFile)
        os.unlink(confFile)

    # Test load/save with no path
    tstConf.confPath = None
    assert tstConf.loadConfig() is False
    assert tstConf.saveConfig() is False

    # Run again and set the paths directly and correctly
    # This should create a config file as well
    with monkeypatch.context() as mp:
        mp.setattr("os.path.expanduser", lambda *a: "")
        tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir)
        assert tstConf.confPath == tmpDir
        assert tstConf.dataPath == tmpDir
        assert os.path.isfile(confFile)

        copyfile(confFile, testFile)
        assert cmpFiles(testFile,
                        compFile,
                        ignoreStart=("timestamp", "lastnotes", "guilang"))

    # Load and save with OSError
    with monkeypatch.context() as mp:
        mp.setattr("builtins.open", causeOSError)

        assert not tstConf.loadConfig()
        assert tstConf.hasError is True
        assert tstConf.errData != []
        assert tstConf.getErrData().startswith("Could not")
        assert tstConf.hasError is False
        assert tstConf.errData == []

        assert not tstConf.saveConfig()
        assert tstConf.hasError is True
        assert tstConf.errData != []
        assert tstConf.getErrData().startswith("Could not")
        assert tstConf.hasError is False
        assert tstConf.errData == []

    # Check handling of novelWriter as a package
    with monkeypatch.context() as mp:
        tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir)
        assert tstConf.confPath == tmpDir
        assert tstConf.dataPath == tmpDir
        appRoot = tstConf.appRoot

        mp.setattr("os.path.isfile", lambda *a: True)
        tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir)
        assert tstConf.confPath == tmpDir
        assert tstConf.dataPath == tmpDir
        assert tstConf.appRoot == os.path.dirname(appRoot)
        assert tstConf.appPath == os.path.dirname(appRoot)

    assert tstConf.loadConfig() is True
    assert tstConf.saveConfig() is True

    # Test Correcting Quote Settings
    origDbl = tstConf.fmtDoubleQuotes
    origSng = tstConf.fmtSingleQuotes
    orDoDbl = tstConf.doReplaceDQuote
    orDoSng = tstConf.doReplaceSQuote

    tstConf.fmtDoubleQuotes = ["\"", "\""]
    tstConf.fmtSingleQuotes = ["'", "'"]
    tstConf.doReplaceDQuote = True
    tstConf.doReplaceSQuote = True
    assert tstConf.saveConfig() is True

    assert tstConf.loadConfig() is True
    assert tstConf.doReplaceDQuote is False
    assert tstConf.doReplaceSQuote is False

    tstConf.fmtDoubleQuotes = origDbl
    tstConf.fmtSingleQuotes = origSng
    tstConf.doReplaceDQuote = orDoDbl
    tstConf.doReplaceSQuote = orDoSng
    assert tstConf.saveConfig() is True

    # Test Correcting icon theme
    origIcons = tstConf.guiIcons

    tstConf.guiIcons = "typicons_colour_dark"
    assert tstConf.saveConfig() is True
    assert tstConf.loadConfig() is True
    assert tstConf.guiIcons == "typicons_dark"

    tstConf.guiIcons = "typicons_grey_dark"
    assert tstConf.saveConfig() is True
    assert tstConf.loadConfig() is True
    assert tstConf.guiIcons == "typicons_dark"

    tstConf.guiIcons = "typicons_colour_light"
    assert tstConf.saveConfig() is True
    assert tstConf.loadConfig() is True
    assert tstConf.guiIcons == "typicons_light"

    tstConf.guiIcons = "typicons_grey_light"
    assert tstConf.saveConfig() is True
    assert tstConf.loadConfig() is True
    assert tstConf.guiIcons == "typicons_light"

    tstConf.guiIcons = origIcons
    assert tstConf.saveConfig()

    # Localisation
    # ============

    i18nDir = os.path.join(fncDir, "i18n")
    os.mkdir(i18nDir)
    os.mkdir(os.path.join(i18nDir, "stuff"))
    tstConf.nwLangPath = i18nDir

    copyfile(os.path.join(filesDir, "nw_en_GB.qm"),
             os.path.join(i18nDir, "nw_en_GB.qm"))
    writeFile(os.path.join(i18nDir, "nw_en_GB.ts"), "")
    writeFile(os.path.join(i18nDir, "nw_abcd.qm"), "")

    tstApp = MockApp()
    tstConf.initLocalisation(tstApp)

    # Check Lists
    theList = tstConf.listLanguages(tstConf.LANG_NW)
    assert theList == [("en_GB", "British English")]
    theList = tstConf.listLanguages(tstConf.LANG_PROJ)
    assert theList == [("en_GB", "British English")]
    theList = tstConf.listLanguages(None)
    assert theList == []

    # Add Language
    copyfile(os.path.join(filesDir, "nw_en_GB.qm"),
             os.path.join(i18nDir, "nw_fr.qm"))
    writeFile(os.path.join(i18nDir, "nw_fr.ts"), "")

    theList = tstConf.listLanguages(tstConf.LANG_NW)
    assert theList == [("en_GB", "British English"), ("fr", "Français")]

    copyfile(confFile, testFile)
    assert cmpFiles(testFile,
                    compFile,
                    ignoreStart=("timestamp", "lastnotes", "guilang"))
示例#18
0
def testCoreToOdt_SaveFull(mockGUI, fncDir, outDir, refDir):
    """Test the document save functions.
    """
    theProject = NWProject(mockGUI)

    theDoc = ToOdt(theProject, isFlat=False)
    theDoc._isNovel = True

    theDoc._theText = ("## Chapter One\n\n"
                       "Text\n\n"
                       "## Chapter Two\n\n"
                       "Text\n\n")
    theDoc.tokenizeText()
    theDoc.initDocument()
    theDoc.doConvert()
    theDoc.closeDocument()

    fullFile = os.path.join(fncDir, "document.odt")

    theDoc.saveOpenDocText(fullFile)
    assert os.path.isfile(fullFile)
    assert zipfile.is_zipfile(fullFile)

    maniFile = os.path.join(outDir, "coreToOdt_SaveFull_manifest.xml")
    settFile = os.path.join(outDir, "coreToOdt_SaveFull_settings.xml")
    contFile = os.path.join(outDir, "coreToOdt_SaveFull_content.xml")
    metaFile = os.path.join(outDir, "coreToOdt_SaveFull_meta.xml")
    stylFile = os.path.join(outDir, "coreToOdt_SaveFull_styles.xml")

    maniComp = os.path.join(refDir, "coreToOdt_SaveFull_manifest.xml")
    settComp = os.path.join(refDir, "coreToOdt_SaveFull_settings.xml")
    contComp = os.path.join(refDir, "coreToOdt_SaveFull_content.xml")
    metaComp = os.path.join(refDir, "coreToOdt_SaveFull_meta.xml")
    stylComp = os.path.join(refDir, "coreToOdt_SaveFull_styles.xml")

    extaxtTo = os.path.join(outDir, "coreToOdt_SaveFull")

    with zipfile.ZipFile(fullFile, mode="r") as theZip:
        theZip.extract("META-INF/manifest.xml", extaxtTo)
        theZip.extract("settings.xml", extaxtTo)
        theZip.extract("content.xml", extaxtTo)
        theZip.extract("meta.xml", extaxtTo)
        theZip.extract("styles.xml", extaxtTo)

    maniOut = os.path.join(outDir, "coreToOdt_SaveFull", "META-INF",
                           "manifest.xml")
    settOut = os.path.join(outDir, "coreToOdt_SaveFull", "settings.xml")
    contOut = os.path.join(outDir, "coreToOdt_SaveFull", "content.xml")
    metaOut = os.path.join(outDir, "coreToOdt_SaveFull", "meta.xml")
    stylOut = os.path.join(outDir, "coreToOdt_SaveFull", "styles.xml")

    def prettifyXml(inFile, outFile):
        with open(outFile, mode="wb") as fileStream:
            fileStream.write(
                etree.tostring(etree.parse(inFile),
                               pretty_print=True,
                               encoding="utf-8",
                               xml_declaration=True))

    prettifyXml(maniOut, maniFile)
    prettifyXml(settOut, settFile)
    prettifyXml(contOut, contFile)
    prettifyXml(metaOut, metaFile)
    prettifyXml(stylOut, stylFile)

    assert cmpFiles(maniFile, maniComp)
    assert cmpFiles(settFile, settComp)
    assert cmpFiles(contFile, contComp)
    assert cmpFiles(metaFile, metaComp, [4, 5])
    assert cmpFiles(stylFile, stylComp)
示例#19
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()
示例#20
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()
示例#21
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()
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)
示例#23
0
def testGuiEditor_Main(qtbot, monkeypatch, nwGUI, fncDir, fncProj, refDir,
                       outDir):
    """Test the document editor.
    """
    # Block message box
    monkeypatch.setattr(QMessageBox, "question", lambda *args: QMessageBox.Yes)
    monkeypatch.setattr(QMessageBox, "information",
                        lambda *args: QMessageBox.Yes)
    monkeypatch.setattr(GuiItemEditor, "exec_", lambda *args: None)
    monkeypatch.setattr(GuiItemEditor, "result",
                        lambda *args: QDialog.Accepted)
    monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *args: True)
    monkeypatch.setattr(GuiDocEditor, "hasFocus", lambda *args: True)

    # Create new, save, close project
    nwGUI.theProject.projTree.setSeed(42)
    assert nwGUI.newProject({"projPath": fncProj})
    assert nwGUI.saveProject()
    assert nwGUI.closeProject()

    assert len(nwGUI.theProject.projTree) == 0
    assert len(nwGUI.theProject.projTree._treeOrder) == 0
    assert len(nwGUI.theProject.projTree._treeRoots) == 0
    assert nwGUI.theProject.projTree.trashRoot() is None
    assert nwGUI.theProject.projPath is None
    assert nwGUI.theProject.projMeta is None
    assert nwGUI.theProject.projFile == "nwProject.nwx"
    assert nwGUI.theProject.projName == ""
    assert nwGUI.theProject.bookTitle == ""
    assert len(nwGUI.theProject.bookAuthors) == 0
    assert not nwGUI.theProject.spellCheck

    # Check the files
    projFile = os.path.join(fncProj, "nwProject.nwx")
    testFile = os.path.join(outDir, "guiEditor_Main_Initial_nwProject.nwx")
    compFile = os.path.join(refDir, "guiEditor_Main_Initial_nwProject.nwx")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [2, 6, 7, 8])
    qtbot.wait(stepDelay)

    # qtbot.stopForInteraction()

    # Re-open project
    assert nwGUI.openProject(fncProj)
    qtbot.wait(stepDelay)

    # Check that we loaded the data
    assert len(nwGUI.theProject.projTree) == 8
    assert len(nwGUI.theProject.projTree._treeOrder) == 8
    assert len(nwGUI.theProject.projTree._treeRoots) == 4
    assert nwGUI.theProject.projTree.trashRoot() is None
    assert nwGUI.theProject.projPath == fncProj
    assert nwGUI.theProject.projMeta == os.path.join(fncProj, "meta")
    assert nwGUI.theProject.projFile == "nwProject.nwx"
    assert nwGUI.theProject.projName == "New Project"
    assert nwGUI.theProject.bookTitle == ""
    assert len(nwGUI.theProject.bookAuthors) == 0
    assert not nwGUI.theProject.spellCheck

    # Check that tree items have been created
    assert nwGUI.treeView._getTreeItem("73475cb40a568") is not None
    assert nwGUI.treeView._getTreeItem("25fc0e7096fc6") is not None
    assert nwGUI.treeView._getTreeItem("31489056e0916") is not None
    assert nwGUI.treeView._getTreeItem("98010bd9270f9") is not None
    assert nwGUI.treeView._getTreeItem("0e17daca5f3e1") is not None
    assert nwGUI.treeView._getTreeItem("44cb730c42048") is not None
    assert nwGUI.treeView._getTreeItem("71ee45a3c0db9") is not None
    assert nwGUI.treeView._getTreeItem("811786ad1ae74") is not None

    nwGUI.mainMenu.aSpellCheck.setChecked(True)
    assert nwGUI.mainMenu._toggleSpellCheck()

    # Change some settings
    nwGUI.mainConf.hideHScroll = True
    nwGUI.mainConf.hideVScroll = True
    nwGUI.mainConf.scrollPastEnd = True
    nwGUI.mainConf.autoScrollPos = 80
    nwGUI.mainConf.autoScroll = True

    # Add a Character File
    nwGUI.switchFocus(nwWidget.TREE)
    nwGUI.treeView.clearSelection()
    nwGUI.treeView._getTreeItem("71ee45a3c0db9").setSelected(True)
    nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
    assert nwGUI.openSelectedItem()

    # Type something into the document
    nwGUI.switchFocus(nwWidget.EDITOR)
    qtbot.keyClick(nwGUI.docEditor,
                   "a",
                   modifier=Qt.ControlModifier,
                   delay=keyDelay)
    for c in "# Jane Doe":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "@tag: Jane":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "This is a file about Jane.":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    # Add a Plot File
    nwGUI.switchFocus(nwWidget.TREE)
    nwGUI.treeView.clearSelection()
    nwGUI.treeView._getTreeItem("44cb730c42048").setSelected(True)
    nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
    assert nwGUI.openSelectedItem()

    # Type something into the document
    nwGUI.switchFocus(nwWidget.EDITOR)
    qtbot.keyClick(nwGUI.docEditor,
                   "a",
                   modifier=Qt.ControlModifier,
                   delay=keyDelay)
    for c in "# Main Plot":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "@tag: MainPlot":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "This is a file detailing the main plot.":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    # Add a World File
    nwGUI.switchFocus(nwWidget.TREE)
    nwGUI.treeView.clearSelection()
    nwGUI.treeView._getTreeItem("811786ad1ae74").setSelected(True)
    nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
    assert nwGUI.openSelectedItem()

    # Add Some Text
    nwGUI.docEditor.replaceText("Hello World!")
    assert nwGUI.docEditor.getText() == "Hello World!"
    nwGUI.docEditor.replaceText("")

    # Type something into the document
    nwGUI.switchFocus(nwWidget.EDITOR)
    qtbot.keyClick(nwGUI.docEditor,
                   "a",
                   modifier=Qt.ControlModifier,
                   delay=keyDelay)
    for c in "# Main Location":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "@tag: Home":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "This is a file describing Jane's home.":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    # Trigger autosaves before making more changes
    nwGUI._autoSaveDocument()
    nwGUI._autoSaveProject()

    # Select the 'New Scene' file
    nwGUI.switchFocus(nwWidget.TREE)
    nwGUI.treeView.clearSelection()
    nwGUI.treeView._getTreeItem("73475cb40a568").setExpanded(True)
    nwGUI.treeView._getTreeItem("31489056e0916").setExpanded(True)
    nwGUI.treeView._getTreeItem("0e17daca5f3e1").setSelected(True)
    assert nwGUI.openSelectedItem()

    # Type something into the document
    nwGUI.switchFocus(nwWidget.EDITOR)
    qtbot.keyClick(nwGUI.docEditor,
                   "a",
                   modifier=Qt.ControlModifier,
                   delay=keyDelay)
    for c in "# Novel":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "## Chapter":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "@pov: Jane":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "@plot: MainPlot":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "### Scene":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "% How about a comment?":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "@pov: Jane":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "@plot: MainPlot":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    for c in "@location: Home":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "#### Some Section":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "@char: Jane":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "This is a paragraph of dummy text.":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in ("This is another paragraph of much longer dummy text. "
              "It is in fact 1 very very DUMB dummy text! "):
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    for c in "We can also try replacing \"quotes\", even single 'quotes' are replaced. ":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    for c in "Isn't that nice? ":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    for c in "We can hyphen-ate, make dashes -- and even longer dashes --- if we want. ":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    for c in "Ellipsis? Not a problem either ... ":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    for c in "How about three hyphens - -":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Left, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Backspace, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Right, delay=keyDelay)
    for c in "- for long dash? It works too.":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "\"Full line double quoted text.\"":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    for c in "'Full line single quoted text.'":
        qtbot.keyClick(nwGUI.docEditor, c, delay=typeDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)
    qtbot.keyClick(nwGUI.docEditor, Qt.Key_Return, delay=keyDelay)

    qtbot.wait(stepDelay)
    nwGUI.docEditor.wCounter.run()
    qtbot.wait(stepDelay)

    # Save the document
    assert nwGUI.docEditor.docChanged
    assert nwGUI.saveDocument()
    assert not nwGUI.docEditor.docChanged
    qtbot.wait(stepDelay)
    nwGUI.rebuildIndex()
    qtbot.wait(stepDelay)

    # Open and view the edited document
    nwGUI.switchFocus(nwWidget.VIEWER)
    assert nwGUI.openDocument("0e17daca5f3e1")
    assert nwGUI.viewDocument("0e17daca5f3e1")
    qtbot.wait(stepDelay)
    assert nwGUI.saveProject()
    assert nwGUI.closeDocViewer()
    qtbot.wait(stepDelay)

    # Check a Quick Create and Delete
    assert nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
    newHandle = nwGUI.treeView.getSelectedHandle()
    assert nwGUI.theProject.projTree["2858dcd1057d3"] is not None
    assert nwGUI.treeView.deleteItem()
    assert nwGUI.treeView.setSelectedHandle(newHandle)
    assert nwGUI.treeView.deleteItem()
    assert nwGUI.theProject.projTree["2fca346db6561"] is not None  # Trash
    assert nwGUI.saveProject()

    # Check the files
    projFile = os.path.join(fncProj, "nwProject.nwx")
    testFile = os.path.join(outDir, "guiEditor_Main_Final_nwProject.nwx")
    compFile = os.path.join(refDir, "guiEditor_Main_Final_nwProject.nwx")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile, [2, 6, 7, 8])

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

    projFile = os.path.join(fncProj, "content", "1a6562590ef19.nwd")
    testFile = os.path.join(outDir, "guiEditor_Main_Final_1a6562590ef19.nwd")
    compFile = os.path.join(refDir, "guiEditor_Main_Final_1a6562590ef19.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    projFile = os.path.join(fncProj, "content", "0e17daca5f3e1.nwd")
    testFile = os.path.join(outDir, "guiEditor_Main_Final_0e17daca5f3e1.nwd")
    compFile = os.path.join(refDir, "guiEditor_Main_Final_0e17daca5f3e1.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    projFile = os.path.join(fncProj, "content", "41cfc0d1f2d12.nwd")
    testFile = os.path.join(outDir, "guiEditor_Main_Final_41cfc0d1f2d12.nwd")
    compFile = os.path.join(refDir, "guiEditor_Main_Final_41cfc0d1f2d12.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)
示例#24
0
def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir, filesDir):
    """Test config intialisation.
    """
    tstConf = Config()

    confFile = os.path.join(tmpDir, "novelwriter.conf")
    testFile = os.path.join(outDir, "baseConfig_novelwriter.conf")
    compFile = os.path.join(refDir, "baseConfig_novelwriter.conf")

    # Make sure we don't have any old conf file
    if os.path.isfile(confFile):
        os.unlink(confFile)

    # Let the config class figure out the path
    with monkeypatch.context() as mp:
        mp.setattr("PyQt5.QtCore.QStandardPaths.writableLocation", lambda *args: fncDir)
        tstConf.verQtValue = 50600
        tstConf.initConfig()
        assert tstConf.confPath == os.path.join(fncDir, tstConf.appHandle)
        assert tstConf.dataPath == os.path.join(fncDir, tstConf.appHandle)
        assert not os.path.isfile(confFile)
        tstConf.verQtValue = 50000
        tstConf.initConfig()
        assert tstConf.confPath == os.path.join(fncDir, tstConf.appHandle)
        assert tstConf.dataPath == os.path.join(fncDir, tstConf.appHandle)
        assert not os.path.isfile(confFile)

    # Fail to make folders
    with monkeypatch.context() as mp:
        mp.setattr("os.mkdir", causeOSError)

        tstConfDir = os.path.join(fncDir, "test_conf")
        tstConf.initConfig(confPath=tstConfDir, dataPath=tmpDir)
        assert tstConf.confPath is None
        assert tstConf.dataPath == tmpDir
        assert not os.path.isfile(confFile)

        tstDataDir = os.path.join(fncDir, "test_data")
        tstConf.initConfig(confPath=tmpDir, dataPath=tstDataDir)
        assert tstConf.confPath == tmpDir
        assert tstConf.dataPath is None
        assert os.path.isfile(confFile)
        os.unlink(confFile)

    # Test load/save with no path
    tstConf.confPath = None
    assert not tstConf.loadConfig()
    assert not tstConf.saveConfig()

    # Run again and set the paths directly and correctly
    # This should create a config file as well
    with monkeypatch.context() as mp:
        mp.setattr("os.path.expanduser", lambda *args: "")
        tstConf.spellTool = nwConst.SP_INTERNAL
        tstConf.initConfig(confPath=tmpDir, dataPath=tmpDir)
        assert tstConf.confPath == tmpDir
        assert tstConf.dataPath == tmpDir
        assert os.path.isfile(confFile)

        copyfile(confFile, testFile)
        assert cmpFiles(testFile, compFile, [2, 9, 10])

    # Load and save with OSError
    with monkeypatch.context() as mp:
        mp.setattr("builtins.open", causeOSError)

        assert not tstConf.loadConfig()
        assert tstConf.hasError is True
        assert tstConf.errData != []
        assert tstConf.getErrData().startswith("Could not")
        assert tstConf.hasError is False
        assert tstConf.errData == []

        assert not tstConf.saveConfig()
        assert tstConf.hasError is True
        assert tstConf.errData != []
        assert tstConf.getErrData().startswith("Could not")
        assert tstConf.hasError is False
        assert tstConf.errData == []

    assert tstConf.loadConfig()
    assert tstConf.saveConfig()

    # Test Correcting Quote Settings
    origDbl = tstConf.fmtDoubleQuotes
    origSng = tstConf.fmtSingleQuotes
    orDoDbl = tstConf.doReplaceDQuote
    orDoSng = tstConf.doReplaceSQuote

    tstConf.fmtDoubleQuotes = ["\"", "\""]
    tstConf.fmtSingleQuotes = ["'", "'"]
    tstConf.doReplaceDQuote = True
    tstConf.doReplaceSQuote = True
    assert tstConf.saveConfig()

    assert tstConf.loadConfig()
    assert not tstConf.doReplaceDQuote
    assert not tstConf.doReplaceSQuote

    tstConf.fmtDoubleQuotes = origDbl
    tstConf.fmtSingleQuotes = origSng
    tstConf.doReplaceDQuote = orDoDbl
    tstConf.doReplaceSQuote = orDoSng
    assert tstConf.saveConfig()

    # Localisation
    i18nDir = os.path.join(fncDir, "i18n")
    os.mkdir(i18nDir)
    os.mkdir(os.path.join(i18nDir, "stuff"))
    tstConf.nwLangPath = i18nDir

    copyfile(os.path.join(filesDir, "nw_en_GB.qm"), os.path.join(fncDir, "nw_en_GB.qm"))
    writeFile(os.path.join(i18nDir, "nw_en_GB.ts"), "")
    writeFile(os.path.join(i18nDir, "nw_abcd.qm"), "")

    tstApp = DummyApp()
    tstConf.initLocalisation(tstApp)
    theList = tstConf.listLanguages(tstConf.LANG_NW)
    assert theList == [("en_GB", "British English")]

    copyfile(confFile, testFile)
    assert cmpFiles(testFile, compFile, [2, 9, 10])
示例#25
0
def testCoreIndex_LoadSave(monkeypatch, nwLipsum, mockGUI, outDir, refDir):
    """Test core functionality of scaning, saving, loading and checking
    the index cache file.
    """
    projFile = os.path.join(nwLipsum, "meta", "tagsIndex.json")
    testFile = os.path.join(outDir, "coreIndex_LoadSave_tagsIndex.json")
    compFile = os.path.join(refDir, "coreIndex_LoadSave_tagsIndex.json")

    theProject = NWProject(mockGUI)
    assert theProject.openProject(nwLipsum)

    theIndex = NWIndex(theProject)
    assert repr(theIndex) == "<NWIndex project='Lorem Ipsum'>"

    notIndexable = {
        "b3643d0f92e32": False,  # Novel ROOT
        "45e6b01ca35c1": False,  # Chapter One FOLDER
        "6bd935d2490cd": False,  # Chapter Two FOLDER
        "67a8707f2f249": False,  # Character ROOT
        "6c6afb1247750": False,  # Plot ROOT
        "60bdf227455cc": False,  # World ROOT
    }
    for tItem in theProject.tree:
        assert theIndex.reIndexHandle(tItem.itemHandle) is notIndexable.get(
            tItem.itemHandle, True)

    assert theIndex.reIndexHandle(None) is False

    # Make the save fail
    with monkeypatch.context() as mp:
        mp.setattr("builtins.open", causeException)
        assert theIndex.saveIndex() is False

    # Make the save pass
    assert theIndex.saveIndex() is True

    # Take a copy of the index
    tagIndex = str(theIndex._tagsIndex.packData())
    itemsIndex = str(theIndex._itemIndex.packData())

    # Delete a handle
    assert theIndex._tagsIndex["Bod"] is not None
    assert theIndex._itemIndex["4c4f28287af27"] is not None
    theIndex.deleteHandle("4c4f28287af27")
    assert theIndex._tagsIndex["Bod"] is None
    assert theIndex._itemIndex["4c4f28287af27"] is None

    # Clear the index
    theIndex.clearIndex()
    assert theIndex._tagsIndex._tags == {}
    assert theIndex._itemIndex._items == {}

    # Make the load fail
    with monkeypatch.context() as mp:
        mp.setattr(json, "load", causeException)
        assert theIndex.loadIndex() is False
        assert theIndex.indexBroken is True

    # Make the load pass
    assert theIndex.loadIndex() is True
    assert theIndex.indexBroken is False

    assert str(theIndex._tagsIndex.packData()) == tagIndex
    assert str(theIndex._itemIndex.packData()) == itemsIndex

    # Check File
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, compFile)

    # Write an emtpy index file and load it
    writeFile(projFile, "{}")
    assert theIndex.loadIndex() is False
    assert theIndex.indexBroken is True

    # Write an index file that passes loading, but is still empty
    writeFile(projFile, '{"tagsIndex": {}, "itemIndex": {}}')
    assert theIndex.loadIndex() is True
    assert theIndex.indexBroken is False

    # Check that the index is re-populated
    assert "04468803b92e1" in theIndex._itemIndex
    assert "2426c6f0ca922" in theIndex._itemIndex
    assert "441420a886d82" in theIndex._itemIndex
    assert "47666c91c7ccf" in theIndex._itemIndex
    assert "4c4f28287af27" in theIndex._itemIndex
    assert "846352075de7d" in theIndex._itemIndex
    assert "88243afbe5ed8" in theIndex._itemIndex
    assert "88d59a277361b" in theIndex._itemIndex
    assert "8c58a65414c23" in theIndex._itemIndex
    assert "db7e733775d4d" in theIndex._itemIndex
    assert "eb103bc70c90c" in theIndex._itemIndex
    assert "f8c0562e50f1b" in theIndex._itemIndex
    assert "f96ec11c6a3da" in theIndex._itemIndex
    assert "fb609cd8319dc" in theIndex._itemIndex
    assert "7a992350f3eb6" in theIndex._itemIndex

    # Finalise
    assert theProject.closeProject() is True