Пример #1
0
def testIndexCheckThese(nwMinimal, nwDummy):
    """Test the tag checker function checkThese.
    """
    theProject = NWProject(nwDummy)
    theProject.projTree.setSeed(42)
    assert theProject.openProject(nwMinimal)

    theIndex = NWIndex(theProject, nwDummy)
    nHandle = theProject.newFile("Hello", nwItemClass.NOVEL,     "a508bb932959c")
    cHandle = theProject.newFile("Jane",  nwItemClass.CHARACTER, "afb3043c7b2b3")
    nItem = theProject.projTree[nHandle]
    cItem = theProject.projTree[cHandle]

    assert theIndex.scanText(cHandle, (
        "# Jane Smith\n"
        "@tag: Jane"
    ))
    assert theIndex.scanText(nHandle, (
        "# Hello World!\n"
        "@pov: Jane"
    ))
    assert str(theIndex.tagIndex) == "{'Jane': [2, '%s', 'CHARACTER', 'T000001']}" % cHandle
    assert theIndex.novelIndex[nHandle]["T000001"]["title"] == "Hello World!"

    assert str(theIndex.checkThese(["@tag",  "Jane"], cItem)) == "[True, True]"
    assert str(theIndex.checkThese(["@tag",  "John"], cItem)) == "[True, True]"
    assert str(theIndex.checkThese(["@tag",  "Jane"], nItem)) == "[True, False]"
    assert str(theIndex.checkThese(["@tag",  "John"], nItem)) == "[True, True]"
    assert str(theIndex.checkThese(["@pov",  "John"], nItem)) == "[True, False]"
    assert str(theIndex.checkThese(["@pov",  "Jane"], nItem)) == "[True, True]"
    assert str(theIndex.checkThese(["@ pov", "Jane"], nItem)) == "[False, False]"
    assert str(theIndex.checkThese(["@what", "Jane"], nItem)) == "[False, False]"

    assert theProject.closeProject()
Пример #2
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
Пример #3
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
Пример #4
0
def testCoreProject_NewSampleB(monkeypatch, fncDir, tmpConf, dummyGUI, tmpDir):
    """Check that we can create a new project can be created from the
    provided sample project folder.
    """
    projData = {
        "projName": "Test Sample",
        "projTitle": "Test Novel",
        "projAuthors": "Jane Doe\nJohn Doh\n",
        "projPath": fncDir,
        "popSample": True,
        "popMinimal": False,
        "popCustom": False,
    }
    theProject = NWProject(dummyGUI)
    theProject.projTree.setSeed(42)
    theProject.mainConf = tmpConf

    # Make sure we do not pick up the nw/assets/sample.zip file
    tmpConf.assetPath = tmpDir

    # Set a fake project file name
    monkeypatch.setattr(nwFiles, "PROJ_FILE", "nothing.nwx")
    assert not theProject.newProject(projData)

    monkeypatch.setattr(nwFiles, "PROJ_FILE", "nwProject.nwx")
    assert theProject.newProject(projData)
    assert theProject.openProject(fncDir)
    assert theProject.projName == "Sample Project"
    assert theProject.saveProject()
    assert theProject.closeProject()

    # Misdirect the appRoot path so neither is possible
    tmpConf.appRoot = tmpDir
    assert not theProject.newProject(projData)
Пример #5
0
def testCoreTree_Reorder(dummyGUI, dummyItems):
    """Test changing tree order.
    """
    theProject = NWProject(dummyGUI)
    theTree = NWTree(theProject)

    aHandle = []
    for tHandle, pHande, nwItem in dummyItems:
        aHandle.append(tHandle)
        theTree.append(tHandle, pHande, nwItem)

    assert len(theTree) == len(dummyItems)

    bHandle = aHandle.copy()
    bHandle[2], bHandle[3] = bHandle[3], bHandle[2]
    assert aHandle != bHandle

    assert theTree.handles() == aHandle
    theTree.setOrder(bHandle)
    assert theTree.handles() == bHandle

    theTree.setOrder(bHandle + ["dummy"])
    assert theTree.handles() == bHandle

    theTree._treeOrder.append("dummy")
    theTree.setOrder(bHandle)
    assert theTree.handles() == bHandle
Пример #6
0
def testItemLayoutSetter(nwDummy):

    theProject = NWProject(nwDummy)
    theItem = NWItem(theProject)

    # Layout
    theItem.setLayout(None)
    assert theItem.itemLayout == nwItemLayout.NO_LAYOUT
    theItem.setLayout("NONSENSE")
    assert theItem.itemLayout == nwItemLayout.NO_LAYOUT
    theItem.setLayout("NO_LAYOUT")
    assert theItem.itemLayout == nwItemLayout.NO_LAYOUT
    theItem.setLayout("TITLE")
    assert theItem.itemLayout == nwItemLayout.TITLE
    theItem.setLayout("BOOK")
    assert theItem.itemLayout == nwItemLayout.BOOK
    theItem.setLayout("PAGE")
    assert theItem.itemLayout == nwItemLayout.PAGE
    theItem.setLayout("PARTITION")
    assert theItem.itemLayout == nwItemLayout.PARTITION
    theItem.setLayout("UNNUMBERED")
    assert theItem.itemLayout == nwItemLayout.UNNUMBERED
    theItem.setLayout("CHAPTER")
    assert theItem.itemLayout == nwItemLayout.CHAPTER
    theItem.setLayout("SCENE")
    assert theItem.itemLayout == nwItemLayout.SCENE
    theItem.setLayout("NOTE")
    assert theItem.itemLayout == nwItemLayout.NOTE
