Improve test coverage of project tree

This commit is contained in:
Veronica Berglyd Olsen
2023-11-17 21:28:44 +01:00
parent c501e12c9d
commit 16a56d6f60
2 changed files with 172 additions and 56 deletions
+6 -5
View File
@@ -511,7 +511,7 @@ class GuiProjectTree(QTreeWidget):
self.setDragDropMode(QAbstractItemView.InternalMove) self.setDragDropMode(QAbstractItemView.InternalMove)
self.setDropIndicatorShown(True) self.setDropIndicatorShown(True)
# Disable built-in autoscroll as it isn't working in some Qt # Disable built-in auto scroll as it isn't working in some Qt
# releases (see #1561) and instead use our own implementation # releases (see #1561) and instead use our own implementation
self.setAutoScroll(False) self.setAutoScroll(False)
@@ -533,7 +533,7 @@ class GuiProjectTree(QTreeWidget):
self.itemDoubleClicked.connect(self._treeDoubleClick) self.itemDoubleClicked.connect(self._treeDoubleClick)
self.itemSelectionChanged.connect(self._treeSelectionChange) self.itemSelectionChanged.connect(self._treeSelectionChange)
# Autoscroll # Auto Scroll
self._scrollMargin = SHARED.theme.baseIconSize self._scrollMargin = SHARED.theme.baseIconSize
self._scrollDirection = 0 self._scrollDirection = 0
self._scrollTimer = QTimer() self._scrollTimer = QTimer()
@@ -1415,7 +1415,7 @@ class GuiProjectTree(QTreeWidget):
return return
def dragMoveEvent(self, event: QDragMoveEvent) -> None: def dragMoveEvent(self, event: QDragMoveEvent) -> None:
"""Capture the drag move event to enable edge autoscroll.""" """Capture the drag move event to enable edge auto scroll."""
y = event.pos().y() y = event.pos().y()
if y < self._scrollMargin: if y < self._scrollMargin:
if not self._scrollTimer.isActive(): if not self._scrollTimer.isActive():
@@ -1429,8 +1429,8 @@ class GuiProjectTree(QTreeWidget):
return return
def dropEvent(self, event: QDropEvent) -> None: def dropEvent(self, event: QDropEvent) -> None:
"""Overload the drop item event to ensure relevant data has been """Overload the drop item event to ensure the drag and drop
updated. action is allowed, and update relevant data.
""" """
sHandle = self.getSelectedHandle() sHandle = self.getSelectedHandle()
sItem = self._getTreeItem(sHandle) if sHandle else None sItem = self._getTreeItem(sHandle) if sHandle else None
@@ -1455,6 +1455,7 @@ class GuiProjectTree(QTreeWidget):
wCount = self._getItemWordCount(sHandle) wCount = self._getItemWordCount(sHandle)
self.propagateCount(sHandle, 0) self.propagateCount(sHandle, 0)
event.accept()
super().dropEvent(event) super().dropEvent(event)
self._postItemMove(sHandle, wCount) self._postItemMove(sHandle, wCount)
self._recordLastMove(sItem, pItem, pIndex) self._recordLastMove(sItem, pItem, pIndex)
+166 -51
View File
@@ -27,8 +27,9 @@ from pathlib import Path
from tools import C, buildTestProject from tools import C, buildTestProject
from mocked import causeOSError from mocked import causeOSError
from PyQt5.QtCore import Qt from PyQt5.QtGui import QDragMoveEvent, QDropEvent
from PyQt5.QtWidgets import QMessageBox, QMenu, QTreeWidgetItem, QDialog from PyQt5.QtCore import QMimeData, QPoint, QTimer, Qt
from PyQt5.QtWidgets import QMessageBox, QMenu, QTreeWidget, QTreeWidgetItem, QDialog
from novelwriter import CONFIG, SHARED from novelwriter import CONFIG, SHARED
from novelwriter.enum import nwItemLayout, nwItemType, nwItemClass from novelwriter.enum import nwItemLayout, nwItemType, nwItemClass
@@ -46,7 +47,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
projView = nwGUI.projView projView = nwGUI.projView
projTree = nwGUI.projView.projTree projTree = nwGUI.projView.projTree
theProject = SHARED.project project = SHARED.project
# Try to add item with no project # Try to add item with no project
assert projView.projTree.newTreeItem(nwItemType.FILE) is False assert projView.projTree.newTreeItem(nwItemType.FILE) is False
@@ -66,7 +67,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
# Create root item # Create root item
assert projView.projTree.newTreeItem(nwItemType.ROOT, nwItemClass.WORLD) is True assert projView.projTree.newTreeItem(nwItemType.ROOT, nwItemClass.WORLD) is True
assert "0000000000010" in theProject.tree assert "0000000000010" in project.tree
# File/Folder Items # File/Folder Items
# ================= # =================
@@ -81,51 +82,51 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
# Create new folder as child of Novel folder # Create new folder as child of Novel folder
projView.setSelectedHandle(C.hNovelRoot) projView.setSelectedHandle(C.hNovelRoot)
assert projView.projTree.newTreeItem(nwItemType.FOLDER) is True assert projView.projTree.newTreeItem(nwItemType.FOLDER) is True
assert theProject.tree["0000000000011"].itemParent == C.hNovelRoot assert project.tree["0000000000011"].itemParent == C.hNovelRoot # type: ignore
assert theProject.tree["0000000000011"].itemRoot == C.hNovelRoot assert project.tree["0000000000011"].itemRoot == C.hNovelRoot # type: ignore
assert theProject.tree["0000000000011"].itemClass == nwItemClass.NOVEL assert project.tree["0000000000011"].itemClass == nwItemClass.NOVEL # type: ignore
# Add a new file in the new folder # Add a new file in the new folder
projView.setSelectedHandle("0000000000011") projView.setSelectedHandle("0000000000011")
assert projView.projTree.newTreeItem(nwItemType.FILE) is True assert projView.projTree.newTreeItem(nwItemType.FILE) is True
assert theProject.tree["0000000000012"].itemParent == "0000000000011" assert project.tree["0000000000012"].itemParent == "0000000000011" # type: ignore
assert theProject.tree["0000000000012"].itemRoot == C.hNovelRoot assert project.tree["0000000000012"].itemRoot == C.hNovelRoot # type: ignore
assert theProject.tree["0000000000012"].itemClass == nwItemClass.NOVEL assert project.tree["0000000000012"].itemClass == nwItemClass.NOVEL # type: ignore
# Add a new chapter next to the other new file # Add a new chapter next to the other new file
projView.setSelectedHandle("0000000000012") projView.setSelectedHandle("0000000000012")
assert projView.projTree.newTreeItem(nwItemType.FILE, hLevel=2) is True assert projView.projTree.newTreeItem(nwItemType.FILE, hLevel=2) is True
assert theProject.tree["0000000000013"].itemParent == "0000000000011" assert project.tree["0000000000013"].itemParent == "0000000000011" # type: ignore
assert theProject.tree["0000000000013"].itemRoot == C.hNovelRoot assert project.tree["0000000000013"].itemRoot == C.hNovelRoot # type: ignore
assert theProject.tree["0000000000013"].itemClass == nwItemClass.NOVEL assert project.tree["0000000000013"].itemClass == nwItemClass.NOVEL # type: ignore
assert nwGUI.openDocument("0000000000013") assert nwGUI.openDocument("0000000000013")
assert nwGUI.docEditor.getText() == "## New Chapter\n\n" assert nwGUI.docEditor.getText() == "## New Chapter\n\n"
# Add a new scene next to the other new file # Add a new scene next to the other new file
projView.setSelectedHandle("0000000000012") projView.setSelectedHandle("0000000000012")
assert projView.projTree.newTreeItem(nwItemType.FILE, hLevel=3) is True assert projView.projTree.newTreeItem(nwItemType.FILE, hLevel=3) is True
assert theProject.tree["0000000000014"].itemParent == "0000000000011" assert project.tree["0000000000014"].itemParent == "0000000000011" # type: ignore
assert theProject.tree["0000000000014"].itemRoot == C.hNovelRoot assert project.tree["0000000000014"].itemRoot == C.hNovelRoot # type: ignore
assert theProject.tree["0000000000014"].itemClass == nwItemClass.NOVEL assert project.tree["0000000000014"].itemClass == nwItemClass.NOVEL # type: ignore
assert nwGUI.openDocument("0000000000014") assert nwGUI.openDocument("0000000000014")
assert nwGUI.docEditor.getText() == "### New Scene\n\n" assert nwGUI.docEditor.getText() == "### New Scene\n\n"
# Add a new file to the characters folder # Add a new file to the characters folder
projView.setSelectedHandle(C.hCharRoot) projView.setSelectedHandle(C.hCharRoot)
assert projView.projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True) is True assert projView.projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True) is True
assert theProject.tree["0000000000015"].itemParent == C.hCharRoot assert project.tree["0000000000015"].itemParent == C.hCharRoot # type: ignore
assert theProject.tree["0000000000015"].itemRoot == C.hCharRoot assert project.tree["0000000000015"].itemRoot == C.hCharRoot # type: ignore
assert theProject.tree["0000000000015"].itemClass == nwItemClass.CHARACTER assert project.tree["0000000000015"].itemClass == nwItemClass.CHARACTER # type: ignore
assert nwGUI.openDocument("0000000000015") assert nwGUI.openDocument("0000000000015")
assert nwGUI.docEditor.getText() == "# New Note\n\n" assert nwGUI.docEditor.getText() == "# New Note\n\n"
# Make sure the sibling folder bug trap works # Make sure the sibling folder bug trap works
projView.setSelectedHandle("0000000000013") projView.setSelectedHandle("0000000000013")
theProject.tree["0000000000013"].setParent(None) # This should not happen project.tree["0000000000013"].setParent(None) # This should not happen # type: ignore
caplog.clear() caplog.clear()
assert projView.projTree.newTreeItem(nwItemType.FILE) is False assert projView.projTree.newTreeItem(nwItemType.FILE) is False
assert "Internal error" in caplog.text assert "Internal error" in caplog.text
theProject.tree["0000000000013"].setParent("0000000000011") project.tree["0000000000013"].setParent("0000000000011") # type: ignore
# Cancel during creation # Cancel during creation
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
@@ -135,7 +136,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
# Get the trash folder # Get the trash folder
projView.projTree._addTrashRoot() projView.projTree._addTrashRoot()
trashHandle = theProject.trashFolder() trashHandle = project.trashFolder()
projView.setSelectedHandle(trashHandle) projView.setSelectedHandle(trashHandle)
assert projView.projTree.newTreeItem(nwItemType.FILE) is False assert projView.projTree.newTreeItem(nwItemType.FILE) is False
assert "Cannot add new files or folders to the Trash folder" in caplog.text assert "Cannot add new files or folders to the Trash folder" in caplog.text
@@ -147,7 +148,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr(GuiEditLabel, "getLabel", lambda *a, **k: ("Stuff", True)) mp.setattr(GuiEditLabel, "getLabel", lambda *a, **k: ("Stuff", True))
projTree.renameTreeItem(C.hPlotRoot) is True projTree.renameTreeItem(C.hPlotRoot) is True
assert theProject.tree[C.hPlotRoot].itemName == "Stuff" assert project.tree[C.hPlotRoot].itemName == "Stuff" # type: ignore
# Rename invalid folder # Rename invalid folder
projTree.renameTreeItem("0000000000000") is False projTree.renameTreeItem("0000000000000") is False
@@ -159,7 +160,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
assert projView.projTree.revealNewTreeItem("abc") is False assert projView.projTree.revealNewTreeItem("abc") is False
# Add an item that cannot be displayed in the tree # Add an item that cannot be displayed in the tree
nHandle = theProject.newFile("Test", None) nHandle = project.newFile("Test", None) # type: ignore
assert projView.projTree.revealNewTreeItem(nHandle) is False assert projView.projTree.revealNewTreeItem(nHandle) is False
# Adding an invalid item directly to the tree should also fail # Adding an invalid item directly to the tree should also fail
@@ -550,7 +551,7 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
SHARED.project.newFile("SubNote", hNovelNote) SHARED.project.newFile("SubNote", hNovelNote)
projTree.revealNewTreeItem(hSubNote) projTree.revealNewTreeItem(hSubNote)
assert SHARED.project.tree[hSubNote].itemParent == hNovelNote assert SHARED.project.tree[hSubNote].itemParent == hNovelNote # type: ignore
def itemPos(tHandle): def itemPos(tHandle):
return projTree.visualItemRect(projTree._getTreeItem(tHandle)).center() return projTree.visualItemRect(projTree._getTreeItem(tHandle)).center()
@@ -579,6 +580,7 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
# ===================== # =====================
# Trigger the dedicated functions the menu entries connect to # Trigger the dedicated functions the menu entries connect to
nwItem = SHARED.project.tree[hNovelNote] nwItem = SHARED.project.tree[hNovelNote]
assert nwItem is not None
# Toggle active flag # Toggle active flag
assert nwItem.isActive is True assert nwItem.isActive is True
@@ -619,17 +621,17 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No) mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
projTree._covertFolderToFile(hNewFolderOne, nwItemLayout.DOCUMENT) projTree._covertFolderToFile(hNewFolderOne, nwItemLayout.DOCUMENT)
assert SHARED.project.tree[hNewFolderOne].isFolderType() assert SHARED.project.tree[hNewFolderOne].isFolderType() # type: ignore
# Convert the first folder to a document # Convert the first folder to a document
projTree._covertFolderToFile(hNewFolderOne, nwItemLayout.DOCUMENT) projTree._covertFolderToFile(hNewFolderOne, nwItemLayout.DOCUMENT)
assert SHARED.project.tree[hNewFolderOne].isFileType() assert SHARED.project.tree[hNewFolderOne].isFileType() # type: ignore
assert SHARED.project.tree[hNewFolderOne].isDocumentLayout() assert SHARED.project.tree[hNewFolderOne].isDocumentLayout() # type: ignore
# Convert the second folder to a note # Convert the second folder to a note
projTree._covertFolderToFile(hNewFolderTwo, nwItemLayout.NOTE) projTree._covertFolderToFile(hNewFolderTwo, nwItemLayout.NOTE)
assert SHARED.project.tree[hNewFolderTwo].isFileType() assert SHARED.project.tree[hNewFolderTwo].isFileType() # type: ignore
assert SHARED.project.tree[hNewFolderTwo].isNoteLayout() assert SHARED.project.tree[hNewFolderTwo].isNoteLayout() # type: ignore
# qtbot.stop() # qtbot.stop()
@@ -646,19 +648,18 @@ def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
monkeypatch.setattr(GuiDocMerge, "result", lambda *a: QDialog.Accepted) monkeypatch.setattr(GuiDocMerge, "result", lambda *a: QDialog.Accepted)
monkeypatch.setattr(GuiDocMerge, "getData", lambda *a: mergeData) monkeypatch.setattr(GuiDocMerge, "getData", lambda *a: mergeData)
# Create a project
buildTestProject(nwGUI, projPath) buildTestProject(nwGUI, projPath)
theProject = SHARED.project project = SHARED.project
projTree = nwGUI.projView.projTree projTree = nwGUI.projView.projTree
mergedDoc1 = "0000000000014" mergedDoc1 = "0000000000014"
# Create File to Merge # Create File to Merge
hChapter1 = theProject.newFile("Chapter 1", C.hNovelRoot) hChapter1 = project.newFile("Chapter 1", C.hNovelRoot)
hSceneOne11 = theProject.newFile("Scene 1.1", hChapter1) hSceneOne11 = project.newFile("Scene 1.1", hChapter1) # type: ignore
hSceneOne12 = theProject.newFile("Scene 1.2", hChapter1) hSceneOne12 = project.newFile("Scene 1.2", hChapter1) # type: ignore
hSceneOne13 = theProject.newFile("Scene 1.3", hChapter1) hSceneOne13 = project.newFile("Scene 1.3", hChapter1) # type: ignore
docText1 = "\n\n".join(ipsumText[0:2]) + "\n\n" docText1 = "\n\n".join(ipsumText[0:2]) + "\n\n"
docText2 = "\n\n".join(ipsumText[1:3]) + "\n\n" docText2 = "\n\n".join(ipsumText[1:3]) + "\n\n"
@@ -671,10 +672,10 @@ def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
lenText4 = len(docText4) lenText4 = len(docText4)
lenAll = lenText1 + lenText2 + lenText3 + lenText4 lenAll = lenText1 + lenText2 + lenText3 + lenText4
theProject.writeNewFile(hChapter1, 2, True, docText1) project.writeNewFile(hChapter1, 2, True, docText1) # type: ignore
theProject.writeNewFile(hSceneOne11, 3, True, docText2) project.writeNewFile(hSceneOne11, 3, True, docText2) # type: ignore
theProject.writeNewFile(hSceneOne12, 3, True, docText3) project.writeNewFile(hSceneOne12, 3, True, docText3) # type: ignore
theProject.writeNewFile(hSceneOne13, 3, True, docText4) project.writeNewFile(hSceneOne13, 3, True, docText4) # type: ignore
projTree.revealNewTreeItem(hChapter1) projTree.revealNewTreeItem(hChapter1)
projTree.revealNewTreeItem(hSceneOne11) projTree.revealNewTreeItem(hSceneOne11)
@@ -705,7 +706,7 @@ def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
# The merge goes through # The merge goes through
assert projTree._mergeDocuments(hChapter1, True) is True assert projTree._mergeDocuments(hChapter1, True) is True
assert len(theProject.storage.getDocument(mergedDoc1).readDocument()) > lenAll assert len(project.storage.getDocument(mergedDoc1).readDocument()) > lenAll # type: ignore
# Merge to Existing Doc # Merge to Existing Doc
# ===================== # =====================
@@ -724,13 +725,13 @@ def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
# Successful merge, and move to trash # Successful merge, and move to trash
mergeData["moveToTrash"] = True mergeData["moveToTrash"] = True
assert len(theProject.storage.getDocument(hChapter1).readDocument()) < lenAll assert len(project.storage.getDocument(hChapter1).readDocument()) < lenAll # type: ignore
assert projTree._mergeDocuments(hChapter1, False) is True assert projTree._mergeDocuments(hChapter1, False) is True
assert len(theProject.storage.getDocument(hChapter1).readDocument()) > lenAll assert len(project.storage.getDocument(hChapter1).readDocument()) > lenAll # type: ignore
assert theProject.tree.isTrash(hSceneOne11) assert project.tree.isTrash(hSceneOne11) # type: ignore
assert theProject.tree.isTrash(hSceneOne12) assert project.tree.isTrash(hSceneOne12) # type: ignore
assert theProject.tree.isTrash(hSceneOne13) assert project.tree.isTrash(hSceneOne13) # type: ignore
# qtbot.stop() # qtbot.stop()
@@ -770,7 +771,7 @@ def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
) )
hSplitDoc = theProject.newFile("Split Doc", C.hNovelRoot) hSplitDoc = theProject.newFile("Split Doc", C.hNovelRoot)
theProject.writeNewFile(hSplitDoc, 1, True, docText) theProject.writeNewFile(hSplitDoc, 1, True, docText) # type: ignore
projTree.revealNewTreeItem(hSplitDoc, nHandle=C.hNovelRoot, wordCount=True) projTree.revealNewTreeItem(hSplitDoc, nHandle=C.hNovelRoot, wordCount=True)
docText = f"# Split Doc\n\n{docText}" docText = f"# Split Doc\n\n{docText}"
@@ -835,7 +836,7 @@ def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
assert tHandle in theProject.tree assert tHandle in theProject.tree
assert (projPath / "content" / f"{tHandle}.nwd").is_file() assert (projPath / "content" / f"{tHandle}.nwd").is_file()
assert theProject.tree.isTrash(hSplitDoc) is True assert theProject.tree.isTrash(hSplitDoc) is True # type: ignore
# Cancelled by user # Cancelled by user
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
@@ -880,7 +881,7 @@ def testGuiProjTree_Duplicate(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mock
assert projTree._duplicateFromHandle(C.hNovelRoot) is True assert projTree._duplicateFromHandle(C.hNovelRoot) is True
assert len(SHARED.project.tree) == 21 assert len(SHARED.project.tree) == 21
# Check tree order that all items are next to eachother # Check tree order that all items are next to each other
assert SHARED.project.tree._order == [ assert SHARED.project.tree._order == [
C.hNovelRoot, C.hTitlePage, "0000000000010", C.hChapterDir, C.hChapterDoc, C.hSceneDoc, C.hNovelRoot, C.hTitlePage, "0000000000010", C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
"0000000000011", "0000000000012", "0000000000013", "0000000000014", "0000000000015", "0000000000011", "0000000000012", "0000000000013", "0000000000014", "0000000000015",
@@ -904,14 +905,128 @@ def testGuiProjTree_Duplicate(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mock
# END Test testGuiProjTree_Duplicate # END Test testGuiProjTree_Duplicate
@pytest.mark.gui
def testGuiProjTree_AutoScroll(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mockRnd):
"""Test the auto scroll feature."""
buildTestProject(nwGUI, projPath)
projTree: GuiProjectTree = nwGUI.projView.projTree
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda parent, text: (text, True))
monkeypatch.setattr(QTreeWidget, "dragMoveEvent", lambda *a, **k: None)
monkeypatch.setattr(QTimer, "isActive", lambda *a: False)
monkeypatch.setattr(QTimer, "start", lambda *a: None)
projTree.setSelectedHandle(C.hChapterDir, True)
projTree._getTreeItem(C.hChapterDir).setExpanded(True) # type: ignore
for i in range(100):
projTree.newTreeItem(nwItemType.FILE, None, 3, False)
projTree.setSelectedHandle("0000000000015", True)
nwGUI.resize(500, 500)
action = Qt.DropAction.MoveAction
mime = QMimeData()
mouse = Qt.MouseButton.LeftButton
modifier = Qt.KeyboardModifier.NoModifier
# Scroll Down
h = projTree.height()
projTree.dragMoveEvent(QDragMoveEvent(QPoint(1, h-1), action, mime, mouse, modifier))
assert projTree._scrollDirection == 1
projTree._doAutoScroll()
assert projTree._scrollDirection == 0
projTree.dragMoveEvent(QDragMoveEvent(QPoint(1, h-2), action, mime, mouse, modifier))
assert projTree._scrollDirection == 1
projTree._doAutoScroll()
assert projTree._scrollDirection == 0
projTree.dragMoveEvent(QDragMoveEvent(QPoint(1, h-3), action, mime, mouse, modifier))
assert projTree._scrollDirection == 1
projTree._doAutoScroll()
assert projTree._scrollDirection == 0
projTree.dragMoveEvent(QDragMoveEvent(QPoint(1, h-4), action, mime, mouse, modifier))
assert projTree._scrollDirection == 1
projTree._doAutoScroll()
assert projTree._scrollDirection == 0
# Scroll Up
projTree.dragMoveEvent(QDragMoveEvent(QPoint(1, 1), action, mime, mouse, modifier))
assert projTree._scrollDirection == -1
projTree._doAutoScroll()
assert projTree._scrollDirection == 0
projTree.dragMoveEvent(QDragMoveEvent(QPoint(1, 2), action, mime, mouse, modifier))
assert projTree._scrollDirection == -1
projTree._doAutoScroll()
assert projTree._scrollDirection == 0
projTree.dragMoveEvent(QDragMoveEvent(QPoint(1, 3), action, mime, mouse, modifier))
assert projTree._scrollDirection == -1
projTree._doAutoScroll()
assert projTree._scrollDirection == 0
projTree.dragMoveEvent(QDragMoveEvent(QPoint(1, 4), action, mime, mouse, modifier))
assert projTree._scrollDirection == -1
projTree._doAutoScroll()
assert projTree._scrollDirection == 0
# qtbot.stop()
# END Test testGuiProjTree_AutoScroll
@pytest.mark.gui
def testGuiProjTree_DragAndDrop(qtbot, monkeypatch, caplog, nwGUI: GuiMain, projPath, mockRnd):
"""Test the auto scroll feature."""
buildTestProject(nwGUI, projPath)
projTree: GuiProjectTree = nwGUI.projView.projTree
monkeypatch.setattr(QTreeWidget, "dropEvent", lambda *a, **k: None)
projTree.setSelectedHandle(C.hSceneDoc, True)
projTree._getTreeItem(C.hChapterDir).setExpanded(True) # type: ignore
nPos = projTree.visualItemRect(projTree._getTreeItem(C.hNovelRoot)).bottomLeft()
action = Qt.DropAction.MoveAction
mime = QMimeData()
mouse = Qt.MouseButton.LeftButton
modifier = Qt.KeyboardModifier.NoModifier
event = QDropEvent(nPos, action, mime, mouse, modifier)
projTree.dropEvent(event)
assert event.isAccepted() is True
# Invalid location
caplog.clear()
event = QDropEvent(QPoint(1000, 1000), action, mime, mouse, modifier)
projTree.dropEvent(event)
assert event.isAccepted() is False
assert "Invalid drop location" in caplog.text
# No item selected
caplog.clear()
event = QDropEvent(nPos, action, mime, mouse, modifier)
projTree.clearSelection()
projTree.dropEvent(event)
assert event.isAccepted() is False
assert "Invalid drag and drop event" in caplog.text
# Root item selected
caplog.clear()
event = QDropEvent(nPos, action, mime, mouse, modifier)
projTree.clearSelection()
projTree.setSelectedHandle(C.hNovelRoot, True)
projTree.dropEvent(event)
assert event.isAccepted() is False
assert "Invalid drag and drop event" in caplog.text
# qtbot.stop()
# END Test testGuiProjTree_DragAndDrop
@pytest.mark.gui @pytest.mark.gui
def testGuiProjTree_Other(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mockRnd): def testGuiProjTree_Other(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mockRnd):
"""Test various parts of the project tree class not covered by """Test various parts of the project tree class not covered by
other tests. other tests.
""" """
# Create a project
buildTestProject(nwGUI, projPath) buildTestProject(nwGUI, projPath)
projView: GuiProjectView = nwGUI.projView projView: GuiProjectView = nwGUI.projView
projTree: GuiProjectTree = nwGUI.projView.projTree projTree: GuiProjectTree = nwGUI.projView.projTree