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)
Example #2
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")
Example #3
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
Example #4
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
Example #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
Example #6
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()
Example #7
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
Example #8
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]
Example #9
0
def testCoreTree_UpdateItemLayout(dummyGUI, dummyItems):
    """Test building a project tree from a list of items.
    """
    theProject = NWProject(dummyGUI)
    theTree = NWTree(theProject)

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

    assert len(theTree) == len(dummyItems)

    # Check rejected items
    assert not theTree.updateItemLayout("0000000000000",
                                        "H1")  # Non-existent handle
    assert not theTree.updateItemLayout("a000000000004",
                                        "H2")  # Character file
    assert not theTree.updateItemLayout("c000000000002",
                                        "H0")  # Wrong header level

    cHandle = "c000000000002"

    # Check layouts we won't change
    theTree[cHandle].setLayout(nwItemLayout.NO_LAYOUT)
    assert not theTree.updateItemLayout("c000000000002", "H1")

    theTree[cHandle].setLayout(nwItemLayout.TITLE)
    assert not theTree.updateItemLayout("c000000000002", "H1")

    theTree[cHandle].setLayout(nwItemLayout.PAGE)
    assert not theTree.updateItemLayout("c000000000002", "H1")

    theTree[cHandle].setLayout(nwItemLayout.NOTE)
    assert not theTree.updateItemLayout("c000000000002", "H1")

    # BOOK is also a layout we change to, but never from
    theTree[cHandle].setLayout(nwItemLayout.BOOK)
    assert not theTree.updateItemLayout("c000000000002", "H1")

    # Test SCENE Changes
    # ==================

    # H1 -> BOOK
    theTree[cHandle].setLayout(nwItemLayout.SCENE)
    assert theTree.updateItemLayout("c000000000002", "H1")
    assert theTree[cHandle].itemLayout == nwItemLayout.BOOK

    # H2 -> CHAPTER
    theTree[cHandle].setLayout(nwItemLayout.SCENE)
    assert theTree.updateItemLayout("c000000000002", "H2")
    assert theTree[cHandle].itemLayout == nwItemLayout.CHAPTER

    # H3 -> No CHange
    theTree[cHandle].setLayout(nwItemLayout.SCENE)
    assert not theTree.updateItemLayout("c000000000002", "H3")

    # H4 -> No CHange
    theTree[cHandle].setLayout(nwItemLayout.SCENE)
    assert not theTree.updateItemLayout("c000000000002", "H4")

    # Test CHAPTER Changes
    # ====================

    # H1 -> BOOK
    theTree[cHandle].setLayout(nwItemLayout.CHAPTER)
    assert theTree.updateItemLayout("c000000000002", "H1")
    assert theTree[cHandle].itemLayout == nwItemLayout.BOOK

    # H2 -> No Change
    theTree[cHandle].setLayout(nwItemLayout.CHAPTER)
    assert not theTree.updateItemLayout("c000000000002", "H2")

    # H3 -> SCENE
    theTree[cHandle].setLayout(nwItemLayout.CHAPTER)
    assert theTree.updateItemLayout("c000000000002", "H3")
    assert theTree[cHandle].itemLayout == nwItemLayout.SCENE

    # H4 -> SCENE
    theTree[cHandle].setLayout(nwItemLayout.CHAPTER)
    assert theTree.updateItemLayout("c000000000002", "H4")
    assert theTree[cHandle].itemLayout == nwItemLayout.SCENE

    # Test UNNUMBERED Changes
    # =======================

    # H1 -> BOOK
    theTree[cHandle].setLayout(nwItemLayout.UNNUMBERED)
    assert theTree.updateItemLayout("c000000000002", "H1")
    assert theTree[cHandle].itemLayout == nwItemLayout.BOOK

    # H2 -> No Change
    theTree[cHandle].setLayout(nwItemLayout.UNNUMBERED)
    assert not theTree.updateItemLayout("c000000000002", "H2")

    # H3 -> SCENE
    theTree[cHandle].setLayout(nwItemLayout.UNNUMBERED)
    assert theTree.updateItemLayout("c000000000002", "H3")
    assert theTree[cHandle].itemLayout == nwItemLayout.SCENE

    # H4 -> SCENE
    theTree[cHandle].setLayout(nwItemLayout.UNNUMBERED)
    assert theTree.updateItemLayout("c000000000002", "H4")
    assert theTree[cHandle].itemLayout == nwItemLayout.SCENE

    # Test PARTITION Changes
    # ======================

    # H1 -> BOOK
    theTree[cHandle].setLayout(nwItemLayout.PARTITION)
    assert not theTree.updateItemLayout("c000000000002", "H1")

    # H2 -> No Change
    theTree[cHandle].setLayout(nwItemLayout.PARTITION)
    assert theTree.updateItemLayout("c000000000002", "H2")
    assert theTree[cHandle].itemLayout == nwItemLayout.CHAPTER

    # H3 -> SCENE
    theTree[cHandle].setLayout(nwItemLayout.PARTITION)
    assert theTree.updateItemLayout("c000000000002", "H3")
    assert theTree[cHandle].itemLayout == nwItemLayout.SCENE

    # H4 -> SCENE
    theTree[cHandle].setLayout(nwItemLayout.PARTITION)
    assert theTree.updateItemLayout("c000000000002", "H4")
    assert theTree[cHandle].itemLayout == nwItemLayout.SCENE