Пример #7
0
def testCoreTree_MakeHandles(monkeypatch, dummyGUI):
    """Test generating item handles.
    """
    theProject = NWProject(dummyGUI)
    theTree = NWTree(theProject)

    theTree.setSeed(42)

    tHandle = theTree._makeHandle()
    assert tHandle == "73475cb40a568"

    # Add the next in line to the project to foprce duplicate
    theTree._projTree["44cb730c42048"] = None
    tHandle = theTree._makeHandle()
    assert tHandle == "71ee45a3c0db9"

    # Fix the time() function and force a handle collission
    theTree.setSeed(None)
    monkeypatch.setattr("nw.core.tree.time", lambda: 123.4)

    tHandle = theTree._makeHandle()
    theTree._projTree[tHandle] = None
    assert tHandle == "5f466d7afa48b"

    tHandle = theTree._makeHandle()
    theTree._projTree[tHandle] = None
    assert tHandle == "a79acf4c634a7"

    monkeypatch.undo()
Пример #8
0
def testItemClassSetter(nwDummy):

    theProject = NWProject(nwDummy)
    theItem = NWItem(theProject)

    # Class
    theItem.setClass(None)
    assert theItem.itemClass == nwItemClass.NO_CLASS
    theItem.setClass("NONSENSE")
    assert theItem.itemClass == nwItemClass.NO_CLASS
    theItem.setClass("NO_CLASS")
    assert theItem.itemClass == nwItemClass.NO_CLASS
    theItem.setClass("NOVEL")
    assert theItem.itemClass == nwItemClass.NOVEL
    theItem.setClass("PLOT")
    assert theItem.itemClass == nwItemClass.PLOT
    theItem.setClass("CHARACTER")
    assert theItem.itemClass == nwItemClass.CHARACTER
    theItem.setClass("WORLD")
    assert theItem.itemClass == nwItemClass.WORLD
    theItem.setClass("TIMELINE")
    assert theItem.itemClass == nwItemClass.TIMELINE
    theItem.setClass("OBJECT")
    assert theItem.itemClass == nwItemClass.OBJECT
    theItem.setClass("ENTITY")
    assert theItem.itemClass == nwItemClass.ENTITY
    theItem.setClass("CUSTOM")
    assert theItem.itemClass == nwItemClass.CUSTOM
    theItem.setClass("ARCHIVE")
    assert theItem.itemClass == nwItemClass.ARCHIVE
    theItem.setClass("TRASH")
    assert theItem.itemClass == nwItemClass.TRASH
Пример #9
0
def testCoreIndex_CheckTagIndex(dummyGUI):
    """Test the tag index checker.
    """
    theProject = NWProject(dummyGUI)
    theIndex = NWIndex(theProject, dummyGUI)

    # Valid Index
    theIndex._tagIndex = {
        "John": [3, "14298de4d9524", "CHARACTER", "T000001"],
        "Jane": [3, "bb2c23b3c42cc", "CHARACTER", "T000001"],
    }
    assert theIndex._checkTagIndex() is None

    # Wrong Key Type
    theIndex._tagIndex = {
        "John": [3, "14298de4d9524", "CHARACTER", "T000001"],
        123456: [3, "bb2c23b3c42cc", "CHARACTER", "T000001"],
    }
    with pytest.raises(KeyError):
        theIndex._checkTagIndex()

    # Wrong Length
    theIndex._tagIndex = {
        "John": [3, "14298de4d9524", "CHARACTER", "T000001"],
        "Jane": [3, "bb2c23b3c42cc", "CHARACTER", "T000001", "Stuff"],
    }
    with pytest.raises(IndexError):
        theIndex._checkTagIndex()

    # Wrong Type of Entry 0
    theIndex._tagIndex = {
        "John": [3, "14298de4d9524", "CHARACTER", "T000001"],
        "Jane": ["3", "bb2c23b3c42cc", "CHARACTER", "T000001"],
    }
    with pytest.raises(ValueError):
        theIndex._checkTagIndex()

    # Wrong Type of Entry 1
    theIndex._tagIndex = {
        "John": [3, "14298de4d9524", "CHARACTER", "T000001"],
        "Jane": [3, 0xbb2c23b3c42cc, "CHARACTER", "T000001"],
    }
    with pytest.raises(ValueError):
        theIndex._checkTagIndex()

    # Wrong Type of Entry 2
    theIndex._tagIndex = {
        "John": [3, "14298de4d9524", "CHARACTER", "T000001"],
        "Jane": [3, "bb2c23b3c42cc", "INVALID_CLASS", "T000001"],
    }
    with pytest.raises(ValueError):
        theIndex._checkTagIndex()

    # Wrong Type of Entry 3
    theIndex._tagIndex = {
        "John": [3, "14298de4d9524", "CHARACTER", "T000001"],
        "Jane": [3, "bb2c23b3c42cc", "CHARACTER", "INVALID"],
    }
    with pytest.raises(ValueError):
        theIndex._checkTagIndex()
Пример #10
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])
Пример #11
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")
    )
