Remove main app testmode flag

This commit is contained in:
Veronica Berglyd Olsen
2025-01-12 03:16:52 +01:00
parent 27a0a47aaa
commit a1d94d63a3
3 changed files with 114 additions and 105 deletions
+13 -16
View File
@@ -97,7 +97,6 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
"style=", "style=",
"config=", "config=",
"data=", "data=",
"testmode",
"meminfo" "meminfo"
] ]
@@ -127,7 +126,6 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
fmtFlags = 0b00 fmtFlags = 0b00
confPath = None confPath = None
dataPath = None dataPath = None
testMode = False
qtStyle = "Fusion" qtStyle = "Fusion"
cmdOpen = None cmdOpen = None
@@ -163,8 +161,6 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
confPath = inArg confPath = inArg
elif inOpt == "--data": elif inOpt == "--data":
dataPath = inArg dataPath = inArg
elif inOpt == "--testmode":
testMode = True
elif inOpt == "--meminfo": elif inOpt == "--meminfo":
CONFIG.memInfo = True CONFIG.memInfo = True
@@ -257,18 +253,8 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
from novelwriter.gui.theme import GuiTheme from novelwriter.gui.theme import GuiTheme
from novelwriter.guimain import GuiMain from novelwriter.guimain import GuiMain
if testMode: # Create App
# Only used for testing where the test framework creates the app app = _createApp(qtStyle)
CONFIG.loadConfig()
SHARED.initTheme(GuiTheme())
return GuiMain()
app = QApplication([CONFIG.appName, (f"-style={qtStyle}")])
app.setApplicationName(CONFIG.appName)
app.setApplicationVersion(__version__)
app.setOrganizationDomain(__domain__)
app.setOrganizationName(__domain__)
app.setDesktopFileName(CONFIG.appName)
# Connect the exception handler before making the main GUI # Connect the exception handler before making the main GUI
sys.excepthook = exceptionHandler sys.excepthook = exceptionHandler
@@ -283,3 +269,14 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
nwGUI.postLaunchTasks(cmdOpen) nwGUI.postLaunchTasks(cmdOpen)
sys.exit(app.exec()) sys.exit(app.exec())
def _createApp(style: str) -> QApplication:
"""Create the app."""
app = QApplication([CONFIG.appName, (f"-style={style}")])
app.setApplicationName(CONFIG.appName)
app.setApplicationVersion(__version__)
app.setOrganizationDomain(__domain__)
app.setOrganizationName(__domain__)
app.setDesktopFileName(CONFIG.appName)
return app
+93 -89
View File
@@ -23,147 +23,153 @@ from __future__ import annotations
import logging import logging
import sys import sys
from unittest.mock import Mock
import pytest import pytest
from novelwriter import CONFIG, logger, main from PyQt6.QtWidgets import QApplication
from tests.mocked import MockGuiMain from novelwriter import (
C_BLUE, C_END, C_WHITE, CONFIG, L_FILE, L_LINE, L_LVLC, L_LVLP, L_TEXT,
L_TIME, _createApp, logger, main
)
from tests.tools import clearLogHandlers
@pytest.mark.base @pytest.mark.base
def testBaseInit_Launch(caplog, monkeypatch, fncPath): def testBaseInit_Launch(caplog, monkeypatch, fncPath):
"""Check launching the main GUI.""" """Check launching the main GUI. This test """
monkeypatch.setattr("novelwriter.guimain.GuiMain", MockGuiMain) monkeypatch.setattr("novelwriter._createApp", lambda *a: Mock())
monkeypatch.setattr("novelwriter.guimain.GuiMain", Mock())
monkeypatch.setattr(sys, "exit", Mock())
# TestMode Launch # Default Launch
nwGUI = main(["--testmode", f"--config={fncPath}", f"--data={fncPath}"]) main([f"--config={fncPath}", f"--data={fncPath}"])
assert isinstance(nwGUI, MockGuiMain) assert CONFIG._confPath == fncPath
assert CONFIG._dataPath == fncPath
# Darwin Launch # Darwin Launch Error Handling
caplog.clear()
osDarwin = CONFIG.osDarwin
CONFIG.osDarwin = True
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setitem(sys.modules, "Foundation", None) mp.setitem(sys.modules, "Foundation", None)
nwGUI = main(["--testmode", f"--config={fncPath}", f"--data={fncPath}"]) main([f"--config={fncPath}", f"--data={fncPath}"])
assert isinstance(nwGUI, MockGuiMain)
CONFIG.osDarwin = osDarwin # Windows Launch Error Handling
# Windows Launch
caplog.clear()
osWindows = CONFIG.osWindows
CONFIG.osWindows = True
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setitem(sys.modules, "ctypes", None) mp.setitem(sys.modules, "ctypes", None)
nwGUI = main(["--testmode", f"--config={fncPath}", f"--data={fncPath}"]) main([f"--config={fncPath}", f"--data={fncPath}"])
assert isinstance(nwGUI, MockGuiMain)
CONFIG.osWindows = osWindows
# Normal Launch @pytest.mark.base
with monkeypatch.context() as mp: def testBaseInit_CreateApp(caplog, monkeypatch, fncPath):
mp.setattr("PyQt6.QtWidgets.QApplication.__init__", lambda *a: None) """Check creating the Qt app."""
mp.setattr("PyQt6.QtWidgets.QApplication.setApplicationName", lambda *a: None) monkeypatch.setattr("PyQt6.QtWidgets.QApplication.__init__", lambda *a: None)
mp.setattr("PyQt6.QtWidgets.QApplication.setApplicationVersion", lambda *a: None) monkeypatch.setattr("PyQt6.QtWidgets.QApplication.setApplicationName", lambda *a: None)
mp.setattr("PyQt6.QtWidgets.QApplication.setWindowIcon", lambda *a: None) monkeypatch.setattr("PyQt6.QtWidgets.QApplication.setApplicationVersion", lambda *a: None)
mp.setattr("PyQt6.QtWidgets.QApplication.setOrganizationDomain", lambda *a: None) monkeypatch.setattr("PyQt6.QtWidgets.QApplication.setWindowIcon", lambda *a: None)
mp.setattr("PyQt6.QtWidgets.QApplication.exec", lambda *a: 0) monkeypatch.setattr("PyQt6.QtWidgets.QApplication.setOrganizationDomain", lambda *a: None)
with pytest.raises(SystemExit) as ex: monkeypatch.setattr("PyQt6.QtWidgets.QApplication.exec", lambda *a: 0)
main([f"--config={fncPath}", f"--data={fncPath}"])
assert ex.value.code == 0 app = _createApp("Fusion")
assert isinstance(app, QApplication)
@pytest.mark.base @pytest.mark.base
def testBaseInit_Options(monkeypatch, fncPath): def testBaseInit_Options(monkeypatch, fncPath):
"""Test command line options for logging level.""" """Test command line options for logging level."""
monkeypatch.setattr("novelwriter.guimain.GuiMain", MockGuiMain) gui = Mock()
app = Mock()
app.exec = Mock(return_value=0)
monkeypatch.setattr("novelwriter._createApp", lambda *a: app)
monkeypatch.setattr("novelwriter.guimain.GuiMain", lambda *a: gui)
monkeypatch.setattr(sys, "argv", [ monkeypatch.setattr(sys, "argv", [
"novelWriter.py", "--testmode", "--meminfo", f"--config={fncPath}", f"--data={fncPath}" "novelWriter.py", f"--config={fncPath}", f"--data={fncPath}"
]) ])
# Defaults w/None Args # Defaults wo/Args
nwGUI = main() gui.reset_mock()
assert nwGUI is not None with pytest.raises(SystemExit) as ex:
main()
assert ex.value.code == 0
assert logger.getEffectiveLevel() == logging.WARNING assert logger.getEffectiveLevel() == logging.WARNING
assert nwGUI.closeMain() == "closeMain" gui.postLaunchTasks.assert_called_once()
gui.postLaunchTasks.assert_called_with(None)
# Defaults # Defaults
nwGUI = main( with pytest.raises(SystemExit) as ex:
["--testmode", f"--config={fncPath}", f"--data={fncPath}", "--style=Fusion"] main([f"--config={fncPath}", f"--data={fncPath}", "--style=Fusion", "--meminfo"])
) assert ex.value.code == 0
assert nwGUI is not None assert CONFIG.memInfo is True
assert logger.getEffectiveLevel() == logging.WARNING
assert nwGUI.closeMain() == "closeMain" def getFormat() -> str:
formatter = logger.handlers[0].formatter
assert formatter is not None
fmt = formatter._fmt
assert fmt is not None
return fmt
# Log Levels w/Color # Log Levels w/Color
nwGUI = main( clearLogHandlers()
["--testmode", "--info", "--color", f"--config={fncPath}", f"--data={fncPath}"] with pytest.raises(SystemExit) as ex:
) main(["--info", "--color", f"--config={fncPath}", f"--data={fncPath}"])
assert nwGUI is not None assert ex.value.code == 0
assert logger.getEffectiveLevel() == logging.INFO assert logger.getEffectiveLevel() == logging.INFO
assert nwGUI.closeMain() == "closeMain" assert getFormat() == f"{L_LVLC} {L_TEXT}"
nwGUI = main( clearLogHandlers()
["--testmode", "--debug", "--color", f"--config={fncPath}", f"--data={fncPath}"] with pytest.raises(SystemExit) as ex:
) main(["--debug", "--color", f"--config={fncPath}", f"--data={fncPath}"])
assert nwGUI is not None assert ex.value.code == 0
assert logger.getEffectiveLevel() == logging.DEBUG assert logger.getEffectiveLevel() == logging.DEBUG
assert nwGUI.closeMain() == "closeMain" assert getFormat() == (
f"{L_TIME} {C_BLUE}{L_FILE}{C_END}:{C_WHITE}{L_LINE}{C_END} {L_LVLC} {L_TEXT}"
)
# Log Levels wo/Color # Log Levels wo/Color
nwGUI = main( clearLogHandlers()
["--testmode", "--info", f"--config={fncPath}", f"--data={fncPath}"] with pytest.raises(SystemExit) as ex:
) main(["--info", f"--config={fncPath}", f"--data={fncPath}"])
assert nwGUI is not None assert ex.value.code == 0
assert logger.getEffectiveLevel() == logging.INFO assert logger.getEffectiveLevel() == logging.INFO
assert nwGUI.closeMain() == "closeMain" assert getFormat() == f"{L_LVLP} {L_TEXT}"
nwGUI = main( clearLogHandlers()
["--testmode", "--debug", f"--config={fncPath}", f"--data={fncPath}"] with pytest.raises(SystemExit) as ex:
) main(["--debug", f"--config={fncPath}", f"--data={fncPath}"])
assert nwGUI is not None assert ex.value.code == 0
assert logger.getEffectiveLevel() == logging.DEBUG assert logger.getEffectiveLevel() == logging.DEBUG
assert nwGUI.closeMain() == "closeMain" assert getFormat() == f"{L_TIME} {L_FILE}:{L_LINE} {L_LVLP} {L_TEXT}"
# Help and Version # Help and Version
with pytest.raises(SystemExit) as ex: with pytest.raises(SystemExit) as ex:
nwGUI = main( main(["--help", f"--config={fncPath}", f"--data={fncPath}"])
["--testmode", "--help", f"--config={fncPath}", f"--data={fncPath}"]
)
assert nwGUI is not None
assert nwGUI.closeMain() == "closeMain"
assert ex.value.code == 0 assert ex.value.code == 0
with pytest.raises(SystemExit) as ex: with pytest.raises(SystemExit) as ex:
nwGUI = main( main(["--version", f"--config={fncPath}", f"--data={fncPath}"])
["--testmode", "--version", f"--config={fncPath}", f"--data={fncPath}"]
)
assert nwGUI is not None
assert nwGUI.closeMain() == "closeMain"
assert ex.value.code == 0 assert ex.value.code == 0
# Invalid options # Invalid options
with pytest.raises(SystemExit) as ex: with pytest.raises(SystemExit) as ex:
nwGUI = main( main(["--invalid", f"--config={fncPath}", f"--data={fncPath}"])
["--testmode", "--invalid", f"--config={fncPath}", f"--data={fncPath}"]
)
assert nwGUI is not None
assert nwGUI.closeMain() == "closeMain"
assert ex.value.code == 2 assert ex.value.code == 2
# Project Path # Project Path
nwGUI = main( gui.reset_mock()
["--testmode", f"--config={fncPath}", f"--data={fncPath}", "sample/"] with pytest.raises(SystemExit) as ex:
) main([f"--config={fncPath}", f"--data={fncPath}", "sample/"])
assert nwGUI is not None assert ex.value.code == 0
assert nwGUI.closeMain() == "closeMain" gui.postLaunchTasks.assert_called_once()
gui.postLaunchTasks.assert_called_with("sample/")
@pytest.mark.base @pytest.mark.base
def testBaseInit_Imports(caplog, monkeypatch, fncPath): def testBaseInit_Imports(caplog, monkeypatch, fncPath):
"""Check import error handling.""" """Check import error handling."""
monkeypatch.setattr("novelwriter.guimain.GuiMain", MockGuiMain) monkeypatch.setattr("novelwriter._createApp", lambda *a: Mock())
monkeypatch.setattr("novelwriter.guimain.GuiMain", lambda *a: Mock())
monkeypatch.setattr("PyQt6.QtWidgets.QApplication.__init__", lambda *a: None) monkeypatch.setattr("PyQt6.QtWidgets.QApplication.__init__", lambda *a: None)
monkeypatch.setattr("PyQt6.QtWidgets.QApplication.exec", lambda *a: 0) monkeypatch.setattr("PyQt6.QtWidgets.QApplication.exec", lambda *a: 0)
monkeypatch.setattr("PyQt6.QtWidgets.QErrorMessage.__init__", lambda *a: None) monkeypatch.setattr("PyQt6.QtWidgets.QErrorMessage.__init__", lambda *a: None)
@@ -174,9 +180,7 @@ def testBaseInit_Imports(caplog, monkeypatch, fncPath):
monkeypatch.setattr("novelwriter.CONFIG.verPyQtValue", 0x050000) monkeypatch.setattr("novelwriter.CONFIG.verPyQtValue", 0x050000)
with pytest.raises(SystemExit) as ex: with pytest.raises(SystemExit) as ex:
_ = main( main([f"--config={fncPath}", f"--data={fncPath}"])
["--testmode", f"--config={fncPath}", f"--data={fncPath}"]
)
assert ex.value.code & 4 == 4 # Python version not satisfied # type: ignore assert ex.value.code & 4 == 4 # Python version not satisfied # type: ignore
assert ex.value.code & 8 == 8 # Qt version not satisfied # type: ignore assert ex.value.code & 8 == 8 # Qt version not satisfied # type: ignore
+8
View File
@@ -28,6 +28,8 @@ from pathlib import Path
from PyQt6.QtWidgets import QDialog, QVBoxLayout, QWidget from PyQt6.QtWidgets import QDialog, QVBoxLayout, QWidget
from novelwriter import logger
XML_IGNORE = ("<novelWriterXML", "<project") XML_IGNORE = ("<novelWriterXML", "<project")
ODT_IGNORE = ("<meta:generator", "<meta:creation-date", "<dc:date", "<meta:editing") ODT_IGNORE = ("<meta:generator", "<meta:creation-date", "<dc:date", "<meta:editing")
NWD_IGNORE = ("%%~date:",) NWD_IGNORE = ("%%~date:",)
@@ -155,6 +157,12 @@ def cleanProject(path: str | Path):
return return
def clearLogHandlers():
"""Clear all log handlers."""
for handler in logger.handlers:
logger.removeHandler(handler)
def buildTestProject(obj: object, projPath: Path) -> None: def buildTestProject(obj: object, projPath: Path) -> None:
"""Build a standard test project in projPath using the project """Build a standard test project in projPath using the project
object as the parent. object as the parent.