Some more tests
All checks were successful
CI / test (push) Successful in 5m6s
Lint / test (push) Successful in 33s
Trivy / test (push) Successful in 24s

This commit is contained in:
Miguel Jacq 2025-11-30 15:20:11 +11:00
parent 32aa1780cf
commit 95b7d828b5
Signed by: mig5
GPG key ID: 59B3F0C24135C6A9
3 changed files with 186 additions and 1 deletions

View file

@ -95,3 +95,28 @@ def _stub_code_block_editor_dialog(monkeypatch):
monkeypatch.setattr( monkeypatch.setattr(
markdown_editor, "CodeBlockEditorDialog", _TestCodeBlockEditorDialog markdown_editor, "CodeBlockEditorDialog", _TestCodeBlockEditorDialog
) )
# --- Freeze Qt time helper (for alarm parsing tests) ---
@pytest.fixture
def freeze_qt_time(monkeypatch):
"""Freeze QDateTime.currentDateTime/QTime.currentTime to midday today.
This avoids flakiness when tests run close to midnight, so that
QTime.currentTime().addSecs(3600) is still the same calendar day.
"""
import bouquin.main_window as _mwmod
from PySide6.QtCore import QDate, QTime, QDateTime
today = QDate.currentDate()
fixed_time = QTime(12, 0)
fixed_dt = QDateTime(today, fixed_time)
# Patch the *imported* Qt symbols that main_window uses
monkeypatch.setattr(
_mwmod.QDateTime, "currentDateTime", staticmethod(lambda: QDateTime(fixed_dt))
)
monkeypatch.setattr(
_mwmod.QTime, "currentTime", staticmethod(lambda: QTime(fixed_time))
)
yield

View file

@ -0,0 +1,31 @@
from PySide6.QtWidgets import QPushButton
from bouquin.code_block_editor_dialog import CodeBlockEditorDialog
from bouquin import strings
def _find_button_by_text(widget, text):
for btn in widget.findChildren(QPushButton):
if text.lower() in btn.text().lower():
return btn
return None
def test_code_block_dialog_delete_flow(qtbot):
dlg = CodeBlockEditorDialog("print(1)", "python", allow_delete=True)
qtbot.addWidget(dlg)
delete_txt = strings._("delete_code_block")
delete_btn = _find_button_by_text(dlg, delete_txt)
assert delete_btn is not None
assert not dlg.was_deleted()
with qtbot.waitSignal(dlg.finished, timeout=2000):
delete_btn.click()
assert dlg.was_deleted()
def test_code_block_dialog_language_and_code(qtbot):
dlg = CodeBlockEditorDialog("x = 1", "not-a-lang", allow_delete=False)
qtbot.addWidget(dlg)
delete_txt = strings._("delete_code_block")
assert _find_button_by_text(dlg, delete_txt) is None
assert dlg.code() == "x = 1"
assert dlg.language() is None

View file