Пример #12
0
def testCoreIndex_ScanThis(nwMinimal, dummyGUI):
    """Test the tag scanner function scanThis.
    """
    theProject = NWProject(dummyGUI)
    theProject.projTree.setSeed(42)
    assert theProject.openProject(nwMinimal)

    theIndex = NWIndex(theProject, dummyGUI)

    isValid, theBits, thePos = theIndex.scanThis("tag: this, and this")
    assert not isValid

    isValid, theBits, thePos = theIndex.scanThis("@")
    assert not isValid

    isValid, theBits, thePos = theIndex.scanThis("@:")
    assert not isValid

    isValid, theBits, thePos = theIndex.scanThis(" @a: b")
    assert not isValid

    isValid, theBits, thePos = theIndex.scanThis("@a:")
    assert isValid
    assert theBits == ["@a"]
    assert thePos == [0]

    isValid, theBits, thePos = theIndex.scanThis("@a:b")
    assert isValid
    assert theBits == ["@a", "b"]
    assert thePos == [0, 3]

    isValid, theBits, thePos = theIndex.scanThis("@a:b,c,d")
    assert isValid
    assert theBits == ["@a", "b", "c", "d"]
    assert thePos == [0, 3, 5, 7]

    isValid, theBits, thePos = theIndex.scanThis("@a : b , c , d")
    assert isValid
    assert theBits == ["@a", "b", "c", "d"]
    assert thePos == [0, 5, 9, 13]

    isValid, theBits, thePos = theIndex.scanThis("@tag: this, and this")
    assert isValid
    assert theBits == ["@tag", "this", "and this"]
    assert thePos == [0, 6, 12]

    assert theProject.closeProject()
Пример #13
0
def testIndexScanThis(nwMinimal, nwDummy):
    """Test the tag scanner function scanThis.
    """
    theProject = NWProject(nwDummy)
    theProject.projTree.setSeed(42)
    assert theProject.openProject(nwMinimal)

    theIndex = NWIndex(theProject, nwDummy)

    isValid, theBits, thePos = theIndex.scanThis("tag: this, and this")
    assert not isValid

    isValid, theBits, thePos = theIndex.scanThis("@")
    assert not isValid

    isValid, theBits, thePos = theIndex.scanThis("@:")
    assert not isValid

    isValid, theBits, thePos = theIndex.scanThis(" @a: b")
    assert not isValid

    isValid, theBits, thePos = theIndex.scanThis("@a:")
    assert isValid
    assert str(theBits) == "['@a']"
    assert str(thePos)  == "[0]"

    isValid, theBits, thePos = theIndex.scanThis("@a:b")
    assert isValid
    assert str(theBits) == "['@a', 'b']"
    assert str(thePos)  == "[0, 3]"

    isValid, theBits, thePos = theIndex.scanThis("@a:b,c,d")
    assert isValid
    assert str(theBits) == "['@a', 'b', 'c', 'd']"
    assert str(thePos)  == "[0, 3, 5, 7]"

    isValid, theBits, thePos = theIndex.scanThis("@a : b , c , d")
    assert isValid
    assert str(theBits) == "['@a', 'b', 'c', 'd']"
    assert str(thePos)  == "[0, 5, 9, 13]"

    isValid, theBits, thePos = theIndex.scanThis("@tag: this, and this")
    assert isValid
    assert str(theBits) == "['@tag', 'this', 'and this']"
    assert str(thePos)  == "[0, 6, 12]"

    assert theProject.closeProject()
Пример #14
0
def testCoreTree_ToCFile(monkeypatch, dummyGUI, dummyItems, tmpDir):
    """Test writing the ToC.txt file.
    """
    theProject = NWProject(dummyGUI)
    theTree = NWTree(theProject)

    for tHandle, pHande, nwItem in dummyItems:
        theTree.append(tHandle, pHande, nwItem)

    assert len(theTree) == len(dummyItems)
    theTree._treeOrder.append("dummy")

    def dummyIsFile(fileName):
        """Return True for items that are files in novelWriter and
        should thus also be files in the project folder structure.
        """
        dItem = theTree[fileName[8:21]]
        assert dItem is not None
        return dItem.itemType == nwItemType.FILE

    monkeypatch.setattr("os.path.isfile", dummyIsFile)

    theProject.projContent = "content"
    theProject.projPath = None
    assert not theTree.writeToCFile()

    theProject.projPath = tmpDir
    assert theTree.writeToCFile()

    pathA = os.path.join("content", "c000000000001.nwd")
    pathB = os.path.join("content", "c000000000002.nwd")
    pathC = os.path.join("content", "b000000000002.nwd")

    with open(os.path.join(tmpDir, nwFiles.TOC_TXT), mode="r",
              encoding="utf8") as inFile:
        assert inFile.read() == (
            "\n"
            "Table of Contents\n"
            "=================\n"
            "\n"
            "File Name                  Class      Layout      Document Label\n"
            "-------------------------------------------------------------\n"
            f"{pathA}  NOVEL      CHAPTER     Chapter One\n"
            f"{pathB}  NOVEL      SCENE       Scene One\n"
            f"{pathC}  CHARACTER  NOTE        Jane Doe\n")
