113 lines
3.5 KiB
Python
113 lines
3.5 KiB
Python
import types
|
|
import pytest
|
|
from PySide6.QtCore import Qt
|
|
from PySide6.QtWidgets import QApplication, QDialog, QWidget
|
|
|
|
from bouquin.db import DBConfig, DBManager
|
|
from bouquin.settings_dialog import SettingsDialog
|
|
from bouquin.settings import APP_NAME, APP_ORG
|
|
from bouquin.key_prompt import KeyPrompt
|
|
from bouquin.theme import Theme, ThemeManager, ThemeConfig
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def app():
|
|
a = QApplication.instance()
|
|
if a is None:
|
|
a = QApplication([])
|
|
a.setApplicationName(APP_NAME)
|
|
a.setOrganizationName(APP_ORG)
|
|
return a
|
|
|
|
|
|
@pytest.fixture
|
|
def db(tmp_path):
|
|
cfg = DBConfig(path=tmp_path / "s.db", key="abc")
|
|
m = DBManager(cfg)
|
|
assert m.connect()
|
|
return m
|
|
|
|
|
|
def test_theme_radio_initialisation_dark_and_light(app, db, monkeypatch, qtbot):
|
|
# Dark preselection
|
|
parent = _ParentWithThemes(app)
|
|
qtbot.addWidget(parent)
|
|
dlg = SettingsDialog(db.cfg, db, parent=parent)
|
|
qtbot.addWidget(dlg)
|
|
dlg.theme_dark.setChecked(True)
|
|
dlg._save()
|
|
assert dlg.config.theme == Theme.DARK.value
|
|
|
|
# Light preselection
|
|
parent2 = _ParentWithThemes(app)
|
|
qtbot.addWidget(parent2)
|
|
dlg2 = SettingsDialog(db.cfg, db, parent=parent2)
|
|
qtbot.addWidget(dlg2)
|
|
dlg2.theme_light.setChecked(True)
|
|
dlg2._save()
|
|
assert dlg2.config.theme == Theme.LIGHT.value
|
|
|
|
|
|
def test_change_key_cancel_branches(app, db, monkeypatch, qtbot):
|
|
parent = _ParentWithThemes(app)
|
|
qtbot.addWidget(parent)
|
|
dlg = SettingsDialog(db.cfg, db, parent=parent)
|
|
qtbot.addWidget(dlg)
|
|
|
|
# First prompt cancelled -> early return
|
|
monkeypatch.setattr(KeyPrompt, "exec", lambda self: QDialog.Rejected)
|
|
dlg._change_key() # should just return without altering key
|
|
assert dlg.key == ""
|
|
|
|
# First OK, second cancelled -> early return at the second branch
|
|
state = {"calls": 0}
|
|
|
|
def _exec(self):
|
|
state["calls"] += 1
|
|
return QDialog.Accepted if state["calls"] == 1 else QDialog.Rejected
|
|
|
|
monkeypatch.setattr(KeyPrompt, "exec", _exec)
|
|
# Also monkeypatch to control key() values
|
|
monkeypatch.setattr(KeyPrompt, "key", lambda self: "new-secret")
|
|
dlg._change_key()
|
|
# Because the second prompt was rejected, key should remain unchanged
|
|
assert dlg.key == ""
|
|
|
|
|
|
def test_save_key_checkbox_cancel_restores_checkbox(app, db, monkeypatch, qtbot):
|
|
parent = _ParentWithThemes(app)
|
|
qtbot.addWidget(parent)
|
|
dlg = SettingsDialog(db.cfg, db, parent=parent)
|
|
qtbot.addWidget(dlg)
|
|
qtbot.addWidget(dlg)
|
|
|
|
# Simulate user checking the box, but cancelling the prompt -> code unchecks it again
|
|
monkeypatch.setattr(KeyPrompt, "exec", lambda self: QDialog.Rejected)
|
|
dlg.save_key_btn.setChecked(True)
|
|
# The slot toggled should run and revert it to unchecked
|
|
assert dlg.save_key_btn.isChecked() is False
|
|
|
|
|
|
def test_change_key_exception_path(app, db, monkeypatch, qtbot):
|
|
parent = _ParentWithThemes(app)
|
|
qtbot.addWidget(parent)
|
|
dlg = SettingsDialog(db.cfg, db, parent=parent)
|
|
qtbot.addWidget(dlg)
|
|
|
|
# Accept both prompts and supply a key
|
|
monkeypatch.setattr(KeyPrompt, "exec", lambda self: QDialog.Accepted)
|
|
monkeypatch.setattr(KeyPrompt, "key", lambda self: "boom")
|
|
|
|
# Force DB rekey to raise to exercise the except-branch
|
|
monkeypatch.setattr(
|
|
db, "rekey", lambda new_key: (_ for _ in ()).throw(RuntimeError("fail"))
|
|
)
|
|
|
|
# Should not raise; error is handled internally
|
|
dlg._change_key()
|
|
|
|
|
|
class _ParentWithThemes(QWidget):
|
|
def __init__(self, app):
|
|
super().__init__()
|
|
self.themes = ThemeManager(app, ThemeConfig())
|