@ -1,3 +1,5 @@
import pytest
from unittest.mock import patch from unittest.mock import patch
from bouquin.reminders import ( from bouquin.reminders import (
Reminder, Reminder,
@ -6,12 +8,38 @@ from bouquin.reminders import (
UpcomingRemindersWidget, UpcomingRemindersWidget,
ManageRemindersDialog, ManageRemindersDialog,
) )
from PySide6.QtCore import QDate, QTime from PySide6.QtCore import QDateTime, QDate, QTime
from PySide6.QtWidgets import QDialog, QMessageBox, QWidget from PySide6.QtWidgets import QDialog, QMessageBox, QWidget
from datetime import date, timedelta from datetime import date, timedelta
@pytest.fixture
def freeze_reminders_time(monkeypatch):
# Freeze 'now' used inside bouquin.reminders to 12:00 today
import bouquin.reminders as rem
today = QDate.currentDate()
fixed_time = QTime(12, 0)
fixed_dt = QDateTime(today, fixed_time)
monkeypatch.setattr(
rem.QDateTime, "currentDateTime", staticmethod(lambda: QDateTime(fixed_dt))
)
yield
def _add_daily_reminder(db, text="Standup", time_str="23:59"):
r = Reminder(
id=None,
text=text,
time_str=time_str,
reminder_type=ReminderType.DAILY,
active=True,
)
r.id = db.save_reminder(r)
return r
def test_reminder_type_enum(app): def test_reminder_type_enum(app):
"""Test ReminderType enum values.""" """Test ReminderType enum values."""
assert ReminderType.ONCE is not None assert ReminderType.ONCE is not None
@ -799,3 +827,104 @@ def test_edit_reminder_dialog(qtbot, fresh_db):
# Verify fields are populated # Verify fields are populated
assert dlg.text_edit.text() == "Original text" assert dlg.text_edit.text() == "Original text"
assert dlg.time_edit.time().toString("HH:mm") == "14:30" assert dlg.time_edit.time().toString("HH:mm") == "14:30"
def test_upcoming_reminders_context_menu_shows(
qtbot, app, fresh_db, freeze_reminders_time, monkeypatch
):
from PySide6 import QtWidgets, QtGui
from PySide6.QtCore import QPoint
from bouquin.reminders import Reminder, ReminderType, UpcomingRemindersWidget
# Add a future reminder for today
r = Reminder(
id=None,
text="Ping",
time_str="23:59",
reminder_type=ReminderType.DAILY,
active=True,
)
r.id = fresh_db.save_reminder(r)
w = UpcomingRemindersWidget(fresh_db)
qtbot.addWidget(w)
w.refresh()
# Select first upcoming item so context menu code path runs
assert w.reminder_list.count() > 0
w.reminder_list.setCurrentItem(w.reminder_list.item(0))
called = {"exec": False, "actions": []}
class DummyAction:
def __init__(self, text, parent=None):
self._text = text
class _Sig:
def connect(self, fn):
pass
self.triggered = _Sig()
class DummyMenu:
def __init__(self, parent=None):
pass
def addAction(self, action):
called["actions"].append(getattr(action, "_text", str(action)))
def exec(self, *_, **__):
called["exec"] = True
# Patch the modules that the inline imports will read from
monkeypatch.setattr(QtWidgets, "QMenu", DummyMenu, raising=True)
monkeypatch.setattr(QtGui, "QAction", DummyAction, raising=True)
# Invoke directly (normally via right-click)
w._show_reminder_context_menu(QPoint(5, 5))
assert called["exec"] is True
assert len(called["actions"]) >= 2 # at least Edit/Deactivate/Delete
def test_upcoming_reminders_delete_selected_dedupes(
qtbot, app, fresh_db, freeze_reminders_time, monkeypatch
):
from PySide6.QtWidgets import QMessageBox
from PySide6.QtCore import QItemSelectionModel
from bouquin.reminders import Reminder, ReminderType, UpcomingRemindersWidget
r = Reminder(
id=None,
text="Duplicate target",
time_str="23:59",
reminder_type=ReminderType.DAILY,
active=True,
)
r.id = fresh_db.save_reminder(r)
w = UpcomingRemindersWidget(fresh_db)
qtbot.addWidget(w)
w.refresh()
assert w.reminder_list.count() >= 2 # daily -> multiple upcoming occurrences
# First selects & clears; second adds to selection
w.reminder_list.setCurrentRow(0, QItemSelectionModel.SelectionFlag.ClearAndSelect)
w.reminder_list.setCurrentRow(1, QItemSelectionModel.SelectionFlag.Select)
deleted_ids = []
def fake_delete(rem_id):
deleted_ids.append(rem_id)
# Auto-confirm deletion
monkeypatch.setattr(
QMessageBox, "question", staticmethod(lambda *a, **k: QMessageBox.Yes)
)
monkeypatch.setattr(fresh_db, "delete_reminder", fake_delete)
w._delete_selected_reminders()
# Should de-duplicate to a single DB delete call
assert deleted_ids == [r.id]