Пример #15
0
def testCoreProject_AccessItems(nwMinimal, dummyGUI):
    """Test helper functions for the project folder.
    """
    theProject = NWProject(dummyGUI)
    theProject.openProject(nwMinimal)

    # Move Novel ROOT to after its files
    oldOrder = [
        "a508bb932959c",  # ROOT: Novel
        "a35baf2e93843",  # FILE: Title Page
        "a6d311a93600a",  # FOLDER: New Chapter
        "f5ab3e30151e1",  # FILE: New Chapter
        "8c659a11cd429",  # FILE: New Scene
        "7695ce551d265",  # ROOT: Plot
        "afb3043c7b2b3",  # ROOT: Characters
        "9d5247ab588e0",  # ROOT: World
    ]
    newOrder = [
        "a35baf2e93843",  # FILE: Title Page
        "f5ab3e30151e1",  # FILE: New Chapter
        "8c659a11cd429",  # FILE: New Scene
        "a6d311a93600a",  # FOLDER: New Chapter
        "a508bb932959c",  # ROOT: Novel
        "7695ce551d265",  # ROOT: Plot
        "afb3043c7b2b3",  # ROOT: Characters
        "9d5247ab588e0",  # ROOT: World
    ]
    assert theProject.projTree.handles() == oldOrder
    assert theProject.setTreeOrder(newOrder)
    assert theProject.projTree.handles() == newOrder

    # Add a non-existing item
    theProject.projTree._treeOrder.append("01234567789abc")

    # Add an item with a non-existent parent
    nHandle = theProject.newFile("Test File", nwItemClass.NOVEL,
                                 "a6d311a93600a")
    theProject.projTree[nHandle].setParent("cba9876543210")
    assert theProject.projTree[nHandle].itemParent == "cba9876543210"

    retOrder = []
    for tItem in theProject.getProjectItems():
        retOrder.append(tItem.itemHandle)

    assert retOrder == [
        "a508bb932959c",  # ROOT: Novel
        "7695ce551d265",  # ROOT: Plot
        "afb3043c7b2b3",  # ROOT: Characters
        "9d5247ab588e0",  # ROOT: World
        nHandle,  # FILE: Test File
        "a35baf2e93843",  # FILE: Title Page
        "a6d311a93600a",  # FOLDER: New Chapter
        "f5ab3e30151e1",  # FILE: New Chapter
        "8c659a11cd429",  # FILE: New Scene
    ]
    assert theProject.projTree[nHandle].itemParent is None
Пример #16
0
def testCoreTree_Methods(dummyGUI, dummyItems):
    """Test building a project tree from a list of items.
    """
    theProject = NWProject(dummyGUI)
    theTree = NWTree(theProject)

    for tHandle, pHande, nwItem in dummyItems:
        theTree.append(tHandle, pHande, nwItem)

    assert len(theTree) == len(dummyItems)

    # Root item lookup
    theTree._treeRoots.append("dummy")
    assert theTree.findRoot(nwItemClass.WORLD) is None
    assert theTree.findRoot(nwItemClass.NOVEL) == "a000000000001"
    assert theTree.findRoot(nwItemClass.CHARACTER) == "a000000000004"

    # Check for root uniqueness
    assert theTree.checkRootUnique(nwItemClass.CUSTOM)
    assert theTree.checkRootUnique(nwItemClass.WORLD)
    assert not theTree.checkRootUnique(nwItemClass.NOVEL)
    assert not theTree.checkRootUnique(nwItemClass.CHARACTER)

    # Find root item of child item
    assert theTree.getRootItem("b000000000001").itemHandle == "a000000000001"
    assert theTree.getRootItem("c000000000001").itemHandle == "a000000000001"
    assert theTree.getRootItem("c000000000002").itemHandle == "a000000000001"
    assert theTree.getRootItem("dummy") is None

    # Get item path
    assert theTree.getItemPath("dummy") == []
    assert theTree.getItemPath("c000000000001") == [
        "c000000000001", "b000000000001", "a000000000001"
    ]

    # Break the folder parent handle
    theTree["b000000000001"].itemParent = "dummy"
    assert theTree.getItemPath("c000000000001") == [
        "c000000000001", "b000000000001"
    ]

    theTree["b000000000001"].itemParent = "a000000000001"
    assert theTree.getItemPath("c000000000001") == [
        "c000000000001", "b000000000001", "a000000000001"
    ]

    # Change file layout
    assert not theTree.setFileItemLayout("dummy", nwItemLayout.UNNUMBERED)
    assert not theTree.setFileItemLayout("b000000000001",
                                         nwItemLayout.UNNUMBERED)
    assert not theTree.setFileItemLayout("c000000000001", "stuff")
    assert theTree.setFileItemLayout("c000000000001", nwItemLayout.UNNUMBERED)
    assert theTree["c000000000001"].itemLayout == nwItemLayout.UNNUMBERED
