예제 #1
0
def testConfigSetPanePos(tmpConf, nwTemp, nwRef):
    refConf = os.path.join(nwRef, "novelwriter.conf")
    testConf = os.path.join(tmpConf.confPath, "novelwriter.conf")

    assert tmpConf.confPath == nwTemp

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

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

    assert tmpConf.setViewPanePos([400, 250])
    assert tmpConf.viewPanePos == [200, 125]
    assert tmpConf.getViewPanePos() == [400, 250]

    assert tmpConf.setOutlinePanePos([400, 250])
    assert tmpConf.outlnPanePos == [200, 125]
    assert tmpConf.getOutlinePanePos() == [400, 250]

    tmpConf.guiScale = 1.0
    assert tmpConf.setMainPanePos([300, 800])
    assert tmpConf.setDocPanePos([400, 400])
    assert tmpConf.setViewPanePos([500, 150])
    assert tmpConf.setOutlinePanePos([500, 150])

    assert tmpConf.confChanged
    assert tmpConf.saveConfig()

    assert cmpFiles(testConf, refConf, [2])
    assert not tmpConf.confChanged
예제 #2
0
def testProjectNewFile(nwFuncTemp, nwTempProj, nwRef, nwDummy):
    """Check that new files can be added to the project.
    """
    projFile = os.path.join(nwFuncTemp, "nwProject.nwx")
    testFile = os.path.join(nwTempProj, "3_nwProject.nwx")
    refFile  = os.path.join(nwRef, "proj", "3_nwProject.nwx")

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

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

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

    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile, [2, 6, 7, 8])
    assert not theProject.projChanged
예제 #3
0
def testProjectNewRoot(nwFuncTemp, nwTempProj, nwRef, nwDummy):
    """Check that new root folders can be added to the project.
    """
    projFile = os.path.join(nwFuncTemp, "nwProject.nwx")
    testFile = os.path.join(nwTempProj, "2_nwProject.nwx")
    refFile  = os.path.join(nwRef, "proj", "2_nwProject.nwx")

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

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

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

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

    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile, [2, 6, 7, 8])
    assert not theProject.projChanged
예제 #4
0
def testProjectNewOpenSave(nwFuncTemp, nwTempProj, nwRef, nwTemp, nwDummy):
    """Test that a basic project can be created, and opened and saved.
    """
    projFile = os.path.join(nwFuncTemp, "nwProject.nwx")
    testFile = os.path.join(nwTempProj, "1_nwProject.nwx")
    refFile  = os.path.join(nwRef, "proj", "1_nwProject.nwx")

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

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

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

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

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

    # Open again
    assert theProject.openProject(projFile)

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

    # Open a second time
    assert theProject.openProject(projFile)
    assert not theProject.openProject(projFile)
    assert theProject.openProject(projFile, overrideLock=True)
    assert theProject.saveProject()
    assert theProject.closeProject()
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile, [2, 6, 7, 8])
예제 #5
0
def testConfigCore(tmpConf, nwTemp, nwRef):
    refConf = os.path.join(nwRef, "novelwriter.conf")
    testConf = os.path.join(tmpConf.confPath, "novelwriter.conf")

    assert tmpConf.confPath == nwTemp
    assert tmpConf.saveConfig()
    assert cmpFiles(testConf, refConf, [2])
    assert not tmpConf.confChanged

    assert tmpConf.loadConfig()
    assert not tmpConf.confChanged
예제 #6
0
def testConfigSetWinSize(tmpConf, nwTemp, nwRef):
    refConf = os.path.join(nwRef, "novelwriter.conf")
    testConf = os.path.join(tmpConf.confPath, "novelwriter.conf")
    tmpConf.guiScale = 1.0

    assert tmpConf.confPath == nwTemp
    assert tmpConf.setWinSize(1105, 655)
    assert not tmpConf.confChanged
    assert tmpConf.setWinSize(70, 70)
    assert tmpConf.confChanged
    assert tmpConf.setWinSize(1100, 650)
    assert tmpConf.saveConfig()

    assert cmpFiles(testConf, refConf, [2])
    assert not tmpConf.confChanged
