Merge branch 'dev' into feature/build_gui

This commit is contained in:
Veronica Berglyd Olsen
2023-05-16 23:45:22 +02:00
69 changed files with 960 additions and 1037 deletions
+69 -69
View File
@@ -28,19 +28,60 @@ from pathlib import Path
from mock import MockGuiMain
from tools import cleanProject
from PyQt5.QtWidgets import QMessageBox
sys.path.insert(1, str(Path(__file__).parent.parent.absolute()))
import novelwriter # noqa: E402
from novelwriter import CONFIG, main # noqa: E402
from PyQt5.QtWidgets import QMessageBox # noqa: E402
from novelwriter.config import Config # noqa: E402
_TST_ROOT = Path(__file__).parent
_TMP_ROOT = _TST_ROOT / "temp"
_TMP_CONF = _TMP_ROOT / "conf"
@pytest.fixture(autouse=True)
def initQt(qtbot):
"""Ensures that the qt main thread is always available in all tests.
##
# Helper Functions
##
def resetConfigVars():
"""Reset the CONFIG object and set various values for testing to
prevent interfering with local OS.
"""
CONFIG.setLastPath(_TMP_ROOT)
CONFIG.setBackupPath(_TMP_ROOT)
CONFIG._homePath = _TMP_ROOT
CONFIG.guiLocale = "en_GB"
return
##
# Auto Fixtures
##
@pytest.fixture(scope="session", autouse=True)
def sessionFixture():
"""A session wide fixture to set up the test environment.
"""
if _TMP_ROOT.exists():
shutil.rmtree(_TMP_ROOT)
_TMP_ROOT.mkdir()
_TMP_CONF.mkdir()
return
@pytest.fixture(scope="function", autouse=True)
def functionFixture(qtbot):
"""Ensures that the main Qt thread is always available, and reset
the config object for each function and redirect its storage paths.
"""
if _TMP_CONF.exists():
shutil.rmtree(_TMP_CONF)
_TMP_CONF.mkdir()
CONFIG.__init__()
CONFIG.initConfig(confPath=_TMP_CONF, dataPath=_TMP_CONF)
resetConfigVars()
return
@@ -49,26 +90,17 @@ def initQt(qtbot):
##
@pytest.fixture(scope="session")
def tmpPath():
"""A temporary folder for the test session. Path version.
"""
theTemp = Path(__file__).parent / "temp"
if theTemp.exists():
shutil.rmtree(theTemp)
theTemp.mkdir(exist_ok=True)
return theTemp
@pytest.fixture(scope="session")
def tstPaths(tmpPath):
def tstPaths():
"""Returns an object that can provide the various paths needed for
running tests.
"""
class _Store:
testDir = Path(__file__).parent
filesDir = testDir / "files"
refDir = testDir / "reference"
outDir = tmpPath / "results"
testDir = _TST_ROOT
filesDir = _TST_ROOT / "files"
refDir = _TST_ROOT / "reference"
outDir = _TMP_ROOT / "results"
tmpDir = _TMP_ROOT
cnfDir = _TMP_CONF
store = _Store()
store.outDir.mkdir(exist_ok=True)
@@ -77,10 +109,10 @@ def tstPaths(tmpPath):
@pytest.fixture(scope="function")
def fncPath(tmpPath):
"""A temporary folder for a single test function. Path version.
def fncPath():
"""A temporary folder for a single test function.
"""
fncPath = tmpPath / "function"
fncPath = _TMP_ROOT / "function"
if fncPath.is_dir():
shutil.rmtree(fncPath)
fncPath.mkdir(exist_ok=True)
@@ -103,46 +135,17 @@ def projPath(fncPath):
# novelWriter Objects
##
@pytest.fixture(scope="function")
def tmpConf(tmpPath):
"""Create a temporary novelWriter configuration object.
"""
confFile = tmpPath / "novelwriter.conf"
if confFile.is_file():
confFile.unlink()
theConf = Config()
theConf.initConfig(tmpPath, tmpPath)
theConf.setLastPath(tmpPath)
theConf.guiLocale = "en_GB"
return theConf
@pytest.fixture(scope="function")
def fncConf(fncPath):
"""Create a temporary novelWriter configuration object.
"""
confFile = fncPath / "novelwriter.conf"
if confFile.is_file():
confFile.unlink()
theConf = Config()
theConf.initConfig(fncPath, fncPath)
theConf.setLastPath(fncPath)
theConf.guiLocale = "en_GB"
return theConf
@pytest.fixture(scope="function")
def mockGUI(monkeypatch, tmpConf):
def mockGUI():
"""Create a mock instance of novelWriter's main GUI class.
"""
monkeypatch.setattr("novelwriter.CONFIG", tmpConf)
theGui = MockGuiMain()
theGui.mainConf = tmpConf
return theGui
@pytest.fixture(scope="function")
def nwGUI(qtbot, monkeypatch, fncPath, fncConf):
def nwGUI(qtbot, monkeypatch, functionFixture):
"""Create an instance of the novelWriter GUI.
"""
monkeypatch.setattr(QMessageBox, "warning", lambda *a: QMessageBox.Ok)
@@ -150,14 +153,13 @@ def nwGUI(qtbot, monkeypatch, fncPath, fncConf):
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Ok)
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr("novelwriter.CONFIG", fncConf)
nwGUI = novelwriter.main(["--testmode", f"--config={fncPath}", f"--data={fncPath}"])
nwGUI = main(["--testmode", f"--config={_TMP_CONF}", f"--data={_TMP_CONF}"])
qtbot.addWidget(nwGUI)
resetConfigVars()
nwGUI.show()
qtbot.wait(20)
nwGUI.mainConf.setLastPath(fncPath)
yield nwGUI
qtbot.wait(20)
@@ -198,13 +200,12 @@ def mockRnd(monkeypatch):
##
@pytest.fixture(scope="function")
def nwLipsum(tmpPath):
def nwLipsum():
"""A medium sized novelWriter example project with a lot of Lorem
Ipsum text.
"""
tstDir = Path(__file__).parent
srcDir = tstDir / "lipsum"
dstDir = tmpPath / "lipsum"
srcDir = _TST_ROOT / "lipsum"
dstDir = _TMP_ROOT / "lipsum"
if dstDir.exists():
shutil.rmtree(dstDir)
@@ -220,13 +221,12 @@ def nwLipsum(tmpPath):
@pytest.fixture(scope="function")
def prjLipsum(tmpPath):
def prjLipsum():
"""A medium sized novelWriter example project with a lot of Lorem
Ipsum text.
"""
tstDir = Path(__file__).parent
srcDir = tstDir / "lipsum"
dstDir = tmpPath / "lipsum"
srcDir = _TST_ROOT / "lipsum"
dstDir = _TMP_ROOT / "lipsum"
if dstDir.exists():
shutil.rmtree(dstDir)
-1
View File
@@ -31,7 +31,6 @@ class MockGuiMain(QObject):
def __init__(self):
super().__init__()
self.mainConf = None
self.hasProject = True
self.theProject = None
self.mainStatus = MockStatusBar()
+119 -109
View File
@@ -28,6 +28,7 @@ from pathlib import Path
from mock import causeOSError, MockApp
from tools import cmpFiles, writeFile
from novelwriter import CONFIG
from novelwriter.config import Config, RecentProjects
from novelwriter.constants import nwFiles
@@ -196,197 +197,206 @@ def testBaseConfig_Localisation(fncPath, tstPaths):
@pytest.mark.base
def testBaseConfig_Methods(tmpConf, tmpPath):
def testBaseConfig_Methods(fncPath):
"""Check class methods.
"""
tstConf = Config()
tstConf.initConfig(confPath=fncPath, dataPath=fncPath)
# Data Path
assert tmpConf.dataPath() == tmpPath
assert tmpConf.dataPath("stuff") == tmpPath / "stuff"
assert tstConf.dataPath() == fncPath
assert tstConf.dataPath("stuff") == fncPath / "stuff"
# Assets Path
appPath = tmpConf._appPath
assert tmpConf.assetPath() == appPath / "assets"
assert tmpConf.assetPath("stuff") == appPath / "assets" / "stuff"
appPath = tstConf._appPath
assert tstConf.assetPath() == appPath / "assets"
assert tstConf.assetPath("stuff") == appPath / "assets" / "stuff"
# Last Path
assert tmpConf.lastPath() == tmpPath
assert tstConf.lastPath() == Path.home().absolute()
tmpStuff = tmpPath / "stuff"
tmpStuff = fncPath / "stuff"
tmpStuff.mkdir()
tmpConf.setLastPath(tmpStuff)
assert tmpConf.lastPath() == tmpStuff
tstConf.setLastPath(tmpStuff)
assert tstConf.lastPath() == tmpStuff
fileStuff = tmpStuff / "more_stuff.txt"
fileStuff.write_text("Stuff")
tmpConf.setLastPath(fileStuff)
assert tmpConf.lastPath() == tmpStuff
tstConf.setLastPath(fileStuff)
assert tstConf.lastPath() == tmpStuff
fileStuff.unlink()
tmpStuff.rmdir()
assert tmpConf.lastPath() == Path.home().absolute()
assert tstConf.lastPath() == Path.home().absolute()
# Recent Projects
assert isinstance(tmpConf.recentProjects, RecentProjects)
assert isinstance(tstConf.recentProjects, RecentProjects)
# END Test testBaseConfig_Methods
@pytest.mark.base
def testBaseConfig_SettersGetters(tmpConf):
def testBaseConfig_SettersGetters(fncPath):
"""Set various sizes and positions
"""
tstConf = Config()
tstConf.initConfig(confPath=fncPath, dataPath=fncPath)
# GUI Scaling
# ===========
tmpConf.guiScale = 1.0
assert tmpConf.pxInt(10) == 10
assert tmpConf.pxInt(13) == 13
assert tmpConf.rpxInt(10) == 10
assert tmpConf.rpxInt(13) == 13
tstConf.guiScale = 1.0
assert tstConf.pxInt(10) == 10
assert tstConf.pxInt(13) == 13
assert tstConf.rpxInt(10) == 10
assert tstConf.rpxInt(13) == 13
tmpConf.guiScale = 2.0
assert tmpConf.pxInt(10) == 20
assert tmpConf.pxInt(13) == 26
assert tmpConf.rpxInt(10) == 5
assert tmpConf.rpxInt(13) == 6
tstConf.guiScale = 2.0
assert tstConf.pxInt(10) == 20
assert tstConf.pxInt(13) == 26
assert tstConf.rpxInt(10) == 5
assert tstConf.rpxInt(13) == 6
# Setter + Getter Combos
# ======================
# Window Size
tmpConf.guiScale = 1.0
tmpConf.setMainWinSize(1205, 655)
assert tmpConf.mainWinSize == [1200, 650]
tstConf.guiScale = 1.0
tstConf.setMainWinSize(1205, 655)
assert tstConf.mainWinSize == [1200, 650]
tmpConf.guiScale = 2.0
tmpConf.setMainWinSize(70, 70)
assert tmpConf.mainWinSize == [70, 70]
assert tmpConf._mainWinSize == [35, 35]
tstConf.guiScale = 2.0
tstConf.setMainWinSize(70, 70)
assert tstConf.mainWinSize == [70, 70]
assert tstConf._mainWinSize == [35, 35]
tmpConf.guiScale = 1.0
tmpConf.setMainWinSize(70, 70)
assert tmpConf.mainWinSize == [70, 70]
assert tmpConf._mainWinSize == [70, 70]
tstConf.guiScale = 1.0
tstConf.setMainWinSize(70, 70)
assert tstConf.mainWinSize == [70, 70]
assert tstConf._mainWinSize == [70, 70]
tmpConf.setMainWinSize(1200, 650)
tstConf.setMainWinSize(1200, 650)
# Preferences Size
tmpConf.guiScale = 2.0
tmpConf.setPreferencesWinSize(70, 70)
assert tmpConf.preferencesWinSize == [70, 70]
assert tmpConf._prefsWinSize == [35, 35]
tstConf.guiScale = 2.0
tstConf.setPreferencesWinSize(70, 70)
assert tstConf.preferencesWinSize == [70, 70]
assert tstConf._prefsWinSize == [35, 35]
tmpConf.guiScale = 1.0
tmpConf.setPreferencesWinSize(70, 70)
assert tmpConf.preferencesWinSize == [70, 70]
assert tmpConf._prefsWinSize == [70, 70]
tstConf.guiScale = 1.0
tstConf.setPreferencesWinSize(70, 70)
assert tstConf.preferencesWinSize == [70, 70]
assert tstConf._prefsWinSize == [70, 70]
tmpConf.setPreferencesWinSize(700, 615)
tstConf.setPreferencesWinSize(700, 615)
# Project Settings Tree Columns
tmpConf.guiScale = 2.0
tmpConf.setProjLoadColWidths([10, 20, 30])
assert tmpConf.projLoadColWidths == [10, 20, 30]
assert tmpConf._projLoadCols == [5, 10, 15]
tstConf.guiScale = 2.0
tstConf.setProjLoadColWidths([10, 20, 30])
assert tstConf.projLoadColWidths == [10, 20, 30]
assert tstConf._projLoadCols == [5, 10, 15]
tmpConf.guiScale = 1.0
tmpConf.setProjLoadColWidths([10, 20, 30])
assert tmpConf.projLoadColWidths == [10, 20, 30]
assert tmpConf._projLoadCols == [10, 20, 30]
tstConf.guiScale = 1.0
tstConf.setProjLoadColWidths([10, 20, 30])
assert tstConf.projLoadColWidths == [10, 20, 30]
assert tstConf._projLoadCols == [10, 20, 30]
tmpConf.setProjLoadColWidths([200, 60, 140])
tstConf.setProjLoadColWidths([200, 60, 140])
# Main Pane Splitter
tmpConf.guiScale = 2.0
tmpConf.setMainPanePos([200, 700])
assert tmpConf.mainPanePos == [200, 700]
assert tmpConf._mainPanePos == [100, 350]
tstConf.guiScale = 2.0
tstConf.setMainPanePos([200, 700])
assert tstConf.mainPanePos == [200, 700]
assert tstConf._mainPanePos == [100, 350]
tmpConf.guiScale = 1.0
tmpConf.setMainPanePos([200, 700])
assert tmpConf.mainPanePos == [200, 700]
assert tmpConf._mainPanePos == [200, 700]
tstConf.guiScale = 1.0
tstConf.setMainPanePos([200, 700])
assert tstConf.mainPanePos == [200, 700]
assert tstConf._mainPanePos == [200, 700]
tmpConf.setMainPanePos([300, 800])
tstConf.setMainPanePos([300, 800])
# View Pane Splitter
tmpConf.guiScale = 2.0
tmpConf.setViewPanePos([400, 250])
assert tmpConf.viewPanePos == [400, 250]
assert tmpConf._viewPanePos == [200, 125]
tstConf.guiScale = 2.0
tstConf.setViewPanePos([400, 250])
assert tstConf.viewPanePos == [400, 250]
assert tstConf._viewPanePos == [200, 125]
tmpConf.guiScale = 1.0
tmpConf.setViewPanePos([400, 250])
assert tmpConf.viewPanePos == [400, 250]
assert tmpConf._viewPanePos == [400, 250]
tstConf.guiScale = 1.0
tstConf.setViewPanePos([400, 250])
assert tstConf.viewPanePos == [400, 250]
assert tstConf._viewPanePos == [400, 250]
tmpConf.setViewPanePos([500, 150])
tstConf.setViewPanePos([500, 150])
# Outline Pane Splitter
tmpConf.guiScale = 2.0
tmpConf.setOutlinePanePos([400, 250])
assert tmpConf.outlinePanePos == [400, 250]
assert tmpConf._outlnPanePos == [200, 125]
tstConf.guiScale = 2.0
tstConf.setOutlinePanePos([400, 250])
assert tstConf.outlinePanePos == [400, 250]
assert tstConf._outlnPanePos == [200, 125]
tmpConf.guiScale = 1.0
tmpConf.setOutlinePanePos([400, 250])
assert tmpConf.outlinePanePos == [400, 250]
assert tmpConf._outlnPanePos == [400, 250]
tstConf.guiScale = 1.0
tstConf.setOutlinePanePos([400, 250])
assert tstConf.outlinePanePos == [400, 250]
assert tstConf._outlnPanePos == [400, 250]
tmpConf.setOutlinePanePos([500, 150])
tstConf.setOutlinePanePos([500, 150])
# Getters Only
# ============
tmpConf.guiScale = 1.0
assert tmpConf.getTextWidth(False) == 700
assert tmpConf.getTextWidth(True) == 800
assert tmpConf.getTextMargin() == 40
assert tmpConf.getTabWidth() == 40
tstConf.guiScale = 1.0
assert tstConf.getTextWidth(False) == 700
assert tstConf.getTextWidth(True) == 800
assert tstConf.getTextMargin() == 40
assert tstConf.getTabWidth() == 40
tmpConf.guiScale = 2.0
assert tmpConf.getTextWidth(False) == 1400
assert tmpConf.getTextWidth(True) == 1600
assert tmpConf.getTextMargin() == 80
assert tmpConf.getTabWidth() == 80
tstConf.guiScale = 2.0
assert tstConf.getTextWidth(False) == 1400
assert tstConf.getTextWidth(True) == 1600
assert tstConf.getTextMargin() == 80
assert tstConf.getTabWidth() == 80
# END Test testBaseConfig_SettersGetters
@pytest.mark.base
def testBaseConfig_Internal(monkeypatch, tmpConf):
def testBaseConfig_Internal(monkeypatch, fncPath):
"""Check internal functions.
"""
tstConf = Config()
tstConf.initConfig(confPath=fncPath, dataPath=fncPath)
# Function _packList
assert tmpConf._packList(["A", 1, 2.0, None, False]) == "A, 1, 2.0, None, False"
assert tstConf._packList(["A", 1, 2.0, None, False]) == "A, 1, 2.0, None, False"
# Function _checkNone
assert tmpConf._checkNone(None) is None
assert tmpConf._checkNone("None") is None
assert tmpConf._checkNone("none") is None
assert tmpConf._checkNone("NONE") is None
assert tmpConf._checkNone("NoNe") is None
assert tmpConf._checkNone(123456) == 123456
assert tstConf._checkNone(None) is None
assert tstConf._checkNone("None") is None
assert tstConf._checkNone("none") is None
assert tstConf._checkNone("NONE") is None
assert tstConf._checkNone("NoNe") is None
assert tstConf._checkNone(123456) == 123456
# Function _checkOptionalPackages
# (Assumes enchant package exists and is importable)
tmpConf._checkOptionalPackages()
assert tmpConf.hasEnchant is True
tstConf._checkOptionalPackages()
assert tstConf.hasEnchant is True
with monkeypatch.context() as mp:
mp.setitem(sys.modules, "enchant", None)
tmpConf._checkOptionalPackages()
assert tmpConf.hasEnchant is False
tstConf._checkOptionalPackages()
assert tstConf.hasEnchant is False
# END Test testBaseConfig_Internal
@pytest.mark.base
def testBaseConfig_RecentCache(monkeypatch, fncConf, fncPath):
def testBaseConfig_RecentCache(monkeypatch, tstPaths):
"""Test recent cache file.
"""
cacheFile = fncPath / nwFiles.RECENT_FILE
recent = RecentProjects(fncConf)
cacheFile = tstPaths.cnfDir / nwFiles.RECENT_FILE
recent = RecentProjects(CONFIG)
# Load when there is no file should pass, but load nothing
assert not cacheFile.exists()
@@ -394,8 +404,8 @@ def testBaseConfig_RecentCache(monkeypatch, fncConf, fncPath):
assert recent.listEntries() == []
# Add a couple of values
pathOne = fncPath / "projPathOne" / nwFiles.PROJ_FILE
pathTwo = fncPath / "projPathTwo" / nwFiles.PROJ_FILE
pathOne = tstPaths.cnfDir / "projPathOne" / nwFiles.PROJ_FILE
pathTwo = tstPaths.cnfDir / "projPathTwo" / nwFiles.PROJ_FILE
recent.update(pathOne, "Proj One", 100, 1600002000)
recent.update(pathTwo, "Proj Two", 200, 1600005600)
+37 -36
View File
@@ -22,46 +22,47 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
import sys
import pytest
import logging
import novelwriter
from mock import MockGuiMain
from novelwriter import CONFIG, main, logger
@pytest.mark.base
def testBaseInit_Launch(caplog, monkeypatch, tmpPath):
def testBaseInit_Launch(caplog, monkeypatch, fncPath):
"""Check launching the main GUI.
"""
monkeypatch.setattr("novelwriter.guimain.GuiMain", MockGuiMain)
# TestMode Launch
nwGUI = novelwriter.main(["--testmode", f"--config={tmpPath}", f"--data={tmpPath}"])
nwGUI = main(["--testmode", f"--config={fncPath}", f"--data={fncPath}"])
assert isinstance(nwGUI, MockGuiMain)
# Darwin Launch
caplog.clear()
osDarwin = novelwriter.CONFIG.osDarwin
novelwriter.CONFIG.osDarwin = True
osDarwin = CONFIG.osDarwin
CONFIG.osDarwin = True
with monkeypatch.context() as mp:
mp.setitem(sys.modules, "Foundation", None)
nwGUI = novelwriter.main(["--testmode", f"--config={tmpPath}", f"--data={tmpPath}"])
nwGUI = main(["--testmode", f"--config={fncPath}", f"--data={fncPath}"])
assert isinstance(nwGUI, MockGuiMain)
assert "Failed" in caplog.text
novelwriter.CONFIG.osDarwin = osDarwin
CONFIG.osDarwin = osDarwin
# Windows Launch
caplog.clear()
osWindows = novelwriter.CONFIG.osWindows
novelwriter.CONFIG.osWindows = True
osWindows = CONFIG.osWindows
CONFIG.osWindows = True
with monkeypatch.context() as mp:
mp.setitem(sys.modules, "ctypes", None)
nwGUI = novelwriter.main(["--testmode", f"--config={tmpPath}", f"--data={tmpPath}"])
nwGUI = main(["--testmode", f"--config={fncPath}", f"--data={fncPath}"])
assert isinstance(nwGUI, MockGuiMain)
if not sys.platform.startswith("darwin"):
# For some reason, the test doesn't work on macOS
assert "Failed" in caplog.text
novelwriter.CONFIG.osWindows = osWindows
CONFIG.osWindows = osWindows
# Normal Launch
monkeypatch.setattr("PyQt5.QtWidgets.QApplication.__init__", lambda *a: None)
@@ -71,72 +72,72 @@ def testBaseInit_Launch(caplog, monkeypatch, tmpPath):
monkeypatch.setattr("PyQt5.QtWidgets.QApplication.setOrganizationDomain", lambda *a: None)
monkeypatch.setattr("PyQt5.QtWidgets.QApplication.exec_", lambda *a: 0)
with pytest.raises(SystemExit) as ex:
novelwriter.main([f"--config={tmpPath}", f"--data={tmpPath}"])
main([f"--config={fncPath}", f"--data={fncPath}"])
assert ex.value.code == 0
# END Test testBaseInit_Launch
@pytest.mark.base
def testBaseInit_Options(monkeypatch, tmpPath):
def testBaseInit_Options(monkeypatch, fncPath):
"""Test command line options for logging level.
"""
monkeypatch.setattr("novelwriter.guimain.GuiMain", MockGuiMain)
monkeypatch.setattr(sys, "argv", [
"novelWriter.py", "--testmode", f"--config={tmpPath}", f"--data={tmpPath}"
"novelWriter.py", "--testmode", f"--config={fncPath}", f"--data={fncPath}"
])
# Defaults w/None Args
nwGUI = novelwriter.main()
assert novelwriter.logger.getEffectiveLevel() == logging.WARNING
nwGUI = main()
assert logger.getEffectiveLevel() == logging.WARNING
assert nwGUI.closeMain() == "closeMain"
# Defaults
nwGUI = novelwriter.main(
["--testmode", f"--config={tmpPath}", f"--data={tmpPath}", "--style=Fusion"]
nwGUI = main(
["--testmode", f"--config={fncPath}", f"--data={fncPath}", "--style=Fusion"]
)
assert novelwriter.logger.getEffectiveLevel() == logging.WARNING
assert logger.getEffectiveLevel() == logging.WARNING
assert nwGUI.closeMain() == "closeMain"
# Log Levels
nwGUI = novelwriter.main(
["--testmode", "--info", f"--config={tmpPath}", f"--data={tmpPath}"]
nwGUI = main(
["--testmode", "--info", f"--config={fncPath}", f"--data={fncPath}"]
)
assert novelwriter.logger.getEffectiveLevel() == logging.INFO
assert logger.getEffectiveLevel() == logging.INFO
assert nwGUI.closeMain() == "closeMain"
nwGUI = novelwriter.main(
["--testmode", "--debug", f"--config={tmpPath}", f"--data={tmpPath}"]
nwGUI = main(
["--testmode", "--debug", f"--config={fncPath}", f"--data={fncPath}"]
)
assert novelwriter.logger.getEffectiveLevel() == logging.DEBUG
assert logger.getEffectiveLevel() == logging.DEBUG
assert nwGUI.closeMain() == "closeMain"
# Help and Version
with pytest.raises(SystemExit) as ex:
nwGUI = novelwriter.main(
["--testmode", "--help", f"--config={tmpPath}", f"--data={tmpPath}"]
nwGUI = main(
["--testmode", "--help", f"--config={fncPath}", f"--data={fncPath}"]
)
assert nwGUI.closeMain() == "closeMain"
assert ex.value.code == 0
with pytest.raises(SystemExit) as ex:
nwGUI = novelwriter.main(
["--testmode", "--version", f"--config={tmpPath}", f"--data={tmpPath}"]
nwGUI = main(
["--testmode", "--version", f"--config={fncPath}", f"--data={fncPath}"]
)
assert nwGUI.closeMain() == "closeMain"
assert ex.value.code == 0
# Invalid options
with pytest.raises(SystemExit) as ex:
nwGUI = novelwriter.main(
["--testmode", "--invalid", f"--config={tmpPath}", f"--data={tmpPath}"]
nwGUI = main(
["--testmode", "--invalid", f"--config={fncPath}", f"--data={fncPath}"]
)
assert nwGUI.closeMain() == "closeMain"
assert ex.value.code == 2
# Project Path
nwGUI = novelwriter.main(
["--testmode", f"--config={tmpPath}", f"--data={tmpPath}", "sample/"]
nwGUI = main(
["--testmode", f"--config={fncPath}", f"--data={fncPath}", "sample/"]
)
assert nwGUI.closeMain() == "closeMain"
@@ -144,7 +145,7 @@ def testBaseInit_Options(monkeypatch, tmpPath):
@pytest.mark.base
def testBaseInit_Imports(caplog, monkeypatch, tmpPath):
def testBaseInit_Imports(caplog, monkeypatch, fncPath):
"""Check import error handling.
"""
monkeypatch.setattr("novelwriter.guimain.GuiMain", MockGuiMain)
@@ -159,8 +160,8 @@ def testBaseInit_Imports(caplog, monkeypatch, tmpPath):
monkeypatch.setattr("novelwriter.CONFIG.verPyQtValue", 0x050000)
with pytest.raises(SystemExit) as ex:
_ = novelwriter.main(
["--testmode", f"--config={tmpPath}", f"--data={tmpPath}"]
_ = main(
["--testmode", f"--config={fncPath}", f"--data={fncPath}"]
)
assert ex.value.code & 4 == 4 # Python version not satisfied
+5 -4
View File
@@ -28,6 +28,7 @@ from zipfile import ZipFile
from mock import causeOSError
from tools import C, buildTestProject, cmpFiles, XML_IGNORE
from novelwriter import CONFIG
from novelwriter.constants import nwItemClass
from novelwriter.core.project import NWProject
from novelwriter.core.coretools import DocMerger, DocSplitter, ProjectBuilder
@@ -371,7 +372,7 @@ def testCoreTools_NewCustomB(monkeypatch, fncPath, tstPaths, mockGUI, mockRnd):
@pytest.mark.core
def testCoreTools_NewSample(monkeypatch, fncPath, tmpConf, tmpPath, mockGUI):
def testCoreTools_NewSample(monkeypatch, fncPath, tstPaths, mockGUI):
"""Check that we can create a new project can be created from the
provided sample project via a zip file.
"""
@@ -391,10 +392,10 @@ def testCoreTools_NewSample(monkeypatch, fncPath, tmpConf, tmpPath, mockGUI):
assert projBuild.buildProject({"popSample": True}) is False
# Force the lookup path for assets to our temp folder
srcSample = tmpConf._appRoot / "sample"
dstSample = tmpPath / "sample.zip"
srcSample = CONFIG._appRoot / "sample"
dstSample = tstPaths.tmpDir / "sample.zip"
monkeypatch.setattr(
"novelwriter.config.Config.assetPath", lambda *a: tmpPath / "sample.zip"
"novelwriter.config.Config.assetPath", lambda *a: tstPaths.tmpDir / "sample.zip"
)
# Cannot extract when the zip does not exist
+9 -13
View File
@@ -29,6 +29,7 @@ from zipfile import ZipFile
from mock import causeOSError
from tools import C, cmpFiles, writeFile, buildTestProject, XML_IGNORE
from novelwriter import CONFIG
from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
from novelwriter.common import formatTimeStamp
from novelwriter.constants import nwFiles
@@ -704,7 +705,7 @@ def testCoreProject_OrphanedFiles(mockGUI, prjLipsum):
@pytest.mark.core
def testCoreProject_Backup(monkeypatch, mockGUI, fncPath, tmpPath):
def testCoreProject_Backup(monkeypatch, mockGUI, fncPath, tstPaths):
"""Test the automated backup feature of the project class. The test
creates a backup of the Minimal test project, and then unzips the
backupd file and checks that the project XML file is identical to
@@ -720,23 +721,18 @@ def testCoreProject_Backup(monkeypatch, mockGUI, fncPath, tmpPath):
# Invalid Settings
# ================
# No project
mockGUI.hasProject = False
assert theProject.backupProject(doNotify=False) is False
mockGUI.hasProject = True
# Invalid path
theProject.mainConf._backupPath = None
CONFIG._backupPath = None
assert theProject.backupProject(doNotify=False) is False
# Missing project name
theProject.mainConf._backupPath = tmpPath
CONFIG._backupPath = tstPaths.tmpDir
theProject.data.setName("")
assert theProject.backupProject(doNotify=False) is False
# Valid Settings
# ==============
theProject.mainConf._backupPath = tmpPath
CONFIG._backupPath = tstPaths.tmpDir
theProject.data.setName("Test Minimal")
# Can't make folder
@@ -752,7 +748,7 @@ def testCoreProject_Backup(monkeypatch, mockGUI, fncPath, tmpPath):
# Test correct settings
assert theProject.backupProject(doNotify=True) is True
theFiles = list((tmpPath / "Test Minimal").iterdir())
theFiles = list((tstPaths.tmpDir / "Test Minimal").iterdir())
assert len(theFiles) == 1
theZip = theFiles[0].name
@@ -760,13 +756,13 @@ def testCoreProject_Backup(monkeypatch, mockGUI, fncPath, tmpPath):
assert theZip[-4:] == ".zip"
# Extract the archive
with ZipFile(tmpPath / "Test Minimal" / theZip, mode="r") as inZip:
inZip.extractall(tmpPath / "extract")
with ZipFile(tstPaths.tmpDir / "Test Minimal" / theZip, mode="r") as inZip:
inZip.extractall(tstPaths.tmpDir / "extract")
# Check that the main project file was restored
assert cmpFiles(
fncPath / "nwProject.nwx",
tmpPath / "extract" / "nwProject.nwx"
tstPaths.tmpDir / "extract" / "nwProject.nwx"
)
# END Test testCoreProject_Backup
+2 -2
View File
@@ -40,8 +40,8 @@ class MockProject:
@pytest.fixture(scope="function", autouse=True)
def mockVersion(monkeypatch):
monkeypatch.setattr("novelwriter.__version__", "2.0-rc1")
monkeypatch.setattr("novelwriter.__hexversion__", "0x020000c1")
monkeypatch.setattr("novelwriter.core.projectxml.__version__", "2.0-rc1")
monkeypatch.setattr("novelwriter.core.projectxml.__hexversion__", "0x020000c1")
return
+6 -5
View File
@@ -25,6 +25,7 @@ import pytest
from mock import causeOSError
from tools import C, buildTestProject, writeFile
from novelwriter import CONFIG
from novelwriter.constants import nwFiles
from novelwriter.core.project import NWProject
from novelwriter.core.storage import NWStorage
@@ -148,9 +149,9 @@ def testCoreStorage_LockFile(monkeypatch, fncPath):
# Successful read
assert storage.readLockFile() == [
storage.mainConf.hostName,
storage.mainConf.osType,
storage.mainConf.kernelVer,
CONFIG.hostName,
CONFIG.osType,
CONFIG.kernelVer,
"1000",
]
@@ -299,10 +300,10 @@ def testCoreStorage_PrepareStorage(monkeypatch, fncPath):
@pytest.mark.core
def testCoreStorage_ZipIt(monkeypatch, mockGUI, fncPath, tmpPath, mockRnd):
def testCoreStorage_ZipIt(monkeypatch, mockGUI, fncPath, tstPaths, mockRnd):
"""Test making a zip archive of a project.
"""
zipFile = tmpPath / "project.zip"
zipFile = tstPaths.tmpDir / "project.zip"
theProject = NWProject(mockGUI)
storage = theProject.storage
+5 -5
View File
@@ -437,7 +437,7 @@ def testCoreTree_Reorder(caplog, mockGUI, mockItems):
@pytest.mark.core
def testCoreTree_ToCFile(monkeypatch, mockGUI, mockItems, tmpPath):
def testCoreTree_ToCFile(monkeypatch, tstPaths, mockGUI, mockItems):
"""Test writing the ToC.txt file.
"""
theProject = NWProject(mockGUI)
@@ -463,20 +463,20 @@ def testCoreTree_ToCFile(monkeypatch, mockGUI, mockItems, tmpPath):
theProject._storage._runtimePath = None
assert theTree.writeToCFile() is False
theProject._storage._runtimePath = tmpPath
theProject._storage._runtimePath = tstPaths.tmpDir
with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError)
assert theTree.writeToCFile() is False
theProject._storage._runtimePath = tmpPath
(tmpPath / "content").mkdir()
theProject._storage._runtimePath = tstPaths.tmpDir
(tstPaths.tmpDir / "content").mkdir()
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(tmpPath / nwFiles.TOC_TXT) == (
assert readFile(tstPaths.tmpDir / nwFiles.TOC_TXT) == (
"\n"
"Table of Contents\n"
"=================\n"
+4 -7
View File
@@ -30,6 +30,7 @@ from PyQt5.QtWidgets import (
QDialogButtonBox, QDialog, QAction, QFileDialog, QFontDialog
)
from novelwriter import CONFIG
from novelwriter.dialogs.quotes import GuiQuoteSelect
from novelwriter.dialogs.preferences import GuiPreferences
@@ -37,12 +38,9 @@ KEY_DELAY = 1
@pytest.mark.gui
def testDlgPreferences_Main(qtbot, monkeypatch, nwGUI, fncPath, tstPaths):
def testDlgPreferences_Main(qtbot, monkeypatch, nwGUI, tstPaths):
"""Test the load project wizard.
"""
theConf = nwGUI.mainConf
assert theConf._confPath == fncPath
monkeypatch.setattr(GuiPreferences, "exec_", lambda *a: None)
monkeypatch.setattr(GuiPreferences, "result", lambda *a: QDialog.Accepted)
monkeypatch.setattr(nwGUI.docEditor.spEnchant, "listDictionaries", lambda: [("en", "none")])
@@ -58,7 +56,6 @@ def testDlgPreferences_Main(qtbot, monkeypatch, nwGUI, fncPath, tstPaths):
nwPrefs = getGuiItem("GuiPreferences")
assert isinstance(nwPrefs, GuiPreferences)
nwPrefs.show()
assert nwPrefs.mainConf._confPath == fncPath
assert nwPrefs.updateTheme is False
assert nwPrefs.updateSyntax is False
@@ -215,8 +212,8 @@ def testDlgPreferences_Main(qtbot, monkeypatch, nwGUI, fncPath, tstPaths):
qtbot.mouseClick(nwPrefs.buttonBox.button(QDialogButtonBox.Ok), Qt.LeftButton)
nwPrefs._doClose()
assert nwGUI.mainConf.saveConfig()
projFile = fncPath / "novelwriter.conf"
assert CONFIG.saveConfig()
projFile = tstPaths.cnfDir / "novelwriter.conf"
testFile = tstPaths.outDir / "guiPreferences_novelwriter.conf"
compFile = tstPaths.refDir / "guiPreferences_novelwriter.conf"
copyfile(projFile, testFile)
+5 -4
View File
@@ -21,13 +21,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
import pytest
from novelwriter.enum import nwItemType
from tools import C, getGuiItem, buildTestProject
from PyQt5.QtGui import QColor
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QDialog, QAction, QColorDialog
from novelwriter import CONFIG
from novelwriter.enum import nwItemType
from novelwriter.dialogs.editlabel import GuiEditLabel
from novelwriter.dialogs.projsettings import GuiProjectSettings
@@ -91,7 +92,7 @@ def testDlgProjSettings_Main(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockR
# Create new project
buildTestProject(nwGUI, projPath)
mockRnd.reset()
nwGUI.mainConf.backupPath = fncPath
CONFIG.setBackupPath(fncPath)
# Set some values
theProject = nwGUI.theProject
@@ -156,7 +157,7 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncPath, projPat
# Create new project
mockRnd.reset()
buildTestProject(nwGUI, projPath)
nwGUI.mainConf.backupPath = fncPath
CONFIG.setBackupPath(fncPath)
# Set some values
theProject = nwGUI.theProject
@@ -357,7 +358,7 @@ def testDlgProjSettings_Replace(qtbot, monkeypatch, nwGUI, fncPath, projPath, mo
# Create new project
mockRnd.reset()
buildTestProject(nwGUI, projPath)
nwGUI.mainConf.backupPath = fncPath
CONFIG.setBackupPath(fncPath)
# Set some values
theProject = nwGUI.theProject
+10 -9
View File
@@ -28,6 +28,7 @@ from PyQt5.QtCore import Qt
from PyQt5.QtGui import QTextBlock, QTextCursor, QTextOption
from PyQt5.QtWidgets import QAction, qApp
from novelwriter import CONFIG
from novelwriter.enum import nwDocAction, nwDocInsert, nwItemLayout
from novelwriter.constants import nwKeyWords, nwUnicode
from novelwriter.core.index import countWords
@@ -55,18 +56,18 @@ def testGuiEditor_Init(qtbot, nwGUI, projPath, ipsumText, mockRnd):
assert nwGUI.docEditor._typPadChar == nwUnicode.U_NBSP
# Check that editor handles settings
nwGUI.mainConf.textFont = None
nwGUI.mainConf.doJustify = True
nwGUI.mainConf.showTabsNSpaces = True
nwGUI.mainConf.showLineEndings = True
nwGUI.mainConf.hideVScroll = True
nwGUI.mainConf.hideHScroll = True
nwGUI.mainConf.fmtPadThin = True
CONFIG.textFont = None
CONFIG.doJustify = True
CONFIG.showTabsNSpaces = True
CONFIG.showLineEndings = True
CONFIG.hideVScroll = True
CONFIG.hideHScroll = True
CONFIG.fmtPadThin = True
assert nwGUI.docEditor.initEditor()
qDoc = nwGUI.docEditor.document()
assert nwGUI.mainConf.textFont == qDoc.defaultFont().family()
assert CONFIG.textFont == qDoc.defaultFont().family()
assert qDoc.defaultTextOption().alignment() == Qt.AlignJustify
assert qDoc.defaultTextOption().flags() & QTextOption.ShowTabsAndSpaces
assert qDoc.defaultTextOption().flags() & QTextOption.ShowLineAndParagraphSeparators
@@ -114,7 +115,7 @@ def testGuiEditor_LoadText(qtbot, monkeypatch, caplog, nwGUI, projPath, ipsumTex
assert "The document you are trying to open is too big." in caplog.text
# Big doc handling
nwGUI.mainConf.bigDocLimit = 50
CONFIG.bigDocLimit = 50
assert nwGUI.docEditor.loadText(C.hSceneDoc) is True
assert nwGUI.docEditor._bigDoc is True
+5 -3
View File
@@ -21,11 +21,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
import pytest
from mock import causeException
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtGui import QTextCursor
from PyQt5.QtWidgets import qApp, QAction
from mock import causeException
from novelwriter import CONFIG
from novelwriter.enum import nwDocAction
from novelwriter.core.tohtml import ToHtml
@@ -134,10 +136,10 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, nwLipsum):
assert nwGUI.docViewer.docHeader.theTitle.text() == "Characters Test Title"
# Ttile without full path
nwGUI.mainConf.showFullPath = False
CONFIG.showFullPath = False
nwGUI.docViewer.updateDocInfo("4c4f28287af27")
assert nwGUI.docViewer.docHeader.theTitle.text() == "Test Title"
nwGUI.mainConf.showFullPath = True
CONFIG.showFullPath = True
# Document footer show/hide references
viewState = nwGUI.viewMeta.isVisible()
+9 -8
View File
@@ -30,6 +30,7 @@ from tools import (
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QDialog, QMessageBox, QInputDialog
from novelwriter import CONFIG
from novelwriter.enum import nwItemType, nwView, nwWidget
from novelwriter.constants import nwFiles
from novelwriter.gui.outline import GuiOutlineView
@@ -75,7 +76,7 @@ def testGuiMain_Launch(qtbot, monkeypatch, nwGUI, prjLipsum):
"""
monkeypatch.setattr(GuiProjectLoad, "exec_", lambda *a: None)
monkeypatch.setattr(GuiProjectLoad, "result", lambda *a: QDialog.Accepted)
nwGUI.mainConf.lastNotes = "0x0"
CONFIG.lastNotes = "0x0"
# Open Lipsum project
nwGUI.postLaunchTasks(prjLipsum)
@@ -244,10 +245,10 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd):
assert nwGUI.mainMenu._toggleSpellCheck()
# Change some settings
nwGUI.mainConf.hideHScroll = True
nwGUI.mainConf.hideVScroll = True
nwGUI.mainConf.autoScrollPos = 80
nwGUI.mainConf.autoScroll = True
CONFIG.hideHScroll = True
CONFIG.hideVScroll = True
CONFIG.autoScrollPos = 80
CONFIG.autoScroll = True
# Add a Character File
nwGUI.switchFocus(nwWidget.TREE)
@@ -589,11 +590,11 @@ def testGuiMain_FocusFullMode(qtbot, nwGUI, projPath, mockRnd):
# Full Screen Mode
# ================
assert nwGUI.mainConf.isFullScreen is False
assert CONFIG.isFullScreen is False
nwGUI.toggleFullScreenMode()
assert nwGUI.mainConf.isFullScreen is True
assert CONFIG.isFullScreen is True
nwGUI.toggleFullScreenMode()
assert nwGUI.mainConf.isFullScreen is False
assert CONFIG.isFullScreen is False
# qtbot.stop()
+7 -12
View File
@@ -20,20 +20,20 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import sys
import novelwriter
import pytest
from PyQt5.QtWidgets import qApp, QMessageBox
LANG_DATA = novelwriter.CONFIG.listLanguages(novelwriter.CONFIG.LANG_NW)
from novelwriter import CONFIG, main
LANG_DATA = CONFIG.listLanguages(CONFIG.LANG_NW)
@pytest.mark.gui
@pytest.mark.skipif(not sys.platform.startswith("linux"), reason="Linux Only")
@pytest.mark.skipif(not LANG_DATA, reason="No i18n Data")
@pytest.mark.parametrize("language", [a for a, b in LANG_DATA])
def testI18n_Localisation(qtbot, monkeypatch, language, fncPath, fncConf):
def testI18n_Localisation(qtbot, monkeypatch, language, fncPath):
"""test loading the gui with a specific language.
"""
monkeypatch.setattr(QMessageBox, "warning", lambda *a: QMessageBox.Ok)
@@ -42,18 +42,13 @@ def testI18n_Localisation(qtbot, monkeypatch, language, fncPath, fncConf):
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
# Set the test langauge
monkeypatch.setattr("novelwriter.CONFIG", fncConf)
fncConf.guiLocale = language
fncConf.initLocalisation(qApp)
CONFIG.guiLocale = language
CONFIG.initLocalisation(qApp)
nwGUI = novelwriter.main(["--testmode", f"--config={fncPath}", f"--data={fncPath}"])
nwGUI = main(["--testmode", f"--config={fncPath}", f"--data={fncPath}"])
qtbot.addWidget(nwGUI)
nwGUI.show()
qtbot.wait(20)
nwGUI.closeMain()
# Reset the app language
fncConf.guiLocale = "en_GB"
fncConf.initLocalisation(qApp)
# END Test testI18n_Localisation
+5 -4
View File
@@ -27,6 +27,7 @@ from PyQt5.QtWidgets import QAction, QFileDialog, QMessageBox
from tools import C, writeFile, buildTestProject
from novelwriter import CONFIG
from novelwriter.enum import nwDocAction, nwDocInsert
from novelwriter.constants import nwKeyWords, nwUnicode
from novelwriter.gui.doceditor import GuiDocEditor
@@ -461,19 +462,19 @@ def testGuiMenu_Insert(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd):
nwGUI.docEditor.clear()
nwGUI.mainMenu.aInsQuoteLS.activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtSQuoteOpen
assert nwGUI.docEditor.getText() == CONFIG.fmtSQuoteOpen
nwGUI.docEditor.clear()
nwGUI.mainMenu.aInsQuoteRS.activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtSQuoteClose
assert nwGUI.docEditor.getText() == CONFIG.fmtSQuoteClose
nwGUI.docEditor.clear()
nwGUI.mainMenu.aInsQuoteLD.activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtDQuoteOpen
assert nwGUI.docEditor.getText() == CONFIG.fmtDQuoteOpen
nwGUI.docEditor.clear()
nwGUI.mainMenu.aInsQuoteRD.activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtDQuoteClose
assert nwGUI.docEditor.getText() == CONFIG.fmtDQuoteClose
nwGUI.docEditor.clear()
nwGUI.mainMenu.aInsMSApos.activate(QAction.Trigger)
+5 -4
View File
@@ -29,6 +29,7 @@ from PyQt5.QtGui import QFocusEvent
from PyQt5.QtCore import Qt, QEvent
from PyQt5.QtWidgets import QInputDialog, QToolTip
from novelwriter import CONFIG
from novelwriter.enum import nwWidget, nwItemType
from novelwriter.gui.noveltree import NovelTreeColumn
from novelwriter.dialogs.editlabel import GuiEditLabel
@@ -67,14 +68,14 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
# Show/Hide Scrollbars
# ====================
nwGUI.mainConf.hideVScroll = True
nwGUI.mainConf.hideHScroll = True
CONFIG.hideVScroll = True
CONFIG.hideHScroll = True
novelView.initSettings()
assert not novelTree.verticalScrollBar().isVisible()
assert not novelTree.horizontalScrollBar().isVisible()
nwGUI.mainConf.hideVScroll = False
nwGUI.mainConf.hideHScroll = False
CONFIG.hideVScroll = False
CONFIG.hideHScroll = False
novelView.initSettings()
assert novelTree.verticalScrollBar().isEnabled()
assert novelTree.horizontalScrollBar().isEnabled()
+5 -4
View File
@@ -28,6 +28,7 @@ from tools import buildTestProject, writeFile
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QAction
from novelwriter import CONFIG
from novelwriter.enum import nwItemClass, nwOutline, nwView
@@ -47,16 +48,16 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, projPath):
outlineMenu = outlineView.outlineBar.mColumns
# Toggle scrollbars
nwGUI.mainConf.hideVScroll = True
nwGUI.mainConf.hideHScroll = True
CONFIG.hideVScroll = True
CONFIG.hideHScroll = True
outlineView.initSettings()
assert outlineTree.verticalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
assert outlineTree.horizontalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
assert outlineData.verticalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
assert outlineData.horizontalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
nwGUI.mainConf.hideVScroll = False
nwGUI.mainConf.hideHScroll = False
CONFIG.hideVScroll = False
CONFIG.hideHScroll = False
outlineView.initSettings()
assert outlineTree.verticalScrollBarPolicy() == Qt.ScrollBarAsNeeded
assert outlineTree.horizontalScrollBarPolicy() == Qt.ScrollBarAsNeeded
+5 -4
View File
@@ -27,6 +27,7 @@ from tools import C, buildTestProject
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMessageBox, QMenu, QTreeWidgetItem, QDialog
from novelwriter import CONFIG
from novelwriter.enum import nwItemLayout, nwItemType, nwItemClass
from novelwriter.gui.projtree import GuiProjectTree
from novelwriter.dialogs.docmerge import GuiDocMerge
@@ -862,14 +863,14 @@ def testGuiProjTree_Other(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
# ====================
# Test that the scrollbar setting works
nwGUI.mainConf.hideVScroll = True
nwGUI.mainConf.hideHScroll = True
CONFIG.hideVScroll = True
CONFIG.hideHScroll = True
projView.initSettings()
assert projTree.verticalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
assert projTree.horizontalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
nwGUI.mainConf.hideVScroll = False
nwGUI.mainConf.hideHScroll = False
CONFIG.hideVScroll = False
CONFIG.hideHScroll = False
projView.initSettings()
assert projTree.verticalScrollBarPolicy() == Qt.ScrollBarAsNeeded
assert projTree.horizontalScrollBarPolicy() == Qt.ScrollBarAsNeeded
+5 -4
View File
@@ -24,6 +24,7 @@ import pytest
from tools import C, buildTestProject
from novelwriter import CONFIG
from novelwriter.gui.statusbar import StatusLED
@@ -60,13 +61,13 @@ def testGuiStatusBar_Main(qtbot, nwGUI, projPath, mockRnd):
assert nwGUI.mainStatus.docIcon._theCol == nwGUI.mainStatus.docIcon._colGood
# Idle Status
nwGUI.mainStatus.mainConf.stopWhenIdle = False
CONFIG.stopWhenIdle = False
nwGUI.mainStatus.setUserIdle(True)
nwGUI.mainStatus.updateTime()
assert nwGUI.mainStatus.userIdle is False
assert nwGUI.mainStatus.timeText.text() == "00:00:00"
nwGUI.mainStatus.mainConf.stopWhenIdle = True
CONFIG.stopWhenIdle = True
nwGUI.mainStatus.setUserIdle(True)
nwGUI.mainStatus.updateTime(5)
assert nwGUI.mainStatus.userIdle is True
@@ -84,10 +85,10 @@ def testGuiStatusBar_Main(qtbot, nwGUI, projPath, mockRnd):
assert nwGUI.mainStatus.langText.text() == "American English"
# Project Stats
nwGUI.mainStatus.mainConf.incNotesWCount = False
CONFIG.incNotesWCount = False
nwGUI._updateStatusWordCount()
assert nwGUI.mainStatus.statsText.text() == "Words: 9 (+9)"
nwGUI.mainStatus.mainConf.incNotesWCount = True
CONFIG.incNotesWCount = True
nwGUI._updateStatusWordCount()
assert nwGUI.mainStatus.statsText.text() == "Words: 11 (+11)"
+26 -36
View File
@@ -19,7 +19,6 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import shutil
import pytest
from pathlib import Path
@@ -31,18 +30,17 @@ from tools import writeFile
from PyQt5.QtGui import QIcon, QPalette, QPixmap
from PyQt5.QtWidgets import QApplication
from novelwriter import CONFIG
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
from novelwriter.config import Config
from novelwriter.constants import nwLabels
from novelwriter.gui.theme import GuiIcons, GuiTheme
@pytest.mark.gui
def testGuiTheme_Main(qtbot, nwGUI, fncPath):
def testGuiTheme_Main(qtbot, nwGUI, tstPaths):
"""Test the theme class init.
"""
mainTheme: GuiTheme = nwGUI.mainTheme
mainConf: Config = nwGUI.mainConf
# Methods
# =======
@@ -55,35 +53,35 @@ def testGuiTheme_Main(qtbot, nwGUI, fncPath):
# ==========
# The defaults should be set
defaultFont = mainConf.guiFont
defaultSize = mainConf.guiFontSize
defaultFont = CONFIG.guiFont
defaultSize = CONFIG.guiFontSize
# CHange them to nonsense values
mainConf.guiFont = "notafont"
mainConf.guiFontSize = 99
CONFIG.guiFont = "notafont"
CONFIG.guiFontSize = 99
# Let the theme class set them back to default
mainTheme._setGuiFont()
assert mainConf.guiFont == defaultFont
assert mainConf.guiFontSize == defaultSize
assert CONFIG.guiFont == defaultFont
assert CONFIG.guiFontSize == defaultSize
# A second call should just restore the defaults again
mainTheme._setGuiFont()
assert mainConf.guiFont == defaultFont
assert mainConf.guiFontSize == defaultSize
assert CONFIG.guiFont == defaultFont
assert CONFIG.guiFontSize == defaultSize
# Scan for Themes
# ===============
assert mainTheme._listConf({}, Path("not_a_path")) is False
themeOne = fncPath / "themes" / "themeone.conf"
themeTwo = fncPath / "themes" / "themetwo.conf"
themeOne = tstPaths.cnfDir / "themes" / "themeone.conf"
themeTwo = tstPaths.cnfDir / "themes" / "themetwo.conf"
writeFile(themeOne, "# Stuff")
writeFile(themeTwo, "# Stuff")
result = {}
assert mainTheme._listConf(result, fncPath / "themes") is True
assert mainTheme._listConf(result, tstPaths.cnfDir / "themes") is True
assert result["themeone"] == themeOne
assert result["themetwo"] == themeTwo
@@ -123,18 +121,14 @@ def testGuiTheme_Main(qtbot, nwGUI, fncPath):
@pytest.mark.gui
def testGuiTheme_Theme(qtbot, monkeypatch, nwGUI, fncPath):
def testGuiTheme_Theme(qtbot, monkeypatch, nwGUI):
"""Test the theme part of the class.
"""
mainTheme: GuiTheme = nwGUI.mainTheme
mainConf: Config = nwGUI.mainConf
# List Themes
# ===========
shutil.copy(mainConf.assetPath("themes") / "default_dark.conf", fncPath / "themes")
shutil.copy(mainConf.assetPath("themes") / "default.conf", fncPath / "themes")
# Block the reading of the files
with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError)
@@ -149,14 +143,14 @@ def testGuiTheme_Theme(qtbot, monkeypatch, nwGUI, fncPath):
assert mainTheme.listThemes() == mainTheme._themeList
# Check handling of broken theme settings
mainConf.guiTheme = "not_a_theme"
CONFIG.guiTheme = "not_a_theme"
availThemes = mainTheme._availThemes
mainTheme._availThemes = {}
assert mainTheme.loadTheme() is False
mainTheme._availThemes = availThemes
# Check handling of unreadable file
mainConf.guiTheme = "default"
CONFIG.guiTheme = "default"
with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError)
assert mainTheme.loadTheme() is False
@@ -168,7 +162,7 @@ def testGuiTheme_Theme(qtbot, monkeypatch, nwGUI, fncPath):
mainTheme._guiPalette.color(QPalette.Window).setRgb(0, 0, 0, 0)
# Load the default theme
mainConf.guiTheme = "default"
CONFIG.guiTheme = "default"
assert mainTheme.loadTheme() is True
# This should load a standard palette
@@ -178,7 +172,7 @@ def testGuiTheme_Theme(qtbot, monkeypatch, nwGUI, fncPath):
# Load Default Dark Theme
# =======================
mainConf.guiTheme = "default_dark"
CONFIG.guiTheme = "default_dark"
assert mainTheme.loadTheme() is True
# Check a few values
@@ -193,18 +187,14 @@ def testGuiTheme_Theme(qtbot, monkeypatch, nwGUI, fncPath):
@pytest.mark.gui
def testGuiTheme_Syntax(qtbot, monkeypatch, nwGUI, fncPath):
def testGuiTheme_Syntax(qtbot, monkeypatch, nwGUI):
"""Test the syntax part of the class.
"""
mainTheme: GuiTheme = nwGUI.mainTheme
mainConf: Config = nwGUI.mainConf
# List Themes
# ===========
shutil.copy(mainConf.assetPath("syntax") / "default_dark.conf", fncPath / "syntax")
shutil.copy(mainConf.assetPath("syntax") / "default_light.conf", fncPath / "syntax")
# Block the reading of the files
with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError)
@@ -221,12 +211,12 @@ def testGuiTheme_Syntax(qtbot, monkeypatch, nwGUI, fncPath):
# Check handling of broken theme settings
availSyntax = mainTheme._availSyntax
mainTheme._availSyntax = {}
mainConf.guiSyntax = "not_a_syntax"
CONFIG.guiSyntax = "not_a_syntax"
assert mainTheme.loadSyntax() is False
mainTheme._availSyntax = availSyntax
# Check handling of unreadable file
mainConf.guiSyntax = "default_light"
CONFIG.guiSyntax = "default_light"
with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError)
assert mainTheme.loadSyntax() is False
@@ -235,7 +225,7 @@ def testGuiTheme_Syntax(qtbot, monkeypatch, nwGUI, fncPath):
# =========================
# Load the default syntax
mainConf.guiSyntax = "default_light"
CONFIG.guiSyntax = "default_light"
assert mainTheme.loadSyntax() is True
# Check some values
@@ -248,7 +238,7 @@ def testGuiTheme_Syntax(qtbot, monkeypatch, nwGUI, fncPath):
# =======================
# Load the default syntax
mainConf.guiSyntax = "default_dark"
CONFIG.guiSyntax = "default_dark"
assert mainTheme.loadSyntax() is True
# Check some values
@@ -263,7 +253,7 @@ def testGuiTheme_Syntax(qtbot, monkeypatch, nwGUI, fncPath):
@pytest.mark.gui
def testGuiTheme_Icons(qtbot, caplog, monkeypatch, nwGUI, fncPath):
def testGuiTheme_Icons(qtbot, caplog, monkeypatch, nwGUI, tstPaths):
"""Test the icon cache class.
"""
iconCache: GuiIcons = nwGUI.mainTheme.iconCache
@@ -280,7 +270,7 @@ def testGuiTheme_Icons(qtbot, caplog, monkeypatch, nwGUI, fncPath):
assert iconCache.loadTheme("typicons_dark") is False
# Load a broken theme file
iconsDir = fncPath / "icons"
iconsDir = tstPaths.cnfDir / "icons"
testIcons = iconsDir / "testicons"
testIcons.mkdir()
writeFile(testIcons / "icons.conf", (
@@ -293,7 +283,7 @@ def testGuiTheme_Icons(qtbot, caplog, monkeypatch, nwGUI, fncPath):
))
iconPath = iconCache._iconPath
iconCache._iconPath = fncPath / "icons"
iconCache._iconPath = tstPaths.cnfDir / "icons"
caplog.clear()
assert iconCache.loadTheme("testicons") is True
+3 -2
View File
@@ -28,6 +28,7 @@ from tools import ODT_IGNORE, cmpFiles, getGuiItem
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QAction, QFileDialog
from novelwriter import CONFIG
from novelwriter.tools.build import GuiBuildNovel
@@ -67,7 +68,7 @@ def testToolBuild_Main(qtbot, monkeypatch, nwGUI, prjLipsum, tstPaths):
assert not nwBuild._saveDocument(nwBuild.FMT_NWD)
# Default Settings
nwGUI.mainConf._lastPath = prjLipsum
CONFIG._lastPath = prjLipsum
qtbot.mouseClick(nwBuild.buildNovel, Qt.LeftButton)
assert nwBuild._saveDocument(nwBuild.FMT_NWD)
@@ -231,7 +232,7 @@ def testToolBuild_Main(qtbot, monkeypatch, nwGUI, prjLipsum, tstPaths):
assert (prjLipsum / "Lorem Ipsum.odt").is_file()
# Print to PDF
if not nwGUI.mainConf.osDarwin:
if not CONFIG.osDarwin:
assert nwBuild._saveDocument(nwBuild.FMT_PDF)
assert (prjLipsum / "Lorem Ipsum.pdf").is_file()
+7 -10
View File
@@ -33,7 +33,7 @@ from novelwriter.tools.writingstats import GuiWritingStats
@pytest.mark.gui
def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncPath, projPath):
def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
"""Test the full writing stats tool.
"""
# Create a project to work on
@@ -126,13 +126,10 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncPath, projPath):
assert sessLog.listBox.topLevelItem(7).text(sessLog.C_COUNT) == "{:n}".format(200)
assert sessLog._saveData(sessLog.FMT_CSV)
qtbot.wait(100)
assert sessLog._saveData(sessLog.FMT_JSON)
qtbot.wait(100)
# Check the exported files
jsonStats = fncPath / "sessionStats.json"
jsonStats = tstPaths.tmpDir / "sessionStats.json"
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.load(inFile)
@@ -171,7 +168,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncPath, projPath):
qtbot.mouseClick(sessLog.incNovel, Qt.LeftButton)
assert sessLog._saveData(sessLog.FMT_JSON)
jsonStats = fncPath / "sessionStats.json"
jsonStats = tstPaths.tmpDir / "sessionStats.json"
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.loads(inFile.read())
@@ -217,7 +214,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncPath, projPath):
qtbot.mouseClick(sessLog.incNotes, Qt.LeftButton)
assert sessLog._saveData(sessLog.FMT_JSON)
jsonStats = fncPath / "sessionStats.json"
jsonStats = tstPaths.tmpDir / "sessionStats.json"
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.load(inFile)
@@ -265,7 +262,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncPath, projPath):
# qtbot.stop()
jsonStats = fncPath / "sessionStats.json"
jsonStats = tstPaths.tmpDir / "sessionStats.json"
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.load(inFile)
@@ -295,7 +292,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncPath, projPath):
qtbot.mouseClick(sessLog.hideZeros, Qt.LeftButton)
assert sessLog._saveData(sessLog.FMT_JSON)
jsonStats = fncPath / "sessionStats.json"
jsonStats = tstPaths.tmpDir / "sessionStats.json"
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.load(inFile)
@@ -348,7 +345,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, fncPath, projPath):
qtbot.mouseClick(sessLog.groupByDay, Qt.LeftButton)
assert sessLog._saveData(sessLog.FMT_JSON)
jsonStats = fncPath / "sessionStats.json"
jsonStats = tstPaths.tmpDir / "sessionStats.json"
with open(jsonStats, mode="r", encoding="utf-8") as inFile:
jsonData = json.load(inFile)