Пример #17
0
def testCoreProject_NewSampleA(fncDir, tmpConf, dummyGUI, tmpDir):
    """Check that we can create a new project can be created from the
    provided sample project via a zip file.
    """
    projData = {
        "projName": "Test Sample",
        "projTitle": "Test Novel",
        "projAuthors": "Jane Doe\nJohn Doh\n",
        "projPath": fncDir,
        "popSample": True,
        "popMinimal": False,
        "popCustom": False,
    }
    theProject = NWProject(dummyGUI)
    theProject.projTree.setSeed(42)
    theProject.mainConf = tmpConf

    # Sample set, but no path
    assert not theProject.newProject({"popSample": True})

    # Force the lookup path for assets to our temp folder
    srcSample = os.path.abspath(os.path.join(tmpConf.appRoot, "sample"))
    dstSample = os.path.join(tmpDir, "sample.zip")
    tmpConf.assetPath = tmpDir

    # Create and open a defective zip file
    with open(dstSample, mode="w+") as outFile:
        outFile.write("foo")

    assert not theProject.newProject(projData)
    os.unlink(dstSample)

    # Create a real zip file, and unpack it
    with ZipFile(dstSample, "w") as zipObj:
        zipObj.write(os.path.join(srcSample, "nwProject.nwx"), "nwProject.nwx")
        for docFile in os.listdir(os.path.join(srcSample, "content")):
            srcDoc = os.path.join(srcSample, "content", docFile)
            zipObj.write(srcDoc, "content/" + docFile)

    assert theProject.newProject(projData)
    assert theProject.openProject(fncDir)
    assert theProject.projName == "Sample Project"
    assert theProject.saveProject()
    assert theProject.closeProject()
    os.unlink(dstSample)
Пример #18
0
def testCoreIndex_CheckThese(nwMinimal, dummyGUI):
    """Test the tag checker function checkThese.
    """
    theProject = NWProject(dummyGUI)
    theProject.projTree.setSeed(42)
    assert theProject.openProject(nwMinimal)

    theIndex = NWIndex(theProject, dummyGUI)
    nHandle = theProject.newFile("Hello", nwItemClass.NOVEL, "a508bb932959c")
    cHandle = theProject.newFile("Jane", nwItemClass.CHARACTER,
                                 "afb3043c7b2b3")
    nItem = theProject.projTree[nHandle]
    cItem = theProject.projTree[cHandle]

    assert theIndex.scanText(cHandle, ("# Jane Smith\n" "@tag: Jane"))
    assert theIndex.scanText(nHandle, ("# Hello World!\n" "@pov: Jane"))
    assert theIndex.tagIndex == {"Jane": [2, cHandle, "CHARACTER", "T000001"]}
    assert theIndex.novelIndex[nHandle]["T000001"]["title"] == "Hello World!"

    assert theIndex.checkThese([], cItem) == []
    assert theIndex.checkThese(["@tag", "Jane"], cItem) == [True, True]
    assert theIndex.checkThese(["@tag", "John"], cItem) == [True, True]
    assert theIndex.checkThese(["@tag", "Jane"], nItem) == [True, False]
    assert theIndex.checkThese(["@tag", "John"], nItem) == [True, True]
    assert theIndex.checkThese(["@pov", "John"], nItem) == [True, False]
    assert theIndex.checkThese(["@pov", "Jane"], nItem) == [True, True]
    assert theIndex.checkThese(["@ pov", "Jane"], nItem) == [False, False]
    assert theIndex.checkThese(["@what", "Jane"], nItem) == [False, False]

    assert theProject.closeProject()
Пример #19
0
def testCoreIndex_CheckTextCounts(dummyGUI):
    """Test the text counts checker.
    """
    theProject = NWProject(dummyGUI)
    theIndex = NWIndex(theProject, dummyGUI)

    # Valid Index
    theIndex._textCounts = {
        "53b69b83cdafc": [72, 15, 2],
        "974e400180a99": [210, 40, 2],
    }
    assert theIndex._checkTextCounts() is None

    # Invalid Handle
    theIndex._textCounts = {
        "53b69b83cdafc": [72, 15, 2],
        "h74e400180a99": [210, 40, 2],
    }
    with pytest.raises(KeyError):
        theIndex._checkTextCounts()

    # Wrong Length
    theIndex._textCounts = {
        "53b69b83cdafc": [72, 15, 2],
        "974e400180a99": [210, 40, 2, 8],
    }
    with pytest.raises(IndexError):
        theIndex._checkTextCounts()

    # Type of Entry 0
    theIndex._textCounts = {
        "53b69b83cdafc": [72, 15, 2],
        "974e400180a99": ["210", 40, 2],
    }
    with pytest.raises(ValueError):
        theIndex._checkTextCounts()

    # Type of Entry 1
    theIndex._textCounts = {
        "53b69b83cdafc": [72, 15, 2],
        "974e400180a99": [210, "40", 2],
    }
    with pytest.raises(ValueError):
        theIndex._checkTextCounts()

    # Type of Entry 2
    theIndex._textCounts = {
        "53b69b83cdafc": [72, 15, 2],
        "974e400180a99": [210, 40, "2"],
    }
    with pytest.raises(ValueError):
        theIndex._checkTextCounts()
Пример #20
0
def testDocMeta(nwDummy, nwLipsum):
    """Check that the document meta data string is parsed correctly.
    """
    theProject = NWProject(nwDummy)
    theProject.projTree.setSeed(42)
    assert theProject.openProject(nwLipsum)

    aDoc = NWDoc(theProject, nwDummy)
    assert aDoc.openDocument("47666c91c7ccf")
    theName, theParent, theClass, theLayout = aDoc.getMeta()

    assert theName == "Scene Five"
    assert theParent == "6bd935d2490cd"
    assert theClass == nwItemClass.NOVEL
    assert theLayout == nwItemLayout.SCENE

    aDoc._docMeta = {"stuff": None}
    theName, theParent, theClass, theLayout = aDoc.getMeta()
    assert theName == ""
    assert theParent is None
    assert theClass is None
    assert theLayout is None
