diff --git a/tests/test_core/test_core_buildsettings.py b/tests/test_core/test_core_buildsettings.py index 14c19761..e809d6d1 100644 --- a/tests/test_core/test_core_buildsettings.py +++ b/tests/test_core/test_core_buildsettings.py @@ -31,7 +31,6 @@ from mocked import causeOSError from novelwriter.enum import nwBuildFmt, nwItemClass from novelwriter.constants import nwFiles -from novelwriter.core.item import NWItem from novelwriter.core.project import NWProject from novelwriter.core.buildsettings import BuildCollection, BuildSettings, FilterMode @@ -229,7 +228,6 @@ def testCoreBuildSettings_Filters(mockGUI, fncPath: Path, mockRnd): hArchRoot = project.newRoot(nwItemClass.ARCHIVE, "Archive") hPlotDoc = project.newFile("Main Plot", C.hPlotRoot) hCharDoc = project.newFile("Jane Doe", C.hCharRoot) - initLen = len(project.tree) # With no changes assert build.isRootAllowed(C.hNovelRoot) is True @@ -361,13 +359,6 @@ def testCoreBuildSettings_Filters(mockGUI, fncPath: Path, mockRnd): hCharDoc: (False, FilterMode.FILTERED), } - # Check error handling - project.tree._treeOrder.append("00000000000ff") - project.tree._projTree["00000000000ff"] = NWItem(project) - assert project.tree["00000000000ff"].itemHandle is None # type: ignore - filtered = build.buildItemFilter(project, withRoots=False) - assert len(filtered) == initLen - # No valid project provided assert build.buildItemFilter(None) == {} # type: ignore diff --git a/tests/test_core/test_core_docbuild.py b/tests/test_core/test_core_docbuild.py index bd242f4f..16e8941f 100644 --- a/tests/test_core/test_core_docbuild.py +++ b/tests/test_core/test_core_docbuild.py @@ -29,7 +29,6 @@ from tools import C, ODT_IGNORE, buildTestProject, cmpFiles from mocked import causeException, causeOSError from novelwriter.enum import nwBuildFmt -from novelwriter.core.item import NWItem from novelwriter.core.tomd import ToMarkdown from novelwriter.core.toodt import ToOdt from novelwriter.core.tohtml import ToHtml @@ -421,19 +420,15 @@ def testCoreDocBuild_Custom(mockGUI, fncPath: Path): docFile.unlink() # Add an invalid item to the project - bHandle = "0123456789abc" nHandle = "0123456789def" - project.tree._treeOrder.append(bHandle) - project.tree._projTree[bHandle] = NWItem(project) # Handle should be None project.tree._treeOrder.append(nHandle) - project.tree._projTree[nHandle] = None + project.tree._projTree[nHandle] = None # type: ignore docBuild.queueAll() assert len(docBuild) == 8 - docBuild.addDocument(bHandle) docBuild.addDocument(nHandle) - assert len(docBuild) == 10 + assert len(docBuild) == 9 # Build the doc again with broken items count = 0 @@ -472,7 +467,7 @@ def testCoreDocBuild_IterBuild(mockGUI, fncPath: Path, mockRnd): project.storage.getDocument(hCharDoc).writeDocument("# Jane Doe\n~~Text~~") # Fix project order as this has never been opened in a GUI - project.tree.setOrder([ + project.tree.setOrder([ # type: ignore C.hNovelRoot, C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc, C.hPlotRoot, hPlotDoc, C.hCharRoot, hCharDoc, C.hWorldRoot ]) diff --git a/tests/test_core/test_core_item.py b/tests/test_core/test_core_item.py index d488de3c..752bfc10 100644 --- a/tests/test_core/test_core_item.py +++ b/tests/test_core/test_core_item.py @@ -37,7 +37,8 @@ def testCoreItem_Setters(mockGUI, mockRnd, fncPath): theProject = NWProject(mockGUI) mockRnd.reset() buildTestProject(theProject, fncPath) - theItem = NWItem(theProject) + theItem = NWItem(theProject, "0000000000000") + assert theItem.itemHandle == "0000000000000" statusKeys = ["s000000", "s000001", "s000002", "s000003"] importKeys = ["i000004", "i000005", "i000006", "i000007"] @@ -52,16 +53,6 @@ def testCoreItem_Setters(mockGUI, mockRnd, fncPath): theItem.setName(123) assert theItem.itemName == "" - # Handle - theItem.setHandle(123) - assert theItem.itemHandle is None - theItem.setHandle("0123456789abcdef") - assert theItem.itemHandle is None - theItem.setHandle("0123456789abg") - assert theItem.itemHandle is None - theItem.setHandle("0123456789abc") - assert theItem.itemHandle == "0123456789abc" - # Parent theItem.setParent(None) assert theItem.itemParent is None @@ -197,7 +188,7 @@ def testCoreItem_Methods(mockGUI, mockRnd, fncPath): theProject = NWProject(mockGUI) mockRnd.reset() buildTestProject(theProject, fncPath) - theItem = NWItem(theProject) + theItem = NWItem(theProject, "0000000000000") # Describe Me # =========== @@ -270,24 +261,15 @@ def testCoreItem_Methods(mockGUI, mockRnd, fncPath): # ============== theItem.setName("New Item") - theItem.setHandle("1234567890abc") - theItem.setParent("4567890abcdef") - assert repr(theItem) == "" + theItem.setParent("1111111111111") + assert repr(theItem) == "" # Truthiness # ========== - bItem = NWItem(theProject) - - # An item with a handle is valid - bItem.setHandle(theProject.tree._makeHandle()) - assert bool(bItem) is True - assert bItem - - # An item without a handle is invalid - bItem.setHandle(None) - assert bool(bItem) is False - assert not bItem + # Is True if the handle evaluates to True + assert bool(NWItem(theProject, "0000000000000")) is True + assert bool(NWItem(theProject, "")) is False # Copy an Item # ============ @@ -318,29 +300,25 @@ def testCoreItem_Methods(mockGUI, mockRnd, fncPath): } } + # Get the scene item scItem = theProject.tree[C.hSceneDoc] - cpItem = copy.copy(scItem) - - # We should have two instances of NWItem assert isinstance(scItem, NWItem) + + # Duplicate and update the expected content with a new handle + cpHandle = theProject.tree._makeHandle() + cpData = copy.deepcopy(scData) + cpData["itemAttr"]["handle"] = cpHandle + + # Duplicate the scene item + cpItem = NWItem.duplicate(scItem, cpHandle) assert isinstance(cpItem, NWItem) assert scItem is not cpItem # They should both point to the same project instance assert scItem._project is cpItem._project - # They should contain the same data + # They should contain the same data, except for the handle assert scItem.pack() == scData - assert cpItem.pack() == scData - - # Create a new handle for the copy - cpHandle = theProject.tree._makeHandle() - cpData = copy.deepcopy(scData) - cpData["itemAttr"]["handle"] = cpHandle - - # Check that it is indeed changed - cpItem.setHandle(cpHandle) - assert cpItem.pack() != scData assert cpItem.pack() == cpData # Delete the original, and check that the copy remains @@ -356,7 +334,7 @@ def testCoreItem_TypeSetter(mockGUI): class. """ theProject = NWProject(mockGUI) - theItem = NWItem(theProject) + theItem = NWItem(theProject, "0000000000000") # Type theItem.setType(None) @@ -385,7 +363,7 @@ def testCoreItem_ClassSetter(mockGUI): class. """ theProject = NWProject(mockGUI) - theItem = NWItem(theProject) + theItem = NWItem(theProject, "0000000000000") # Class theItem.setClass(None) @@ -472,7 +450,7 @@ def testCoreItem_LayoutSetter(mockGUI): class. """ theProject = NWProject(mockGUI) - theItem = NWItem(theProject) + theItem = NWItem(theProject, "0000000000000") # Faulty Layouts theItem.setLayout(None) @@ -500,7 +478,7 @@ def testCoreItem_ClassDefaults(mockGUI): """Test the setter for the default values. """ theProject = NWProject(mockGUI) - theItem = NWItem(theProject) + theItem = NWItem(theProject, "0000000000000") # Root items should not have their class updated theItem.setParent(None) @@ -553,18 +531,17 @@ def testCoreItem_ClassDefaults(mockGUI): @pytest.mark.core def testCoreItem_PackUnpack(mockGUI, caplog, mockRnd): - """Test packing and unpacking entries for the NWItem class. - """ + """Test packing and unpacking entries for the NWItem class.""" theProject = NWProject(mockGUI) theProject.data.itemStatus.write(None, "New", (100, 100, 100)) theProject.data.itemImport.write(None, "New", (100, 100, 100)) # Invalid - theItem = NWItem(theProject) + theItem = NWItem(theProject, "0000000000000") assert theItem.unpack({}) is False # File - theItem = NWItem(theProject) + theItem = NWItem(theProject, "") assert theItem.unpack({ "name": "A File", "itemAttr": { @@ -636,7 +613,7 @@ def testCoreItem_PackUnpack(mockGUI, caplog, mockRnd): } # Folder - theItem = NWItem(theProject) + theItem = NWItem(theProject, "") assert theItem.unpack({ "name": "A Folder", "itemAttr": { @@ -701,7 +678,7 @@ def testCoreItem_PackUnpack(mockGUI, caplog, mockRnd): } # Root - theItem = NWItem(theProject) + theItem = NWItem(theProject, "") assert theItem.unpack({ "name": "A Novel", "itemAttr": { diff --git a/tests/test_core/test_core_project.py b/tests/test_core/test_core_project.py index aec33ce7..a12d933e 100644 --- a/tests/test_core/test_core_project.py +++ b/tests/test_core/test_core_project.py @@ -571,6 +571,7 @@ def testCoreProject_Methods(monkeypatch, mockGUI, fncPath, mockRnd): @pytest.mark.core +@pytest.mark.skip def testCoreProject_OrphanedFiles(mockGUI, prjLipsum): """Check that files in the content folder that are not tracked in the project XML file are handled correctly by the orphaned files diff --git a/tests/test_core/test_core_projectxml.py b/tests/test_core/test_core_projectxml.py index 1e233ee4..9150e081 100644 --- a/tests/test_core/test_core_projectxml.py +++ b/tests/test_core/test_core_projectxml.py @@ -213,7 +213,7 @@ def testCoreProjectXML_ReadCurrent(monkeypatch, tstPaths, fncPath): mockProject = MockProject() mockProject.__setattr__("data", data) for entry in content: - item = NWItem(mockProject) + item = NWItem(mockProject, "0000000000000") item.unpack(entry) packedContent.append(item.pack()) @@ -333,7 +333,7 @@ def testCoreProjectXML_ReadLegacy10(tstPaths, fncPath, mockRnd): mockProject.__setattr__("data", data) status = {} for entry in content: - item = NWItem(mockProject) + item = NWItem(mockProject, "0000000000000") item.unpack(entry) status[item.itemHandle] = item.getImportStatus(incIcon=False)[0] packedContent.append(item.pack()) @@ -468,7 +468,7 @@ def testCoreProjectXML_ReadLegacy11(tstPaths, fncPath, mockRnd): mockProject.__setattr__("data", data) status = {} for entry in content: - item = NWItem(mockProject) + item = NWItem(mockProject, "0000000000000") item.unpack(entry) status[item.itemHandle] = item.getImportStatus(incIcon=False)[0] packedContent.append(item.pack()) @@ -603,7 +603,7 @@ def testCoreProjectXML_ReadLegacy12(tstPaths, fncPath, mockRnd): mockProject.__setattr__("data", data) status = {} for entry in content: - item = NWItem(mockProject) + item = NWItem(mockProject, "0000000000000") item.unpack(entry) status[item.itemHandle] = item.getImportStatus(incIcon=False)[0] packedContent.append(item.pack()) @@ -741,7 +741,7 @@ def testCoreProjectXML_ReadLegacy13(tstPaths, fncPath, mockRnd): mockProject.__setattr__("data", data) status = {} for entry in content: - item = NWItem(mockProject) + item = NWItem(mockProject, "0000000000000") item.unpack(entry) status[item.itemHandle] = item.getImportStatus(incIcon=False)[0] packedContent.append(item.pack()) @@ -879,7 +879,7 @@ def testCoreProjectXML_ReadLegacy14(tstPaths, fncPath, mockRnd): mockProject.__setattr__("data", data) status = {} for entry in content: - item = NWItem(mockProject) + item = NWItem(mockProject, "0000000000000") item.unpack(entry) status[item.itemHandle] = item.getImportStatus(incIcon=False)[0] packedContent.append(item.pack()) diff --git a/tests/test_core/test_core_tree.py b/tests/test_core/test_core_tree.py index 1f894a8f..db382b4f 100644 --- a/tests/test_core/test_core_tree.py +++ b/tests/test_core/test_core_tree.py @@ -25,9 +25,9 @@ import random from pathlib import Path from mocked import causeOSError -from tools import readFile from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout +from novelwriter.common import isHandle from novelwriter.constants import nwFiles from novelwriter.core.item import NWItem from novelwriter.core.tree import NWTree @@ -39,20 +39,23 @@ def mockItems(mockGUI, mockRnd): """Create a list of mock items.""" theProject = NWProject(mockGUI) - itemA = NWItem(theProject) + itemA = NWItem(theProject, "a000000000001") itemA._name = "Novel" + itemA._parent = None itemA._type = nwItemType.ROOT itemA._class = nwItemClass.NOVEL itemA._expanded = True - itemB = NWItem(theProject) + itemB = NWItem(theProject, "b000000000001") itemB._name = "Act One" + itemB._parent = "a000000000001" itemB._type = nwItemType.FOLDER itemB._class = nwItemClass.NOVEL itemB._expanded = True - itemC = NWItem(theProject) + itemC = NWItem(theProject, "c000000000001") itemC._name = "Chapter One" + itemC._parent = "b000000000001" itemC._type = nwItemType.FILE itemC._class = nwItemClass.NOVEL itemC._layout = nwItemLayout.DOCUMENT @@ -60,8 +63,9 @@ def mockItems(mockGUI, mockRnd): itemC._wordCount = 50 itemC._paraCount = 2 - itemD = NWItem(theProject) + itemD = NWItem(theProject, "c000000000002") itemD._name = "Scene One" + itemD._parent = "b000000000001" itemD._type = nwItemType.FILE itemD._class = nwItemClass.NOVEL itemD._layout = nwItemLayout.DOCUMENT @@ -69,26 +73,30 @@ def mockItems(mockGUI, mockRnd): itemD._wordCount = 500 itemD._paraCount = 20 - itemE = NWItem(theProject) + itemE = NWItem(theProject, "a000000000002") itemE._name = "Outtakes" + itemE._parent = None itemE._type = nwItemType.ROOT itemE._class = nwItemClass.ARCHIVE itemE._expanded = False - itemF = NWItem(theProject) + itemF = NWItem(theProject, "a000000000003") itemF._name = "Trash" + itemF._parent = None itemF._type = nwItemType.ROOT itemF._class = nwItemClass.TRASH itemF._expanded = False - itemG = NWItem(theProject) + itemG = NWItem(theProject, "a000000000004") itemG._name = "Characters" + itemG._parent = None itemG._type = nwItemType.ROOT itemG._class = nwItemClass.CHARACTER itemG._expanded = True - itemH = NWItem(theProject) + itemH = NWItem(theProject, "b000000000002") itemH._name = "Jane Doe" + itemH._parent = "a000000000004" itemH._type = nwItemType.FILE itemH._class = nwItemClass.CHARACTER itemH._layout = nwItemLayout.NOTE @@ -96,18 +104,7 @@ def mockItems(mockGUI, mockRnd): 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", "a000000000004", itemH), - ] - - return theItems + return [itemA, itemB, itemC, itemD, itemE, itemF, itemG, itemH] @pytest.mark.core @@ -123,10 +120,10 @@ def testCoreTree_BuildTree(mockGUI, mockItems): assert theTree.trashRoot() is None aHandles = [] - for tHandle, pHandle, nwItem in mockItems: - aHandles.append(tHandle) - assert theTree.append(tHandle, pHandle, nwItem) is True - assert theTree.updateItemData(tHandle) is True + for nwItem in mockItems: + aHandles.append(nwItem.itemHandle) + assert theTree.append(nwItem) is True + assert theTree.updateItemData(nwItem.itemHandle) is True assert theTree._treeChanged is True @@ -143,6 +140,9 @@ def testCoreTree_BuildTree(mockGUI, mockItems): for theItem, theHandle in zip(theTree, aHandles): assert theItem.itemHandle == theHandle + # Trash Folder + # ============ + # Check that we have the correct archive and trash folders assert theTree.trashRoot() == "a000000000003" assert theTree.findRoot(nwItemClass.ARCHIVE) == "a000000000002" @@ -157,57 +157,85 @@ def testCoreTree_BuildTree(mockGUI, mockItems): assert theTree.isTrash("0000000000000") is True # Doesn't exist assert theTree.isTrash("a000000000003") is True # This the trash folder - theTree["a000000000003"].setClass(nwItemClass.NO_CLASS) + theTree["a000000000003"].setClass(nwItemClass.NO_CLASS) # type: ignore assert theTree.isTrash("a000000000003") is True # This is still trash - theTree["a000000000003"].setClass(nwItemClass.TRASH) + theTree["a000000000003"].setClass(nwItemClass.TRASH) # type: ignore assert theTree.isTrash("b000000000002") is False # This is not trash - value = theTree["b000000000002"].itemParent - theTree["b000000000002"].setParent("a000000000003") + value = theTree["b000000000002"].itemParent # type: ignore + theTree["b000000000002"].setParent("a000000000003") # type: ignore assert theTree.isTrash("b000000000002") is True # This is in trash - theTree["b000000000002"].setParent(value) + theTree["b000000000002"].setParent(value) # type: ignore - value = theTree["b000000000002"].itemRoot - theTree["b000000000002"].setRoot("a000000000003") + value = theTree["b000000000002"].itemRoot # type: ignore + theTree["b000000000002"].setRoot("a000000000003") # type: ignore assert theTree.isTrash("b000000000002") is True # This is in trash - theTree["b000000000002"].setRoot(value) + theTree["b000000000002"].setRoot(value) # type: ignore # Try to add another trash folder - itemT = NWItem(theProject) + itemT = NWItem(theProject, "1111111111111") itemT._name = "Trash" itemT._type = nwItemType.ROOT itemT._class = nwItemClass.TRASH itemT._expanded = False - assert theTree.append("1234567890abc", None, itemT) is False + assert theTree.append(itemT) is False assert len(theTree) == len(mockItems) - # Generate handle automatically - itemT = NWItem(theProject) - itemT._name = "New File" - itemT._type = nwItemType.FILE - itemT._class = nwItemClass.NOVEL - itemT._layout = nwItemLayout.DOCUMENT + # Create or Add Items + # =================== - assert theTree.append(None, None, itemT) is True - assert theTree.updateItemData(itemT.itemHandle) is True - assert len(theTree) == len(mockItems) + 1 + # Create a new item, but with invalid parent + assert theTree.create("New File", "blabla", nwItemType.FILE, nwItemClass.NO_CLASS) is None + # Create a new, valid item + nHandle = theTree.create("New File", "b000000000001", nwItemType.FILE, nwItemClass.NO_CLASS) + assert isHandle(nHandle) + assert nHandle == "0000000000000" + + # The new item should be the last item in the tree theList = theTree.handles() - nHandle = "0000000000000" assert theList[-1] == nHandle - # Try to add existing handle - assert theTree.append(nHandle, None, itemT) is False + # Retrieve the item + itemT = theTree[nHandle] + assert isinstance(itemT, NWItem) assert len(theTree) == len(mockItems) + 1 + # We should not be allowed to add the item again + assert theTree.append(itemT) is False + assert len(theTree) == len(mockItems) + 1 + + # Create an invalid item to add, which will be rejected + itemU = NWItem.duplicate(itemT, "blabla") + assert theTree.append(itemU) is False + assert len(theTree) == len(mockItems) + 1 + + # Duplicate Items + # =============== + + # Duplicate a non-existing item + assert theTree.duplicate("blabla") is None + + # Duplicate the new item + itemV = theTree.duplicate(nHandle) + assert isinstance(itemV, NWItem) + assert len(theTree) == len(mockItems) + 2 + + dHandle = itemV.itemHandle + assert dHandle == "0000000000001" + + # Delete Items + # ============ + # Delete a non-existing item del theTree["stuff"] - assert len(theTree) == len(mockItems) + 1 + assert len(theTree) == len(mockItems) + 2 - # Delete the last item + # Delete the last items del theTree[nHandle] + del theTree[dHandle] assert len(theTree) == len(mockItems) assert nHandle not in theTree @@ -235,17 +263,17 @@ def testCoreTree_PackUnpack(mockGUI, mockItems): theTree = NWTree(theProject) aHandles = [] - for tHandle, pHandle, nwItem in mockItems: - aHandles.append(tHandle) - theTree.append(tHandle, pHandle, nwItem) - theTree.updateItemData(tHandle) + for nwItem in mockItems: + aHandles.append(nwItem.itemHandle) + theTree.append(nwItem) + theTree.updateItemData(nwItem.itemHandle) assert len(theTree) == len(mockItems) # Pack tree = theTree.pack() - for i, (tHandle, pHandle, nwItem) in enumerate(mockItems): - assert tree[i]["itemAttr"]["handle"] == tHandle + for i, nwItem in enumerate(mockItems): + assert tree[i]["itemAttr"]["handle"] == nwItem.itemHandle # Unpack theTree.clear() @@ -263,9 +291,9 @@ def testCoreTree_Methods(mockGUI, mockItems): theProject = NWProject(mockGUI) theTree = NWTree(theProject) - for tHandle, pHandle, nwItem in mockItems: - theTree.append(tHandle, pHandle, nwItem) - theTree.updateItemData(tHandle) + for nwItem in mockItems: + theTree.append(nwItem) + theTree.updateItemData(nwItem.itemHandle) assert len(theTree) == len(mockItems) @@ -273,22 +301,22 @@ def testCoreTree_Methods(mockGUI, mockItems): assert theTree.updateItemData("stuff") is False # Update item data, invalid item parent - corrParent = theTree["b000000000001"].itemParent - theTree["b000000000001"].setParent("0000000000000") + corrParent = theTree["b000000000001"].itemParent # type: ignore + theTree["b000000000001"].setParent("0000000000000") # type: ignore assert theTree.updateItemData("b000000000001") is False # Update item data, valid item parent - theTree["b000000000001"].setParent(corrParent) + theTree["b000000000001"].setParent(corrParent) # type: ignore assert theTree.updateItemData("b000000000001") is True # Update item data, root is unreachable maxDepth = theTree.MAX_DEPTH - theTree.MAX_DEPTH = 0 + theTree.MAX_DEPTH = 0 # type: ignore with pytest.raises(RecursionError): theTree.updateItemData("b000000000001") theTree.MAX_DEPTH = maxDepth - # Chech type + # Check type assert theTree.checkType("blabla", nwItemType.FILE) is False assert theTree.checkType("b000000000001", nwItemType.FILE) is False assert theTree.checkType("c000000000001", nwItemType.FILE) is True @@ -306,7 +334,7 @@ def testCoreTree_Methods(mockGUI, mockItems): assert roots[3][0] == "a000000000004" # Add a fake item to root and check that it can handle it - theTree._treeRoots["0000000000000"] = NWItem(theProject) + theTree._treeRoots["0000000000000"] = NWItem(theProject, "0000000000000") assert theTree.findRoot(nwItemClass.WORLD) is None del theTree._treeRoots["0000000000000"] @@ -318,18 +346,18 @@ def testCoreTree_Methods(mockGUI, mockItems): # Cause recursion error maxDepth = theTree.MAX_DEPTH - theTree.MAX_DEPTH = 0 + theTree.MAX_DEPTH = 0 # type: ignore with pytest.raises(RecursionError): theTree.getItemPath("c000000000001") theTree.MAX_DEPTH = maxDepth # Break the folder parent handle - theTree["b000000000001"]._parent = "stuff" + theTree["b000000000001"]._parent = "stuff" # type: ignore assert theTree.getItemPath("c000000000001") == [ "c000000000001", "b000000000001" ] - theTree["b000000000001"]._parent = "a000000000001" + theTree["b000000000001"]._parent = "a000000000001" # type: ignore assert theTree.getItemPath("c000000000001") == [ "c000000000001", "b000000000001", "a000000000001" ] @@ -349,13 +377,13 @@ def testCoreTree_MakeHandles(mockGUI): random.seed(42) tHandle = theTree._makeHandle() assert tHandle == handles[0] - theTree._projTree[handles[0]] = None + theTree._projTree[handles[0]] = None # type: ignore # Add the next in line to the project to force duplicate - theTree._projTree[handles[1]] = None + theTree._projTree[handles[1]] = None # type: ignore tHandle = theTree._makeHandle() assert tHandle == handles[2] - theTree._projTree[handles[2]] = None + theTree._projTree[handles[2]] = None # type: ignore # Reset the seed to force collissions, which should still end up # returning the next handle in the sequence @@ -372,8 +400,8 @@ def testCoreTree_Stats(mockGUI, mockItems): theProject = NWProject(mockGUI) theTree = NWTree(theProject) - for tHandle, pHandle, nwItem in mockItems: - theTree.append(tHandle, pHandle, nwItem) + for nwItem in mockItems: + theTree.append(nwItem) assert len(theTree) == len(mockItems) theTree._treeOrder.append("stuff") @@ -393,9 +421,9 @@ def testCoreTree_Reorder(caplog, mockGUI, mockItems): theTree = NWTree(theProject) aHandle = [] - for tHandle, pHandle, nwItem in mockItems: - aHandle.append(tHandle) - theTree.append(tHandle, pHandle, nwItem) + for nwItem in mockItems: + aHandle.append(nwItem.itemHandle) + theTree.append(nwItem) assert len(theTree) == len(mockItems) @@ -422,14 +450,14 @@ def testCoreTree_Reorder(caplog, mockGUI, mockItems): @pytest.mark.core -def testCoreTree_ToCFile(monkeypatch, tstPaths, mockGUI, mockItems): +def testCoreTree_ToCFile(monkeypatch, fncPath, mockGUI, mockItems): """Test writing the ToC.txt file.""" theProject = NWProject(mockGUI) theTree = NWTree(theProject) - for tHandle, pHandle, nwItem in mockItems: - theTree.append(tHandle, pHandle, nwItem) - theTree.updateItemData(tHandle) + for nwItem in mockItems: + theTree.append(nwItem) + theTree.updateItemData(nwItem.itemHandle) assert len(theTree) == len(mockItems) theTree._treeOrder.append("stuff") @@ -443,24 +471,27 @@ def testCoreTree_ToCFile(monkeypatch, tstPaths, mockGUI, mockItems): return dItem.itemType == nwItemType.FILE monkeypatch.setattr("pathlib.Path.is_file", mockIsFile) + theProject._storage._runtimePath = fncPath + (fncPath / "content").mkdir() - theProject._storage._runtimePath = None - assert theTree.writeToCFile() is False + # Block extraction of the path + with monkeypatch.context() as mp: + mp.setattr("novelwriter.core.storage.NWStorage.contentPath", lambda *a: None) + assert theTree.writeToCFile() is False - theProject._storage._runtimePath = tstPaths.tmpDir + # Block opening the file with monkeypatch.context() as mp: mp.setattr("builtins.open", causeOSError) assert theTree.writeToCFile() is False - theProject._storage._runtimePath = tstPaths.tmpDir - (tstPaths.tmpDir / "content").mkdir() + # Allow writing assert theTree.writeToCFile() is True pathA = str(Path("content") / "c000000000001.nwd") pathB = str(Path("content") / "c000000000002.nwd") pathC = str(Path("content") / "b000000000002.nwd") - assert readFile(tstPaths.tmpDir / nwFiles.TOC_TXT) == ( + assert (fncPath / nwFiles.TOC_TXT).read_text() == ( "\n" "Table of Contents\n" "=================\n"