예제 #7
0
def testProjectBackup(nwDummy, nwMinimal, nwTemp):
    """Test the automated backup feature of the project class. The test
    creates a backup of the Minimal test project, and then unzips the
    backupd file and checks that the project XML file is identical to
    the original file.
    """
    theProject = NWProject(nwDummy)
    assert theProject.openProject(nwMinimal)

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

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

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

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

    # Test correct settings
    theProject.mainConf.backupPath = nwTemp
    assert theProject.zipIt(doNotify=False)

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

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

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

    # Check that the main project file was restored
    assert cmpFiles(
        os.path.join(nwMinimal, "nwProject.nwx"), os.path.join(nwTemp, "extract", "nwProject.nwx")
    )
예제 #8
0
def testConfigSetTreeColWidths(tmpConf, nwTemp, nwRef):
    refConf = os.path.join(nwRef, "novelwriter.conf")
    testConf = os.path.join(tmpConf.confPath, "novelwriter.conf")

    assert tmpConf.confPath == nwTemp
    tmpConf.guiScale = 1.0

    assert tmpConf.setTreeColWidths([10, 20, 30])
    assert tmpConf.treeColWidth == [10, 20, 30]
    assert tmpConf.setTreeColWidths([120, 30, 50])

    assert tmpConf.setProjColWidths([10, 20, 30])
    assert tmpConf.projColWidth == [10, 20, 30]
    assert tmpConf.setProjColWidths([140, 55, 140])

    assert tmpConf.confChanged
    assert tmpConf.saveConfig()

    assert cmpFiles(testConf, refConf, [2])
    assert not tmpConf.confChanged
예제 #9
0
def testConfigFlags(tmpConf, nwTemp, nwRef):
    refConf = os.path.join(nwRef, "novelwriter.conf")
    testConf = os.path.join(tmpConf.confPath, "novelwriter.conf")

    assert tmpConf.confPath == nwTemp

    assert not tmpConf.setShowRefPanel(False)
    assert tmpConf.setShowRefPanel(True)

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

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

    assert tmpConf.confChanged
    assert tmpConf.saveConfig()

    assert cmpFiles(testConf, refConf, [2])
    assert not tmpConf.confChanged
예제 #10
0
def testProjectNewCustomB(nwFuncTemp, nwTempProj, nwRef, nwDummy):
    """Create a new project from a project wizard dictionary.
    Custom type without chapters, but with scenes.
    """
    projFile = os.path.join(nwFuncTemp, "nwProject.nwx")
    testFile = os.path.join(nwTempProj, "5_nwProject.nwx")
    refFile  = os.path.join(nwRef, "proj", "5_nwProject.nwx")

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

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

    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile, [2, 6, 7, 8])