def testCoreTree_XMLPackUnpack(dummyGUI, dummyItems):
    """Test changing tree order.
    """
    theProject = NWProject(dummyGUI)
    theTree = NWTree(theProject)

    for tHandle, pHande, nwItem in dummyItems:
        theTree.append(tHandle, pHande, nwItem)

    assert len(theTree) == len(dummyItems)

    nwXML = etree.Element("novelWriterXML")
    theTree.packXML(nwXML)
    assert etree.tostring(nwXML, pretty_print=False, encoding="utf-8") == (
        b"<novelWriterXML>"
        b"<content count=\"8\">"
        b"<item handle=\"a000000000001\" order=\"0\" parent=\"None\">"
        b"<name>Novel</name><type>ROOT</type><class>NOVEL</class><status>None</status>"
        b"<expanded>True</expanded></item>"
        b"<item handle=\"b000000000001\" order=\"0\" parent=\"a000000000001\">"
        b"<name>Act One</name><type>FOLDER</type><class>NOVEL</class><status>None</status>"
        b"<expanded>True</expanded></item>"
        b"<item handle=\"c000000000001\" order=\"0\" parent=\"b000000000001\">"
        b"<name>Chapter One</name><type>FILE</type><class>NOVEL</class><status>None</status>"
        b"<exported>True</exported><layout>CHAPTER</layout><charCount>300</charCount>"
        b"<wordCount>50</wordCount><paraCount>2</paraCount><cursorPos>0</cursorPos></item>"
        b"<item handle=\"c000000000002\" order=\"0\" parent=\"b000000000001\">"
        b"<name>Scene One</name><type>FILE</type><class>NOVEL</class><status>None</status>"
        b"<exported>True</exported><layout>SCENE</layout><charCount>3000</charCount>"
        b"<wordCount>500</wordCount><paraCount>20</paraCount><cursorPos>0</cursorPos></item>"
        b"<item handle=\"a000000000002\" order=\"0\" parent=\"None\">"
        b"<name>Outtakes</name><type>ROOT</type><class>ARCHIVE</class><status>None</status>"
        b"<expanded>False</expanded></item>"
        b"<item handle=\"a000000000003\" order=\"0\" parent=\"None\">"
        b"<name>Trash</name><type>TRASH</type><class>TRASH</class><status>None</status>"
        b"<expanded>False</expanded></item>"
        b"<item handle=\"a000000000004\" order=\"0\" parent=\"None\">"
        b"<name>Characters</name><type>ROOT</type><class>CHARACTER</class><status>None</status>"
        b"<expanded>True</expanded></item>"
        b"<item handle=\"b000000000002\" order=\"0\" parent=\"a000000000002\">"
        b"<name>Jane Doe</name><type>FILE</type><class>CHARACTER</class><status>None</status>"
        b"<exported>True</exported><layout>NOTE</layout><charCount>2000</charCount>"
        b"<wordCount>400</wordCount><paraCount>16</paraCount><cursorPos>0</cursorPos></item>"
        b"</content></novelWriterXML>"
    )

    theTree.clear()
    assert len(theTree) == 0
    assert not theTree.unpackXML(nwXML)
    assert theTree.unpackXML(nwXML[0])
    assert len(theTree) == len(dummyItems)
Пример #22
0
def testCoreIndex_CheckThese(nwMinimal, dummyGUI):
    """Test the tag checker function checkThese.
    """
    theProject = NWProject(dummyGUI)
    theProject.projTree.setSeed(42)
    assert theProject.openProject(nwMinimal)

    theIndex = NWIndex(theProject, dummyGUI)
    nHandle = theProject.newFile("Hello", nwItemClass.NOVEL, "a508bb932959c")
    cHandle = theProject.newFile("Jane", nwItemClass.CHARACTER,
                                 "afb3043c7b2b3")
    nItem = theProject.projTree[nHandle]
    cItem = theProject.projTree[cHandle]

    assert not theIndex.novelChangedSince(0)
    assert not theIndex.notesChangedSince(0)
    assert not theIndex.indexChangedSince(0)

    assert theIndex.scanText(cHandle, ("# Jane Smith\n"
                                       "@tag: Jane\n"
                                       "@tag:\n"
                                       "@:\n"))
    assert theIndex.scanText(
        nHandle,
        (
            "# Hello World!\n"
            "@pov: Jane\n"
            "@invalid: John\n"  # Checks for issue #688
        ))
    assert theIndex._tagIndex == {"Jane": [2, cHandle, "CHARACTER", "T000001"]}
    assert theIndex.getNovelData(nHandle, "T000001")["title"] == "Hello World!"
    assert theIndex.getReferences(nHandle, "T000001") == {
        "@char": [],
        "@custom": [],
        "@entity": [],
        "@focus": [],
        "@location": [],
        "@object": [],
        "@plot": [],
        "@pov": ["Jane"],
        "@time": []
    }

    assert theIndex.novelChangedSince(0)
    assert theIndex.notesChangedSince(0)
    assert theIndex.indexChangedSince(0)

    assert theIndex.checkThese([], cItem) == []
    assert theIndex.checkThese(["@tag", "Jane"], cItem) == [True, True]
    assert theIndex.checkThese(["@tag", "John"], cItem) == [True, True]
    assert theIndex.checkThese(["@tag", "Jane"], nItem) == [True, False]
    assert theIndex.checkThese(["@tag", "John"], nItem) == [True, True]
    assert theIndex.checkThese(["@pov", "John"], nItem) == [True, False]
    assert theIndex.checkThese(["@pov", "Jane"], nItem) == [True, True]
    assert theIndex.checkThese(["@ pov", "Jane"], nItem) == [False, False]
    assert theIndex.checkThese(["@what", "Jane"], nItem) == [False, False]

    assert theProject.closeProject()
