Improve test coverage of Outline
This commit is contained in:
@@ -461,7 +461,7 @@ class GuiOutlineView(QTreeWidget):
|
|||||||
document editor.
|
document editor.
|
||||||
"""
|
"""
|
||||||
tHandle, tLine = self.getSelectedHandle()
|
tHandle, tLine = self.getSelectedHandle()
|
||||||
self.theParent.openDocument(tHandle, tLine=tLine-1, doScroll=True)
|
self.theParent.openDocument(tHandle, tLine=tLine - 1, doScroll=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
|
|||||||
@@ -1453,7 +1453,7 @@ class GuiMain(QMainWindow):
|
|||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
# Slots
|
# Private Slots
|
||||||
##
|
##
|
||||||
|
|
||||||
@pyqtSlot(str, Enum)
|
@pyqtSlot(str, Enum)
|
||||||
|
|||||||
@@ -19,17 +19,144 @@ You should have received a copy of the GNU General Public License
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import time
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from PyQt5.QtWidgets import QTreeWidgetItem, QMessageBox
|
from tools import buildTestProject, writeFile
|
||||||
|
|
||||||
keyDelay = 2
|
from PyQt5.QtCore import Qt
|
||||||
typeDelay = 1
|
from PyQt5.QtWidgets import QWidget, QMessageBox, QAction
|
||||||
stepDelay = 20
|
|
||||||
|
from novelwriter.enum import nwItemClass, nwOutline, nwView
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.gui
|
@pytest.mark.gui
|
||||||
def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, nwLipsum):
|
def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, fncDir):
|
||||||
|
"""Test the outline view.
|
||||||
|
"""
|
||||||
|
# Block message box
|
||||||
|
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
|
||||||
|
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
|
||||||
|
|
||||||
|
# Create a project
|
||||||
|
prjDir = os.path.join(fncDir, "project")
|
||||||
|
buildTestProject(nwGUI, prjDir)
|
||||||
|
|
||||||
|
nwGUI.rebuildIndex()
|
||||||
|
nwGUI._changeView(nwView.OUTLINE)
|
||||||
|
|
||||||
|
outlineMain = nwGUI.projView
|
||||||
|
outlineView = outlineMain.outlineView
|
||||||
|
outlineData = outlineMain.outlineData
|
||||||
|
outlineMenu = outlineMain.outlineBar.mColumns
|
||||||
|
|
||||||
|
# Toggle scrollbars
|
||||||
|
nwGUI.mainConf.hideVScroll = True
|
||||||
|
nwGUI.mainConf.hideHScroll = True
|
||||||
|
nwGUI.projView.initOutline()
|
||||||
|
assert outlineView.verticalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
|
||||||
|
assert outlineView.horizontalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
|
||||||
|
assert outlineData.verticalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
|
||||||
|
assert outlineData.horizontalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
|
||||||
|
|
||||||
|
nwGUI.mainConf.hideVScroll = False
|
||||||
|
nwGUI.mainConf.hideHScroll = False
|
||||||
|
nwGUI.projView.initOutline()
|
||||||
|
assert outlineView.verticalScrollBarPolicy() == Qt.ScrollBarAsNeeded
|
||||||
|
assert outlineView.horizontalScrollBarPolicy() == Qt.ScrollBarAsNeeded
|
||||||
|
assert outlineData.verticalScrollBarPolicy() == Qt.ScrollBarAsNeeded
|
||||||
|
assert outlineData.horizontalScrollBarPolicy() == Qt.ScrollBarAsNeeded
|
||||||
|
|
||||||
|
# Check focus
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(QWidget, "hasFocus", lambda *a: True)
|
||||||
|
assert outlineMain.treeFocus() is True
|
||||||
|
|
||||||
|
outlineMain.setTreeFocus() # Can't check. just ensures that it doesn't error
|
||||||
|
|
||||||
|
# Option State
|
||||||
|
# ============
|
||||||
|
pOptions = nwGUI.theProject.options
|
||||||
|
colNames = [h.name for h in nwOutline]
|
||||||
|
colItems = [h for h in nwOutline]
|
||||||
|
colWidth = {h: outlineView.DEF_WIDTH[h] for h in nwOutline}
|
||||||
|
colHidden = {h: outlineView.DEF_HIDDEN[h] for h in nwOutline}
|
||||||
|
|
||||||
|
assert outlineView.topLevelItemCount() > 0
|
||||||
|
|
||||||
|
# Save header state not allowed
|
||||||
|
outlineView._lastBuild = 0
|
||||||
|
outlineView._saveHeaderState()
|
||||||
|
assert pOptions.getValue("GuiOutline", "headerOrder", []) == []
|
||||||
|
|
||||||
|
# Allow saving header state
|
||||||
|
outlineView._lastBuild = time.time()
|
||||||
|
outlineView._saveHeaderState()
|
||||||
|
assert pOptions.getValue("GuiOutline", "headerOrder", []) == colNames
|
||||||
|
assert outlineView._treeOrder == colItems
|
||||||
|
assert outlineView._colWidth == colWidth
|
||||||
|
assert outlineView._colHidden == colHidden
|
||||||
|
|
||||||
|
# Get default values
|
||||||
|
optItems = pOptions.getValue("GuiOutline", "headerOrder", [])
|
||||||
|
optWidth = pOptions.getValue("GuiOutline", "columnWidth", {})
|
||||||
|
optHidden = pOptions.getValue("GuiOutline", "columnHidden", {})
|
||||||
|
|
||||||
|
# Add invalid column name
|
||||||
|
pOptions.setValue("GuiOutline", "headerOrder", optItems + ["blabla"])
|
||||||
|
outlineView._loadHeaderState()
|
||||||
|
assert outlineView._treeOrder == colItems
|
||||||
|
assert outlineView._colHidden == colHidden
|
||||||
|
|
||||||
|
# Add duplicate column name
|
||||||
|
pOptions.setValue("GuiOutline", "headerOrder", optItems + [optItems[-1]])
|
||||||
|
outlineView._loadHeaderState()
|
||||||
|
assert outlineView._treeOrder == colItems
|
||||||
|
assert outlineView._colHidden == colHidden
|
||||||
|
|
||||||
|
# Invalid column width data
|
||||||
|
pOptions.setValue("GuiOutline", "headerOrder", optItems)
|
||||||
|
pOptions.setValue("GuiOutline", "columnWidth", {"blabla": None})
|
||||||
|
outlineView._loadHeaderState()
|
||||||
|
assert outlineView._treeOrder == colItems
|
||||||
|
assert outlineView._colHidden == colHidden
|
||||||
|
|
||||||
|
# Invalid column width data
|
||||||
|
pOptions.setValue("GuiOutline", "headerOrder", optItems)
|
||||||
|
pOptions.setValue("GuiOutline", "columnWidth", optWidth)
|
||||||
|
pOptions.setValue("GuiOutline", "columnHidden", {"bloabla": None})
|
||||||
|
outlineView._loadHeaderState()
|
||||||
|
assert outlineView._treeOrder == colItems
|
||||||
|
assert outlineView._colHidden == colHidden
|
||||||
|
|
||||||
|
# Valid settings
|
||||||
|
pOptions.setValue("GuiOutline", "headerOrder", optItems)
|
||||||
|
pOptions.setValue("GuiOutline", "columnWidth", optWidth)
|
||||||
|
pOptions.setValue("GuiOutline", "columnHidden", optHidden)
|
||||||
|
outlineView._loadHeaderState()
|
||||||
|
assert outlineView._treeOrder == colItems
|
||||||
|
assert outlineView._colHidden == colHidden
|
||||||
|
|
||||||
|
# Header Menu
|
||||||
|
# ===========
|
||||||
|
|
||||||
|
# Trigger the menu entry for all hidden columns
|
||||||
|
for hItem in nwOutline:
|
||||||
|
if outlineView.DEF_HIDDEN[hItem]:
|
||||||
|
outlineMenu.actionMap[hItem].activate(QAction.Trigger)
|
||||||
|
|
||||||
|
# Now no columns should be hidden
|
||||||
|
outlineView._saveHeaderState()
|
||||||
|
assert not any(pOptions.getValue("GuiOutline", "columnHidden", None).values())
|
||||||
|
|
||||||
|
# qtbot.stop()
|
||||||
|
|
||||||
|
# END Test testGuiOutline_Main
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gui
|
||||||
|
def testGuiOutline_Content(qtbot, monkeypatch, nwGUI, nwLipsum):
|
||||||
"""Test the outline view.
|
"""Test the outline view.
|
||||||
"""
|
"""
|
||||||
# Block message box
|
# Block message box
|
||||||
@@ -40,26 +167,59 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, nwLipsum):
|
|||||||
nwGUI.mainConf.lastPath = nwLipsum
|
nwGUI.mainConf.lastPath = nwLipsum
|
||||||
|
|
||||||
nwGUI.rebuildIndex()
|
nwGUI.rebuildIndex()
|
||||||
nwGUI.mainStack.setCurrentIndex(nwGUI.idxOutlineView)
|
nwGUI._changeView(nwView.OUTLINE)
|
||||||
|
|
||||||
outlineView = nwGUI.projView.outlineView
|
outlineMain = nwGUI.projView
|
||||||
outlineData = nwGUI.projView.outlineData
|
outlineBar = outlineMain.outlineBar
|
||||||
|
outlineView = outlineMain.outlineView
|
||||||
|
outlineData = outlineMain.outlineData
|
||||||
|
|
||||||
assert outlineView.topLevelItemCount() > 0
|
lipHandle = "b3643d0f92e32"
|
||||||
|
|
||||||
# Context Menu
|
# Check defaults in dropdown list
|
||||||
# outlineView._headerRightClick(QPoint(1, 1))
|
assert outlineBar.novelValue.itemData(0) == lipHandle
|
||||||
# outlineView.headerMenu.actionMap[nwOutline.CCOUNT].activate(QAction.Trigger)
|
assert outlineBar.novelValue.itemData(1) is None # Separator
|
||||||
# outlineView.headerMenu.close()
|
assert outlineBar.novelValue.itemData(2) == "" # All novels
|
||||||
# qtbot.mouseClick(outlineView, Qt.LeftButton)
|
|
||||||
|
|
||||||
# outlineView._loadHeaderState()
|
# Add a second novel folder
|
||||||
# assert not outlineView._colHidden[nwOutline.CCOUNT]
|
newHandle = nwGUI.theProject.newRoot(nwItemClass.NOVEL)
|
||||||
|
nwGUI.treeView.revealNewTreeItem(newHandle)
|
||||||
|
|
||||||
|
# Check new values in dropdown list
|
||||||
|
assert outlineBar.novelValue.itemData(0) == lipHandle
|
||||||
|
assert outlineBar.novelValue.itemData(1) == newHandle
|
||||||
|
assert outlineBar.novelValue.itemData(2) is None # Separator
|
||||||
|
assert outlineBar.novelValue.itemData(3) == "" # All novels
|
||||||
|
|
||||||
|
# Add a bunch of files in a header order that hits all tree combos
|
||||||
|
docList = [
|
||||||
|
("Section 1", 4), ("Scene 1", 3), ("Chapter 1", 2), ("Part 1", 1),
|
||||||
|
("Section 2", 4), ("Scene 2", 3), ("Chapter 2", 2),
|
||||||
|
("Section 3", 4), ("Scene 3", 3),
|
||||||
|
("Section 4", 4),
|
||||||
|
]
|
||||||
|
for dTitle, hLevel in docList:
|
||||||
|
aHandle = nwGUI.theProject.newFile(dTitle, newHandle)
|
||||||
|
hHash = "#"*hLevel
|
||||||
|
writeFile(os.path.join(nwLipsum, "content", f"{aHandle}.nwd"), f"{hHash} {dTitle}\n\n")
|
||||||
|
nwGUI.treeView.revealNewTreeItem(aHandle)
|
||||||
|
|
||||||
|
nwGUI.rebuildIndex()
|
||||||
|
|
||||||
|
# Build the second novel
|
||||||
|
outlineBar.novelValue.setCurrentIndex(1)
|
||||||
|
outlineBar._refreshRequested()
|
||||||
|
|
||||||
|
# Go back to Lipsum
|
||||||
|
outlineBar.novelValue.setCurrentIndex(0)
|
||||||
|
outlineBar._refreshRequested()
|
||||||
|
|
||||||
|
# Check Details
|
||||||
|
# =============
|
||||||
|
|
||||||
# First Item
|
# First Item
|
||||||
outlineView.refreshTree()
|
outlineView.refreshTree()
|
||||||
selItem = outlineView.topLevelItem(0)
|
selItem = outlineView.topLevelItem(0)
|
||||||
assert isinstance(selItem, QTreeWidgetItem)
|
|
||||||
|
|
||||||
outlineView.setCurrentItem(selItem)
|
outlineView.setCurrentItem(selItem)
|
||||||
assert outlineData.titleLabel.text() == "<b>Title</b>"
|
assert outlineData.titleLabel.text() == "<b>Title</b>"
|
||||||
@@ -110,6 +270,6 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, nwLipsum):
|
|||||||
outlineView._treeDoubleClick(selItem, 0)
|
outlineView._treeDoubleClick(selItem, 0)
|
||||||
assert nwGUI.docEditor.docHandle() == "88243afbe5ed8"
|
assert nwGUI.docEditor.docHandle() == "88243afbe5ed8"
|
||||||
|
|
||||||
# qtbot.stopForInteraction()
|
# qtbot.stop()
|
||||||
|
|
||||||
# END Test testGuiOutline_Main
|
# END Test testGuiOutline_Content
|
||||||
|
|||||||
Reference in New Issue
Block a user