diff --git a/tests/test_dialogs/test_dlg_preferences.py b/tests/test_dialogs/test_dlg_preferences.py index c4c2e590..408865c7 100644 --- a/tests/test_dialogs/test_dlg_preferences.py +++ b/tests/test_dialogs/test_dlg_preferences.py @@ -22,9 +22,11 @@ from __future__ import annotations import pytest +from tools import getGuiItem + from PyQt5.QtGui import QFontDatabase, QKeyEvent from PyQt5.QtCore import QEvent, Qt -from PyQt5.QtWidgets import QDialogButtonBox, QFileDialog, QFontDialog +from PyQt5.QtWidgets import QAction, QDialogButtonBox, QFileDialog, QFontDialog from novelwriter import CONFIG, SHARED from novelwriter.constants import nwConst, nwUnicode @@ -38,9 +40,13 @@ KEY_DELAY = 1 def testDlgPreferences_Main(qtbot, monkeypatch, nwGUI, tstPaths): """Test the preferences dialog loading.""" monkeypatch.setattr(SHARED._spelling, "listDictionaries", lambda: [("en", "English [en]")]) + monkeypatch.setattr(GuiPreferences, "exec_", lambda *a: None) # Load GUI with standard values - prefs = GuiPreferences(nwGUI) + nwGUI.mainMenu.aPreferences.activate(QAction.ActionEvent.Trigger) + qtbot.waitUntil(lambda: getGuiItem("GuiPreferences") is not None, timeout=1000) + prefs = getGuiItem("GuiPreferences") + assert isinstance(prefs, GuiPreferences) prefs.show() # Check Languages @@ -95,10 +101,6 @@ def testDlgPreferences_Actions(qtbot, monkeypatch, nwGUI): # Check Navigation vBar = prefs.mainForm.verticalScrollBar() old = -1 - with qtbot.waitSignal(vBar.valueChanged) as value: - prefs.sidebar.button(0).click() - assert value.args[0] > old - old = value.args[0] with qtbot.waitSignal(vBar.valueChanged) as value: prefs.sidebar.button(1).click() assert value.args[0] > old @@ -107,6 +109,10 @@ def testDlgPreferences_Actions(qtbot, monkeypatch, nwGUI): prefs.sidebar.button(2).click() assert value.args[0] > old old = value.args[0] + with qtbot.waitSignal(vBar.valueChanged) as value: + prefs.sidebar.button(3).click() + assert value.args[0] > old + old = value.args[0] # Check Search prefs.searchText.setText("Display language") diff --git a/tests/test_tools/test_tools_noveldetails.py b/tests/test_tools/test_tools_noveldetails.py new file mode 100644 index 00000000..c8925e53 --- /dev/null +++ b/tests/test_tools/test_tools_noveldetails.py @@ -0,0 +1,136 @@ +""" +novelWriter – Novel Details Tool Tester +======================================= + +This file is a part of novelWriter +Copyright 2018–2024, Veronica Berglyd Olsen + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" +from __future__ import annotations + +import pytest + +from tools import getGuiItem + +from PyQt5.QtWidgets import QAction + +from novelwriter import SHARED +from novelwriter.enum import nwItemClass +from novelwriter.tools.noveldetails import GuiNovelDetails + + +@pytest.mark.gui +def testToolNovelDetails_Main(qtbot, nwGUI, prjLipsum, ipsumText): + """Test the Novel Details main dialog.""" + nwGUI.openProject(prjLipsum) + nHandle = "b3643d0f92e32" + + # Add a second Novel folder + project = SHARED.project + secondText = "#! Second\n\n" + "\n\n".join(ipsumText) + sHandle = project.newRoot(nwItemClass.NOVEL, "Second") + dHandle = project.newFile("Document", sHandle) + project.storage.getDocument(dHandle).writeDocument(secondText) + project.index.reIndexHandle(dHandle) + nwGUI.projView.projTree.revealNewTreeItem(sHandle) + nwGUI.projView.projTree.revealNewTreeItem(dHandle) + + # Create the dialog + nwGUI.mainMenu.aNovelDetails.activate(QAction.ActionEvent.Trigger) + qtbot.waitUntil(lambda: getGuiItem("GuiNovelDetails") is not None, timeout=1000) + details = getGuiItem("GuiNovelDetails") + assert isinstance(details, GuiNovelDetails) + + # Overview Page + # ============= + overview = details.overviewPage + + # The selector should default to the first entry + assert details.novelSelector.handle == nHandle + + # Check project data + assert overview.projName.text() == "Lorem Ipsum" + assert overview.projWords.text() == f"{4376:n}" + assert overview.projNovels.text() == f"{3638:n}" + assert overview.projNotes.text() == f"{738:n}" + assert overview.projRevisions.text() != "" + assert overview.projEditTime.text() != "" + + # Check novel data for "Novel" + assert overview.novelName.text() == "Novel" + assert overview.novelWords.text() == f"{3000:n}" + assert overview.novelChapters.text() == f"{3:n}" + assert overview.novelScenes.text() == f"{5:n}" + + # Check novel data for "Second" + details.novelSelector.setHandle(sHandle, blockSignal=False) + assert overview.novelName.text() == "Second" + assert overview.novelWords.text() == f"{529:n}" + assert overview.novelChapters.text() == f"{0:n}" + assert overview.novelScenes.text() == f"{0:n}" + + # Contents Page + # ============= + details.novelSelector.setHandle(nHandle, blockSignal=False) + details.sidebar.button(details.PAGE_CONTENTS).click() + assert details.mainStack.currentIndex() == 1 + contents = details.contentsPage + + # Check defaults + words = [f"{v:n}" for v in [40, 176, 92, 6, 1071, 1615, 0]] + pages = [f"{v:n}" for v in [2, 2, 2, 2, 4, 6, 0]] + page = [f"{v:n}" for v in [1, 3, 5, 7, 9, 13, 19]] + for i in range(6): + item = contents.tocTree.topLevelItem(i) + assert item is not None + assert item.text(contents.C_WORDS) == words[i] + assert item.text(contents.C_PAGES) == pages[i] + assert item.text(contents.C_PAGE) == page[i] + + # Change Settings + contents.poValue.setValue(7) + contents.wpValue.setValue(50) + words = [f"{v:n}" for v in [40, 176, 92, 6, 1071, 1615, 0]] + pages = [f"{v:n}" for v in [2, 4, 2, 2, 22, 34, 0]] + page = ["i", "iii"] + [f"{v:n}" for v in [1, 3, 5, 27, 61]] + for i in range(6): + item = contents.tocTree.topLevelItem(i) + assert item is not None + assert item.text(contents.C_WORDS) == words[i] + assert item.text(contents.C_PAGES) == pages[i] + assert item.text(contents.C_PAGE) == page[i] + + # Turn off use odd pages + contents.dblValue.setChecked(False) + contents.poValue.setValue(0) + contents.wpValue.setValue(100) + words = [f"{v:n}" for v in [40, 176, 92, 6, 1071, 1615, 0]] + pages = [f"{v:n}" for v in [1, 2, 1, 1, 11, 17, 0]] + page = [f"{v:n}" for v in [1, 2, 4, 5, 6, 17, 34]] + for i in range(6): + item = contents.tocTree.topLevelItem(i) + assert item is not None + assert item.text(contents.C_WORDS) == words[i] + assert item.text(contents.C_PAGES) == pages[i] + assert item.text(contents.C_PAGE) == page[i] + + # Revert to Overview page + details.sidebar.button(details.PAGE_OVERVIEW).click() + assert details.mainStack.currentIndex() == 0 + + # qtbot.stop() + details.close() + +# END Test testToolNovelDetails_Main diff --git a/tests/tools.py b/tests/tools.py index 6bc21966..51cdcc19 100644 --- a/tests/tools.py +++ b/tests/tools.py @@ -156,20 +156,23 @@ def cleanProject(path: str | Path): return -def buildTestProject(obj, projPath): +def buildTestProject(obj: object, projPath: Path) -> None: """Build a standard test project in projPath using the project object as the parent. """ from novelwriter.enum import nwItemClass + from novelwriter.guimain import GuiMain from novelwriter.core.project import NWProject if isinstance(obj, NWProject): nwGUI = None project = obj - else: + elif isinstance(obj, GuiMain): from novelwriter import SHARED nwGUI = obj project = SHARED.project + else: + return project.storage.createNewProject(projPath) project.setDefaultStatusImport() @@ -181,27 +184,27 @@ def buildTestProject(obj, projPath): # Creating a minimal project with a few root folders and a # single chapter folder with a single file. - xHandle = {} - xHandle[1] = project.newRoot(nwItemClass.NOVEL, "Novel") - xHandle[2] = project.newRoot(nwItemClass.PLOT, "Plot") - xHandle[3] = project.newRoot(nwItemClass.CHARACTER, "Characters") - xHandle[4] = project.newRoot(nwItemClass.WORLD, "World") - xHandle[5] = project.newFile("Title Page", xHandle[1]) - xHandle[6] = project.newFolder("New Chapter", xHandle[1]) - xHandle[7] = project.newFile("New Chapter", xHandle[6]) - xHandle[8] = project.newFile("New Scene", xHandle[6]) + nrHandle = project.newRoot(nwItemClass.NOVEL, "Novel") + project.newRoot(nwItemClass.PLOT, "Plot") + project.newRoot(nwItemClass.CHARACTER, "Characters") + project.newRoot(nwItemClass.WORLD, "World") - aDoc = project.storage.getDocument(xHandle[5]) + tdHandle = project.newFile("Title Page", nrHandle) + cfHandle = project.newFolder("New Chapter", nrHandle) or "" + cdHandle = project.newFile("New Chapter", cfHandle) + sdHandle = project.newFile("New Scene", cfHandle) + + aDoc = project.storage.getDocument(tdHandle) aDoc.writeDocument("#! New Novel\n\n>> By Jane Doe <<\n") - project.index.reIndexHandle(xHandle[5]) + project.index.reIndexHandle(tdHandle) - aDoc = project.storage.getDocument(xHandle[7]) + aDoc = project.storage.getDocument(cdHandle) aDoc.writeDocument("## %s\n\n" % project.tr("New Chapter")) - project.index.reIndexHandle(xHandle[7]) + project.index.reIndexHandle(cdHandle) - aDoc = project.storage.getDocument(xHandle[8]) + aDoc = project.storage.getDocument(sdHandle) aDoc.writeDocument("### %s\n\n" % project.tr("New Scene")) - project.index.reIndexHandle(xHandle[8]) + project.index.reIndexHandle(sdHandle) project.session.startSession() project.setProjectChanged(True)