Пример #23
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])
Пример #24
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()
Пример #25
0
def testCoreProject_Helpers(monkeypatch, fncDir, dummyGUI):
    """Test helper functions for the project folder.
    """
    theProject = NWProject(dummyGUI)

    # No path
    assert theProject.ensureFolderStructure() is False

    # Set the correct dir
    theProject.projPath = fncDir

    # Block user's home folder
    monkeypatch.setattr("os.path.expanduser", lambda *args, **kwargs: fncDir)
    assert theProject.ensureFolderStructure() is False
    monkeypatch.undo()

    # Create a file to block meta folder
    metaDir = os.path.join(fncDir, "meta")
    writeFile(metaDir, "dummy")
    assert theProject.ensureFolderStructure() is False
    os.unlink(metaDir)

    # Create a file to block cache folder
    cacheDir = os.path.join(fncDir, "cache")
    writeFile(cacheDir, "dummy")
    assert theProject.ensureFolderStructure() is False
    os.unlink(cacheDir)

    # Create a file to block content folder
    contentDir = os.path.join(fncDir, "content")
    writeFile(contentDir, "dummy")
    assert theProject.ensureFolderStructure() is False
    os.unlink(contentDir)

    # Now, do it right
    assert theProject.ensureFolderStructure() is True
    assert os.path.isdir(metaDir)
    assert os.path.isdir(cacheDir)
    assert os.path.isdir(contentDir)
Пример #26
0
def testItemTypeSetter(nwDummy):

    theProject = NWProject(nwDummy)
    theItem = NWItem(theProject)

    # Type
    theItem.setType(None)
    assert theItem.itemType == nwItemType.NO_TYPE
    theItem.setType("NONSENSE")
    assert theItem.itemType == nwItemType.NO_TYPE
    theItem.setType("NO_TYPE")
    assert theItem.itemType == nwItemType.NO_TYPE
    theItem.setType("ROOT")
    assert theItem.itemType == nwItemType.ROOT
    theItem.setType("FOLDER")
    assert theItem.itemType == nwItemType.FOLDER
    theItem.setType("FILE")
    assert theItem.itemType == nwItemType.FILE
    theItem.setType("TRASH")
    assert theItem.itemType == nwItemType.TRASH
Пример #27
0
def testCoreTree_Stats(dummyGUI, dummyItems):
    """Test project stats methods.
    """
    theProject = NWProject(dummyGUI)
    theTree = NWTree(theProject)

    for tHandle, pHande, nwItem in dummyItems:
        theTree.append(tHandle, pHande, nwItem)

    assert len(theTree) == len(dummyItems)
    theTree._treeOrder.append("dummy")

    # Count Words
    novelWords, noteWords = theTree.sumWords()
    assert novelWords == 550
    assert noteWords == 400

    # Count types
    nRoot, nFolder, nFile = theTree.countTypes()
    assert nRoot == 3
    assert nFolder == 1
    assert nFile == 3
Пример #28
0
def testCoreTree_MakeHandles(monkeypatch, dummyGUI):
    """Test generating item handles.
    """
    theProject = NWProject(dummyGUI)
    theTree = NWTree(theProject)

    theTree.setSeed(42)

    tHandle = theTree._makeHandle()
    assert tHandle == "73475cb40a568"

    # Add the next in line to the project to force duplicate
    theTree._projTree["44cb730c42048"] = None
    tHandle = theTree._makeHandle()
    assert tHandle == "71ee45a3c0db9"

    # Fix the time() function and force a handle collission
    theTree.setSeed(None)
    theTree._handleCount = 0
    monkeypatch.setattr("nw.core.tree.time", lambda: 123.4)

    tHandle = theTree._makeHandle()
    theTree._projTree[tHandle] = None
    newSeed = "123.4_0_"
    assert tHandle == sha256(newSeed.encode()).hexdigest()[0:13]

    tHandle = theTree._makeHandle()
    theTree._projTree[tHandle] = None
    newSeed = "123.4_1_"
    assert tHandle == sha256(newSeed.encode()).hexdigest()[0:13]

    # Reset the count and the handle for 0 and 1 should be duplicates
    # which forces the function to add the '!'
    theTree._handleCount = 0
    tHandle = theTree._makeHandle()
    theTree._projTree[tHandle] = None
    newSeed = "123.4_1_!"
    assert tHandle == sha256(newSeed.encode()).hexdigest()[0:13]