예제 #11
0
def testMergeSplitTools(qtbot, monkeypatch, yesToAll, nwTempGUI, nwLipsum, nwRef, nwTemp):

    nwGUI = nw.main(["--testmode", "--config=%s" % nwLipsum, "--data=%s" % nwTemp])
    qtbot.addWidget(nwGUI)
    nwGUI.show()
    qtbot.waitForWindowShown(nwGUI)
    qtbot.wait(stepDelay)

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

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

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

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

    nwMerge._doMerge()
    qtbot.wait(stepDelay)

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

    projFile = os.path.join(nwLipsum, "content", "73475cb40a568.nwd")
    testFile = os.path.join(nwTempGUI, "4_73475cb40a568.nwd")
    refFile  = os.path.join(nwRef, "gui", "4_73475cb40a568.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)

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

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

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

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

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

    # This should give us back the file as it was before
    projFile = os.path.join(nwLipsum, "content", "71ee45a3c0db9.nwd")
    testFile = os.path.join(nwTempGUI, "4_71ee45a3c0db9.nwd")
    refFile  = os.path.join(nwRef, "gui", "4_73475cb40a568.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile, [1, 2, 3])

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

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

    nwSplit._doSplit()

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

    projFile = os.path.join(nwLipsum, "content", "25fc0e7096fc6.nwd")
    testFile = os.path.join(nwTempGUI, "5_25fc0e7096fc6.nwd")
    refFile  = os.path.join(nwRef, "gui", "5_25fc0e7096fc6.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)

    projFile = os.path.join(nwLipsum, "content", "31489056e0916.nwd")
    testFile = os.path.join(nwTempGUI, "5_31489056e0916.nwd")
    refFile  = os.path.join(nwRef, "gui", "5_31489056e0916.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)

    projFile = os.path.join(nwLipsum, "content", "98010bd9270f9.nwd")
    testFile = os.path.join(nwTempGUI, "5_98010bd9270f9.nwd")
    refFile  = os.path.join(nwRef, "gui", "5_98010bd9270f9.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)

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

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

    nwSplit._doSplit()

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

    projFile = os.path.join(nwLipsum, "content", "1a6562590ef19.nwd")
    testFile = os.path.join(nwTempGUI, "5_25fc0e7096fc6.nwd")
    refFile  = os.path.join(nwRef, "gui", "5_25fc0e7096fc6.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile, [1, 2, 3])

    projFile = os.path.join(nwLipsum, "content", "031b4af5197ec.nwd")
    testFile = os.path.join(nwTempGUI, "5_031b4af5197ec.nwd")
    refFile  = os.path.join(nwRef, "gui", "5_031b4af5197ec.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)

    projFile = os.path.join(nwLipsum, "content", "41cfc0d1f2d12.nwd")
    testFile = os.path.join(nwTempGUI, "5_41cfc0d1f2d12.nwd")
    refFile  = os.path.join(nwRef, "gui", "5_41cfc0d1f2d12.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)

    projFile = os.path.join(nwLipsum, "content", "2858dcd1057d3.nwd")
    testFile = os.path.join(nwTempGUI, "5_2858dcd1057d3.nwd")
    refFile  = os.path.join(nwRef, "gui", "5_2858dcd1057d3.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)

    projFile = os.path.join(nwLipsum, "content", "2fca346db6561.nwd")
    testFile = os.path.join(nwTempGUI, "5_2fca346db6561.nwd")
    refFile  = os.path.join(nwRef, "gui", "5_2fca346db6561.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)

    # qtbot.stopForInteraction()
    nwGUI.closeMain()
예제 #12
0
def testBuildTool(qtbot, yesToAll, nwTempBuild, nwLipsum, nwRef, nwTemp):

    nwGUI = nw.main(["--testmode", "--config=%s" % nwLipsum, "--data=%s" % nwTemp])
    qtbot.addWidget(nwGUI)
    nwGUI.show()
    qtbot.waitForWindowShown(nwGUI)
    qtbot.wait(stepDelay)

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

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

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

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

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

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

    projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd")
    testFile = os.path.join(nwTempBuild, "1_LoremIpsum.nwd")
    refFile  = os.path.join(nwRef, "build", "1_LoremIpsum.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)

    projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm")
    testFile = os.path.join(nwTempBuild, "1_LoremIpsum.htm")
    refFile  = os.path.join(nwRef, "build", "1_LoremIpsum.htm")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)

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

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

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

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

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

    projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd")
    testFile = os.path.join(nwTempBuild, "2_LoremIpsum.nwd")
    refFile  = os.path.join(nwRef, "build", "2_LoremIpsum.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)

    projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm")
    testFile = os.path.join(nwTempBuild, "2_LoremIpsum.htm")
    refFile  = os.path.join(nwRef, "build", "2_LoremIpsum.htm")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)

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

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

    # Save files that can be compared
    assert nwBuild._saveDocument(nwBuild.FMT_NWD)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd")
    testFile = os.path.join(nwTempBuild, "3_LoremIpsum.nwd")
    refFile  = os.path.join(nwRef, "build", "3_LoremIpsum.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)

    assert nwBuild._saveDocument(nwBuild.FMT_HTM)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm")
    testFile = os.path.join(nwTempBuild, "3_LoremIpsum.htm")
    refFile  = os.path.join(nwRef, "build", "3_LoremIpsum.htm")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)

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

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

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

    # Save files that can be compared
    assert nwBuild._saveDocument(nwBuild.FMT_NWD)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.nwd")
    testFile = os.path.join(nwTempBuild, "4_LoremIpsum.nwd")
    refFile  = os.path.join(nwRef, "build", "4_LoremIpsum.nwd")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)

    assert nwBuild._saveDocument(nwBuild.FMT_HTM)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.htm")
    testFile = os.path.join(nwTempBuild, "4_LoremIpsum.htm")
    refFile  = os.path.join(nwRef, "build", "4_LoremIpsum.htm")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)

    # Check the JSON files too at this stage
    assert nwBuild._saveDocument(nwBuild.FMT_JSON_H)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.json")
    testFile = os.path.join(nwTempBuild, "4H_LoremIpsum.json")
    refFile  = os.path.join(nwRef, "build", "4H_LoremIpsum.json")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile, [8])

    assert nwBuild._saveDocument(nwBuild.FMT_JSON_M)
    projFile = os.path.join(nwLipsum, "Lorem Ipsum.json")
    testFile = os.path.join(nwTempBuild, "4M_LoremIpsum.json")
    refFile  = os.path.join(nwRef, "build", "4M_LoremIpsum.json")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile, [8])

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

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

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

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

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

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

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

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

    nwBuild._doClose()

    # qtbot.stopForInteraction()
    nwGUI.closeMain()
예제 #13
0
def testProjectSettings(qtbot, monkeypatch, yesToAll, nwFuncTemp, nwTempGUI, nwRef, nwTemp):
    nwGUI = nw.main(["--testmode", "--config=%s" % nwTemp, "--data=%s" % nwTemp])
    qtbot.addWidget(nwGUI)
    nwGUI.show()
    qtbot.waitForWindowShown(nwGUI)
    qtbot.wait(stepDelay)

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

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

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

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

    # Main settings
    qtbot.wait(stepDelay)
    projEdit.tabMain.editName.setText("")
    for c in "Project Name":
        qtbot.keyClick(projEdit.tabMain.editName, c, delay=typeDelay)
    for c in "Project Title":
        qtbot.keyClick(projEdit.tabMain.editTitle, c, delay=typeDelay)
    for c in "Jane Doe":
        qtbot.keyClick(projEdit.tabMain.editAuthors, c, delay=typeDelay)
    qtbot.keyClick(projEdit.tabMain.editAuthors, Qt.Key_Return, delay=keyDelay)
    for c in "John Doh":
        qtbot.keyClick(projEdit.tabMain.editAuthors, c, delay=typeDelay)

    # Test Status Tab
    qtbot.wait(stepDelay)
    projEdit._tabBox.setCurrentWidget(projEdit.tabStatus)
    projEdit.tabStatus.listBox.item(2).setSelected(True)
    qtbot.mouseClick(projEdit.tabStatus.delButton, Qt.LeftButton)
    qtbot.mouseClick(projEdit.tabStatus.newButton, Qt.LeftButton)
    projEdit.tabStatus.listBox.item(3).setSelected(True)
    for n in range(8):
        qtbot.keyClick(projEdit.tabStatus.editName, Qt.Key_Backspace, delay=typeDelay)
    for c in "Final":
        qtbot.keyClick(projEdit.tabStatus.editName, c, delay=typeDelay)
    qtbot.mouseClick(projEdit.tabStatus.saveButton, Qt.LeftButton)

    # Auto-Replace Tab
    qtbot.wait(stepDelay)
    projEdit._tabBox.setCurrentWidget(projEdit.tabReplace)

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

    qtbot.wait(stepDelay)
    projEdit.tabReplace.listBox.clearSelection()
    qtbot.mouseClick(projEdit.tabReplace.addButton, Qt.LeftButton)

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

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

    qtbot.wait(stepDelay)
    projEdit._doSave()

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

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

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

    projEdit._doClose()

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

    # Check the files
    projFile = os.path.join(nwFuncTemp, "nwProject.nwx")
    testFile = os.path.join(nwTempGUI, "2_nwProject.nwx")
    refFile  = os.path.join(nwRef, "gui", "2_nwProject.nwx")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile, [2, 8, 9, 10])

    # qtbot.stopForInteraction()
    nwGUI.closeMain()
예제 #14
0
def testItemEditor(qtbot, yesToAll, monkeypatch, nwFuncTemp, nwTempGUI, nwRef, nwTemp):
    nwGUI = nw.main(["--testmode", "--config=%s" % nwTemp, "--data=%s" % nwTemp])
    qtbot.addWidget(nwGUI)
    nwGUI.show()
    qtbot.waitForWindowShown(nwGUI)
    qtbot.wait(stepDelay)

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

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

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

    qtbot.addWidget(itemEdit)

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

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

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

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

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

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

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

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

    # Check the files
    projFile = os.path.join(nwFuncTemp, "nwProject.nwx")
    testFile = os.path.join(nwTempGUI, "3_nwProject.nwx")
    refFile  = os.path.join(nwRef, "gui", "3_nwProject.nwx")
    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile, [2, 6, 7, 8])

    # qtbot.stopForInteraction()
    nwGUI.closeMain()
예제 #15
0
def testPreferences(qtbot, monkeypatch, yesToAll, nwMinimal, nwTemp, nwRef, tmpConf):
    nwGUI = nw.main(["--testmode", "--config=%s" % nwMinimal, "--data=%s" % nwTemp])
    qtbot.addWidget(nwGUI)
    nwGUI.show()
    qtbot.waitForWindowShown(nwGUI)
    qtbot.wait(stepDelay)

    assert nwGUI.openProject(nwMinimal)

    monkeypatch.setattr(GuiPreferences, "exec_", lambda *args: None)
    monkeypatch.setattr(GuiPreferences, "result", lambda *args: QDialog.Accepted)
    nwGUI.mainMenu.aPreferences.activate(QAction.Trigger)
    qtbot.waitUntil(lambda: getGuiItem("GuiPreferences") is not None, timeout=1000)

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

    # Override Config
    tmpConf.confPath = nwMinimal
    tmpConf.showGUI = False
    nwGUI.mainConf = tmpConf
    nwPrefs.mainConf = tmpConf
    nwPrefs.tabGeneral.mainConf = tmpConf
    nwPrefs.tabProjects.mainConf = tmpConf
    nwPrefs.tabLayout.mainConf = tmpConf
    nwPrefs.tabEditing.mainConf = tmpConf
    nwPrefs.tabAutoRep.mainConf = tmpConf

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

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

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

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

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

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

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

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

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

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

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

    # Text Layout Settings
    qtbot.wait(keyDelay)
    tabLayout = nwPrefs.tabLayout
    nwPrefs._tabBox.setCurrentWidget(tabLayout)

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

    qtbot.wait(keyDelay)
    tabLayout.textStyleSize.setValue(13)
    tabLayout.textFlowMax.setValue(700)
    tabLayout.focusDocWidth.setValue(900)
    tabLayout.textMargin.setValue(45)
    tabLayout.tabWidth.setValue(45)

    qtbot.wait(keyDelay)
    assert not tabLayout.textFlowFixed.isChecked()
    qtbot.mouseClick(tabLayout.textFlowFixed, Qt.LeftButton)
    assert tabLayout.textFlowFixed.isChecked()

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

    qtbot.wait(keyDelay)
    assert tabLayout.textJustify.isChecked()
    qtbot.mouseClick(tabLayout.textJustify, Qt.LeftButton)
    assert not tabLayout.textJustify.isChecked()

    qtbot.wait(keyDelay)
    assert tabLayout.scrollPastEnd.isChecked()
    qtbot.mouseClick(tabLayout.scrollPastEnd, Qt.LeftButton)
    assert not tabLayout.scrollPastEnd.isChecked()

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

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

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

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

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

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

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

    # Auto-Replace Settings
    qtbot.wait(keyDelay)
    tabAutoRep = nwPrefs.tabAutoRep
    nwPrefs._tabBox.setCurrentWidget(tabAutoRep)

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

    qtbot.wait(keyDelay)
    assert tabAutoRep.autoReplaceMain.isChecked()
    qtbot.mouseClick(tabAutoRep.autoReplaceMain, Qt.LeftButton)
    assert not tabAutoRep.autoReplaceMain.isChecked()

    qtbot.wait(keyDelay)
    assert not tabAutoRep.autoReplaceSQ.isEnabled()
    assert not tabAutoRep.autoReplaceDQ.isEnabled()
    assert not tabAutoRep.autoReplaceDash.isEnabled()
    assert not tabAutoRep.autoReplaceDots.isEnabled()

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

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

    assert tmpConf.confChanged
    tmpConf.lastPath = ""

    assert nwGUI.mainConf.saveConfig()

    # qtbot.stopForInteraction()
    nwGUI.closeMain()

    refConf = os.path.join(nwRef, "novelwriter_prefs.conf")
    projConf = os.path.join(nwGUI.mainConf.confPath, "novelwriter.conf")
    testConf = os.path.join(nwTemp, "novelwriter_prefs.conf")
    copyfile(projConf, testConf)
    ignoreLines = [
        2,                          # Timestamp
        11, 12, 13, 14, 15, 16, 17, # Window sizes
        7, 27,                      # Fonts (depends on system default)
    ]
    assert cmpFiles(testConf, refConf, ignoreLines)
예제 #16
0
def testIndexBuildCheck(monkeypatch, nwLipsum, nwDummy, nwTempProj, nwRef):
    """Test core functionality of scaning, saving, loading and checking
    the index cache file.
    """
    projFile = os.path.join(nwLipsum, "meta", "tagsIndex.json")
    testFile = os.path.join(nwTempProj, "1_tagsIndex.json")
    refFile  = os.path.join(nwRef, "proj", "1_tagsIndex.json")

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

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

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

    assert not theIndex.reIndexHandle(None)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    # Finalise
    assert theProject.closeProject()

    copyfile(projFile, testFile)
    assert cmpFiles(testFile, refFile)