Пример #29
0
def testCoreTree_BuildTree(dummyGUI, dummyItems):
    """Test building a project tree from a list of items.
    """
    theProject = NWProject(dummyGUI)
    theTree = NWTree(theProject)

    theTree.setSeed(42)
    assert theTree._handleSeed == 42

    # Check that tree is empty (calls NWTree.__bool__)
    assert not theTree

    # Check for archive and trash folders
    assert theTree.trashRoot() is None
    assert theTree.archiveRoot() is None
    assert not theTree.isTrashRoot("a000000000003")

    aHandles = []
    for tHandle, pHande, nwItem in dummyItems:
        aHandles.append(tHandle)
        assert theTree.append(tHandle, pHande, nwItem)

    assert theTree._treeChanged

    # Check that tree is not empty (calls __bool__)
    assert theTree

    # Check the number of elements (calls __len__)
    assert len(theTree) == len(dummyItems)

    # Check that we have the correct handles
    assert theTree.handles() == aHandles

    # Check by iterator (calls __iter__, __next__ and __getitem__)
    for theItem, theHandle in zip(theTree, aHandles):
        assert theItem.itemHandle == theHandle

    # Check that we have the correct archive and trash folders
    assert theTree.trashRoot() == "a000000000003"
    assert theTree.archiveRoot() == "a000000000002"
    assert theTree.isTrashRoot("a000000000003")

    # Try to add another trash folder
    itemT = NWItem(theProject)
    itemT.itemName = "Trash"
    itemT.itemType = nwItemType.TRASH
    itemT.itemClass = nwItemClass.TRASH
    itemT.isExpanded = False

    assert not theTree.append("1234567890abc", None, itemT)
    assert len(theTree) == len(dummyItems)

    # Generate handle automatically
    itemT = NWItem(theProject)
    itemT.itemName = "New File"
    itemT.itemType = nwItemType.FILE
    itemT.itemClass = nwItemClass.NOVEL
    itemT.itemLayout = nwItemLayout.SCENE

    assert theTree.append(None, None, itemT)
    assert len(theTree) == len(dummyItems) + 1

    theList = theTree.handles()
    assert theList[-1] == "73475cb40a568"

    # Try to add existing handle
    assert not theTree.append("73475cb40a568", None, itemT)
    assert len(theTree) == len(dummyItems) + 1

    # Delete a non-existing item
    del theTree["dummy"]
    assert len(theTree) == len(dummyItems) + 1

    # Delete the last item
    del theTree["73475cb40a568"]
    assert len(theTree) == len(dummyItems)
    assert "73475cb40a568" not in theTree

    # Delete the Novel, Archive and Trash folders
    del theTree["a000000000001"]
    assert len(theTree) == len(dummyItems) - 1
    assert "a000000000001" not in theTree

    del theTree["a000000000002"]
    assert len(theTree) == len(dummyItems) - 2
    assert "a000000000002" not in theTree
    assert theTree.archiveRoot() is None

    del theTree["a000000000003"]
    assert len(theTree) == len(dummyItems) - 3
    assert "a000000000003" not in theTree
    assert theTree.trashRoot() is None
Пример #30
0
def dummyItems(dummyGUI):
    """Create a list of dummy items.
    """
    theProject = NWProject(dummyGUI)

    itemA = NWItem(theProject)
    itemA.itemName = "Novel"
    itemA.itemType = nwItemType.ROOT
    itemA.itemClass = nwItemClass.NOVEL
    itemA.isExpanded = True

    itemB = NWItem(theProject)
    itemB.itemName = "Act One"
    itemB.itemType = nwItemType.FOLDER
    itemB.itemClass = nwItemClass.NOVEL
    itemB.isExpanded = True

    itemC = NWItem(theProject)
    itemC.itemName = "Chapter One"
    itemC.itemType = nwItemType.FILE
    itemC.itemClass = nwItemClass.NOVEL
    itemC.itemLayout = nwItemLayout.CHAPTER
    itemC.charCount = 300
    itemC.wordCount = 50
    itemC.paraCount = 2

    itemD = NWItem(theProject)
    itemD.itemName = "Scene One"
    itemD.itemType = nwItemType.FILE
    itemD.itemClass = nwItemClass.NOVEL
    itemD.itemLayout = nwItemLayout.SCENE
    itemD.charCount = 3000
    itemD.wordCount = 500
    itemD.paraCount = 20

    itemE = NWItem(theProject)
    itemE.itemName = "Outtakes"
    itemE.itemType = nwItemType.ROOT
    itemE.itemClass = nwItemClass.ARCHIVE
    itemE.isExpanded = False

    itemF = NWItem(theProject)
    itemF.itemName = "Trash"
    itemF.itemType = nwItemType.TRASH
    itemF.itemClass = nwItemClass.TRASH
    itemF.isExpanded = False

    itemG = NWItem(theProject)
    itemG.itemName = "Characters"
    itemG.itemType = nwItemType.ROOT
    itemG.itemClass = nwItemClass.CHARACTER
    itemG.isExpanded = True

    itemH = NWItem(theProject)
    itemH.itemName = "Jane Doe"
    itemH.itemType = nwItemType.FILE
    itemH.itemClass = nwItemClass.CHARACTER
    itemH.itemLayout = nwItemLayout.NOTE
    itemH.charCount = 2000
    itemH.wordCount = 400
    itemH.paraCount = 16

    theItems = [
        ("a000000000001", None, itemA),
        ("b000000000001", "a000000000001", itemB),
        ("c000000000001", "b000000000001", itemC),
        ("c000000000002", "b000000000001", itemD),
        ("a000000000002", None, itemE),
        ("a000000000003", None, itemF),
        ("a000000000004", None, itemG),
        ("b000000000002", "a000000000002", itemH),
    ]

    return theItems