More tests
This commit is contained in:
parent
cb78d9f783
commit
9435800910
12 changed files with 1187 additions and 35 deletions
|
|
@ -536,3 +536,69 @@ def test_db_gather_stats_exception_in_dates_with_content(fresh_db, monkeypatch):
|
|||
|
||||
# Should default to 0 when exception occurs
|
||||
assert pages_with_content == 0
|
||||
|
||||
|
||||
def test_delete_version(fresh_db):
|
||||
"""Test deleting a specific version by version_id."""
|
||||
d = date.today().isoformat()
|
||||
|
||||
# Create multiple versions
|
||||
vid1, _ = fresh_db.save_new_version(d, "version 1", "note1")
|
||||
vid2, _ = fresh_db.save_new_version(d, "version 2", "note2")
|
||||
vid3, _ = fresh_db.save_new_version(d, "version 3", "note3")
|
||||
|
||||
# Verify all versions exist
|
||||
versions = fresh_db.list_versions(d)
|
||||
assert len(versions) == 3
|
||||
|
||||
# Delete the second version
|
||||
fresh_db.delete_version(version_id=vid2)
|
||||
|
||||
# Verify it's deleted
|
||||
versions_after = fresh_db.list_versions(d)
|
||||
assert len(versions_after) == 2
|
||||
|
||||
# Make sure the deleted version is not in the list
|
||||
version_ids = [v["id"] for v in versions_after]
|
||||
assert vid2 not in version_ids
|
||||
assert vid1 in version_ids
|
||||
assert vid3 in version_ids
|
||||
|
||||
|
||||
def test_update_reminder_active(fresh_db):
|
||||
"""Test updating the active status of a reminder."""
|
||||
from bouquin.reminders import Reminder, ReminderType
|
||||
|
||||
# Create a reminder object
|
||||
reminder = Reminder(
|
||||
id=None,
|
||||
text="Test reminder",
|
||||
reminder_type=ReminderType.ONCE,
|
||||
time_str="14:30",
|
||||
date_iso=date.today().isoformat(),
|
||||
active=True,
|
||||
)
|
||||
|
||||
# Save it
|
||||
reminder_id = fresh_db.save_reminder(reminder)
|
||||
|
||||
# Verify it's active
|
||||
reminders = fresh_db.get_all_reminders()
|
||||
active_reminder = [r for r in reminders if r.id == reminder_id][0]
|
||||
assert active_reminder.active is True
|
||||
|
||||
# Deactivate it
|
||||
fresh_db.update_reminder_active(reminder_id, False)
|
||||
|
||||
# Verify it's inactive
|
||||
reminders = fresh_db.get_all_reminders()
|
||||
inactive_reminder = [r for r in reminders if r.id == reminder_id][0]
|
||||
assert inactive_reminder.active is False
|
||||
|
||||
# Reactivate it
|
||||
fresh_db.update_reminder_active(reminder_id, True)
|
||||
|
||||
# Verify it's active again
|
||||
reminders = fresh_db.get_all_reminders()
|
||||
reactivated_reminder = [r for r in reminders if r.id == reminder_id][0]
|
||||
assert reactivated_reminder.active is True
|
||||
|
|
|
|||
|
|
@ -167,3 +167,145 @@ def test_revert_exception_shows_message(qtbot, fresh_db, monkeypatch):
|
|||
|
||||
# Should show the critical box, which our timer will accept; _revert returns.
|
||||
dlg._revert()
|
||||
|
||||
|
||||
def test_delete_version_from_history(qtbot, fresh_db):
|
||||
"""Test deleting a version through the history dialog."""
|
||||
d = "2001-01-01"
|
||||
|
||||
# Create multiple versions
|
||||
vid1, _ = fresh_db.save_new_version(d, "v1", "first")
|
||||
vid2, _ = fresh_db.save_new_version(d, "v2", "second")
|
||||
vid3, _ = fresh_db.save_new_version(d, "v3", "third")
|
||||
|
||||
w = QWidget()
|
||||
dlg = HistoryDialog(fresh_db, d, parent=w)
|
||||
qtbot.addWidget(dlg)
|
||||
dlg.show()
|
||||
|
||||
# Verify we have 3 versions
|
||||
assert dlg.list.count() == 3
|
||||
|
||||
# Select the first version (oldest, not current)
|
||||
dlg.list.setCurrentRow(2) # Last row is oldest version
|
||||
|
||||
# Call _delete
|
||||
dlg._delete()
|
||||
|
||||
# Verify the version was deleted
|
||||
assert dlg.list.count() == 2
|
||||
|
||||
# Verify from DB
|
||||
versions = fresh_db.list_versions(d)
|
||||
assert len(versions) == 2
|
||||
|
||||
|
||||
def test_delete_current_version_returns_early(qtbot, fresh_db):
|
||||
"""Test that deleting the current version returns early without deleting."""
|
||||
d = "2001-01-02"
|
||||
|
||||
# Create versions
|
||||
vid1, _ = fresh_db.save_new_version(d, "v1", "first")
|
||||
vid2, _ = fresh_db.save_new_version(d, "v2", "second")
|
||||
|
||||
w = QWidget()
|
||||
dlg = HistoryDialog(fresh_db, d, parent=w)
|
||||
qtbot.addWidget(dlg)
|
||||
dlg.show()
|
||||
|
||||
# Find and select the current version
|
||||
for i in range(dlg.list.count()):
|
||||
item = dlg.list.item(i)
|
||||
if item.data(Qt.UserRole) == dlg._current_id:
|
||||
dlg.list.setCurrentItem(item)
|
||||
break
|
||||
|
||||
# Try to delete - should return early
|
||||
dlg._delete()
|
||||
|
||||
# Verify nothing was deleted
|
||||
versions = fresh_db.list_versions(d)
|
||||
assert len(versions) == 2
|
||||
|
||||
|
||||
def test_delete_version_with_error(qtbot, fresh_db, monkeypatch):
|
||||
"""Test that delete version error shows a message box."""
|
||||
d = "2001-01-03"
|
||||
|
||||
# Create versions
|
||||
vid1, _ = fresh_db.save_new_version(d, "v1", "first")
|
||||
vid2, _ = fresh_db.save_new_version(d, "v2", "second")
|
||||
|
||||
w = QWidget()
|
||||
dlg = HistoryDialog(fresh_db, d, parent=w)
|
||||
qtbot.addWidget(dlg)
|
||||
dlg.show()
|
||||
|
||||
# Select a non-current version
|
||||
for i in range(dlg.list.count()):
|
||||
item = dlg.list.item(i)
|
||||
if item.data(Qt.UserRole) != dlg._current_id:
|
||||
dlg.list.setCurrentItem(item)
|
||||
break
|
||||
|
||||
# Make delete_version raise an error
|
||||
def boom(*args, **kwargs):
|
||||
raise RuntimeError("Delete failed")
|
||||
|
||||
monkeypatch.setattr(dlg._db, "delete_version", boom)
|
||||
|
||||
# Set up auto-closer for message box
|
||||
def make_closer(max_tries=50, interval_ms=10):
|
||||
tries = {"n": 0}
|
||||
|
||||
def closer():
|
||||
tries["n"] += 1
|
||||
w = QApplication.activeModalWidget()
|
||||
if isinstance(w, QMessageBox):
|
||||
ok = w.button(QMessageBox.Ok)
|
||||
if ok is not None:
|
||||
ok.click()
|
||||
else:
|
||||
w.accept()
|
||||
elif tries["n"] < max_tries:
|
||||
QTimer.singleShot(interval_ms, closer)
|
||||
|
||||
return closer
|
||||
|
||||
QTimer.singleShot(0, make_closer())
|
||||
|
||||
# Call delete - should show error message
|
||||
dlg._delete()
|
||||
|
||||
|
||||
def test_delete_multiple_versions(qtbot, fresh_db):
|
||||
"""Test deleting multiple versions at once."""
|
||||
d = "2001-01-04"
|
||||
|
||||
# Create multiple versions
|
||||
vid1, _ = fresh_db.save_new_version(d, "v1", "first")
|
||||
vid2, _ = fresh_db.save_new_version(d, "v2", "second")
|
||||
vid3, _ = fresh_db.save_new_version(d, "v3", "third")
|
||||
vid4, _ = fresh_db.save_new_version(d, "v4", "fourth")
|
||||
|
||||
w = QWidget()
|
||||
dlg = HistoryDialog(fresh_db, d, parent=w)
|
||||
qtbot.addWidget(dlg)
|
||||
dlg.show()
|
||||
|
||||
# Select multiple non-current items
|
||||
selected_count = 0
|
||||
for i in range(dlg.list.count()):
|
||||
item = dlg.list.item(i)
|
||||
if item.data(Qt.UserRole) != dlg._current_id:
|
||||
item.setSelected(True)
|
||||
selected_count += 1
|
||||
if selected_count >= 2: # Select 2 items
|
||||
break
|
||||
|
||||
# Delete them
|
||||
dlg._delete()
|
||||
|
||||
# Verify versions were deleted (should have current + 1 remaining)
|
||||
versions = fresh_db.list_versions(d)
|
||||
assert len(versions) == 2 # Current + 1 that wasn't deleted
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import pytest
|
||||
import importlib.metadata
|
||||
|
||||
from datetime import date, timedelta
|
||||
from pathlib import Path
|
||||
|
||||
import bouquin.main_window as mwmod
|
||||
|
|
@ -2134,3 +2135,352 @@ def test_calendar_date_selection(qtbot, app, tmp_path):
|
|||
|
||||
# The window should load that date
|
||||
assert test_date.toString("yyyy-MM-dd") in str(w._current_date_iso())
|
||||
|
||||
|
||||
def test_main_window_without_reminders(qtbot, app, tmp_db_cfg):
|
||||
"""Test main window when reminders feature is disabled."""
|
||||
s = get_settings()
|
||||
s.setValue("db/default_db", str(tmp_db_cfg.path))
|
||||
s.setValue("db/key", tmp_db_cfg.key)
|
||||
s.setValue("ui/idle_minutes", 0)
|
||||
s.setValue("ui/theme", "light")
|
||||
s.setValue("ui/move_todos", True)
|
||||
s.setValue("ui/tags", True)
|
||||
s.setValue("ui/time_log", True)
|
||||
s.setValue("ui/reminders", False) # Disabled
|
||||
s.setValue("ui/locale", "en")
|
||||
s.setValue("ui/font_size", 11)
|
||||
|
||||
themes = ThemeManager(app, ThemeConfig(theme=Theme.LIGHT))
|
||||
window = MainWindow(themes=themes)
|
||||
qtbot.addWidget(window)
|
||||
window.show()
|
||||
|
||||
# Verify reminders widget is hidden
|
||||
assert window.upcoming_reminders.isHidden()
|
||||
assert not window.toolBar.actAlarm.isVisible()
|
||||
|
||||
|
||||
def test_main_window_without_time_log(qtbot, app, tmp_db_cfg):
|
||||
"""Test main window when time_log feature is disabled."""
|
||||
s = get_settings()
|
||||
s.setValue("db/default_db", str(tmp_db_cfg.path))
|
||||
s.setValue("db/key", tmp_db_cfg.key)
|
||||
s.setValue("ui/idle_minutes", 0)
|
||||
s.setValue("ui/theme", "light")
|
||||
s.setValue("ui/move_todos", True)
|
||||
s.setValue("ui/tags", True)
|
||||
s.setValue("ui/time_log", False) # Disabled
|
||||
s.setValue("ui/reminders", True)
|
||||
s.setValue("ui/locale", "en")
|
||||
s.setValue("ui/font_size", 11)
|
||||
|
||||
themes = ThemeManager(app, ThemeConfig(theme=Theme.LIGHT))
|
||||
window = MainWindow(themes=themes)
|
||||
qtbot.addWidget(window)
|
||||
window.show()
|
||||
|
||||
# Verify time_log widget is hidden
|
||||
assert window.time_log.isHidden()
|
||||
assert not window.toolBar.actTimer.isVisible()
|
||||
|
||||
|
||||
def test_main_window_without_tags(qtbot, app, tmp_db_cfg):
|
||||
"""Test main window when tags feature is disabled."""
|
||||
s = get_settings()
|
||||
s.setValue("db/default_db", str(tmp_db_cfg.path))
|
||||
s.setValue("db/key", tmp_db_cfg.key)
|
||||
s.setValue("ui/idle_minutes", 0)
|
||||
s.setValue("ui/theme", "light")
|
||||
s.setValue("ui/move_todos", True)
|
||||
s.setValue("ui/tags", False) # Disabled
|
||||
s.setValue("ui/time_log", True)
|
||||
s.setValue("ui/reminders", True)
|
||||
s.setValue("ui/locale", "en")
|
||||
s.setValue("ui/font_size", 11)
|
||||
|
||||
themes = ThemeManager(app, ThemeConfig(theme=Theme.LIGHT))
|
||||
window = MainWindow(themes=themes)
|
||||
qtbot.addWidget(window)
|
||||
window.show()
|
||||
|
||||
# Verify tags widget is hidden
|
||||
assert window.tags.isHidden()
|
||||
|
||||
|
||||
def test_close_current_tab(qtbot, app, tmp_db_cfg, fresh_db):
|
||||
"""Test closing the current tab via _close_current_tab."""
|
||||
s = get_settings()
|
||||
s.setValue("db/default_db", str(tmp_db_cfg.path))
|
||||
s.setValue("db/key", tmp_db_cfg.key)
|
||||
s.setValue("ui/idle_minutes", 0)
|
||||
s.setValue("ui/theme", "light")
|
||||
s.setValue("ui/move_todos", True)
|
||||
s.setValue("ui/tags", True)
|
||||
s.setValue("ui/time_log", True)
|
||||
s.setValue("ui/reminders", True)
|
||||
s.setValue("ui/locale", "en")
|
||||
s.setValue("ui/font_size", 11)
|
||||
|
||||
themes = ThemeManager(app, ThemeConfig(theme=Theme.LIGHT))
|
||||
window = MainWindow(themes=themes)
|
||||
qtbot.addWidget(window)
|
||||
window.show()
|
||||
|
||||
# Open multiple tabs
|
||||
today = date.today().isoformat()
|
||||
tomorrow = (date.today() + timedelta(days=1)).isoformat()
|
||||
|
||||
window._open_date_in_tab(QDate.fromString(today, "yyyy-MM-dd"))
|
||||
window._open_date_in_tab(QDate.fromString(tomorrow, "yyyy-MM-dd"))
|
||||
|
||||
initial_count = window.tab_widget.count()
|
||||
assert initial_count >= 2
|
||||
|
||||
# Close current tab
|
||||
window._close_current_tab()
|
||||
|
||||
# Verify tab was closed
|
||||
assert window.tab_widget.count() == initial_count - 1
|
||||
|
||||
|
||||
def test_table_insertion(qtbot, app, tmp_db_cfg, fresh_db):
|
||||
"""Test inserting a table template."""
|
||||
s = get_settings()
|
||||
s.setValue("db/default_db", str(tmp_db_cfg.path))
|
||||
s.setValue("db/key", tmp_db_cfg.key)
|
||||
s.setValue("ui/idle_minutes", 0)
|
||||
s.setValue("ui/theme", "light")
|
||||
s.setValue("ui/move_todos", True)
|
||||
s.setValue("ui/tags", True)
|
||||
s.setValue("ui/time_log", True)
|
||||
s.setValue("ui/reminders", True)
|
||||
s.setValue("ui/locale", "en")
|
||||
s.setValue("ui/font_size", 11)
|
||||
|
||||
themes = ThemeManager(app, ThemeConfig(theme=Theme.LIGHT))
|
||||
window = MainWindow(themes=themes)
|
||||
qtbot.addWidget(window)
|
||||
window.show()
|
||||
|
||||
# Open a date
|
||||
today = date.today().isoformat()
|
||||
window._open_date_in_tab(QDate.fromString(today, "yyyy-MM-dd"))
|
||||
|
||||
# Ensure we have an editor
|
||||
editor = window.editor
|
||||
assert editor is not None
|
||||
|
||||
# Insert table
|
||||
window._on_table_requested()
|
||||
|
||||
# Verify table was inserted
|
||||
text = editor.toPlainText()
|
||||
assert "Column 1" in text
|
||||
assert "Column 2" in text
|
||||
assert "Column 3" in text
|
||||
assert "---" in text
|
||||
|
||||
|
||||
def test_parse_today_alarms(qtbot, app, tmp_db_cfg, fresh_db):
|
||||
"""Test parsing inline alarms from markdown (⏰ HH:MM format)."""
|
||||
from PySide6.QtCore import QTime
|
||||
|
||||
s = get_settings()
|
||||
s.setValue("db/default_db", str(tmp_db_cfg.path))
|
||||
s.setValue("db/key", tmp_db_cfg.key)
|
||||
s.setValue("ui/idle_minutes", 0)
|
||||
s.setValue("ui/theme", "light")
|
||||
s.setValue("ui/move_todos", True)
|
||||
s.setValue("ui/tags", True)
|
||||
s.setValue("ui/time_log", True)
|
||||
s.setValue("ui/reminders", True)
|
||||
s.setValue("ui/locale", "en")
|
||||
s.setValue("ui/font_size", 11)
|
||||
|
||||
themes = ThemeManager(app, ThemeConfig(theme=Theme.LIGHT))
|
||||
window = MainWindow(themes=themes)
|
||||
qtbot.addWidget(window)
|
||||
window.show()
|
||||
|
||||
# Open today's date
|
||||
today_qdate = QDate.currentDate()
|
||||
window._open_date_in_tab(today_qdate)
|
||||
|
||||
# Set content with a future alarm
|
||||
future_time = QTime.currentTime().addSecs(3600) # 1 hour from now
|
||||
alarm_text = f"Do something ⏰ {future_time.hour():02d}:{future_time.minute():02d}"
|
||||
|
||||
# Set the editor's current_date attribute
|
||||
window.editor.current_date = today_qdate
|
||||
window.editor.setPlainText(alarm_text)
|
||||
|
||||
# Clear any existing timers
|
||||
window._reminder_timers = []
|
||||
|
||||
# Trigger alarm parsing
|
||||
window._rebuild_reminders_for_today()
|
||||
|
||||
# Verify timer was created (not DB reminder)
|
||||
assert len(window._reminder_timers) > 0
|
||||
|
||||
|
||||
def test_parse_today_alarms_invalid_time(qtbot, app, tmp_db_cfg, fresh_db):
|
||||
"""Test that invalid time formats are skipped."""
|
||||
s = get_settings()
|
||||
s.setValue("db/default_db", str(tmp_db_cfg.path))
|
||||
s.setValue("db/key", tmp_db_cfg.key)
|
||||
s.setValue("ui/idle_minutes", 0)
|
||||
s.setValue("ui/theme", "light")
|
||||
s.setValue("ui/move_todos", True)
|
||||
s.setValue("ui/tags", True)
|
||||
s.setValue("ui/time_log", True)
|
||||
s.setValue("ui/reminders", True)
|
||||
s.setValue("ui/locale", "en")
|
||||
s.setValue("ui/font_size", 11)
|
||||
|
||||
themes = ThemeManager(app, ThemeConfig(theme=Theme.LIGHT))
|
||||
window = MainWindow(themes=themes)
|
||||
qtbot.addWidget(window)
|
||||
window.show()
|
||||
|
||||
# Open today's date
|
||||
today_qdate = QDate.currentDate()
|
||||
window._open_date_in_tab(today_qdate)
|
||||
|
||||
# Set content with invalid time
|
||||
alarm_text = "Do something ⏰ 25:99" # Invalid time
|
||||
|
||||
window.editor.current_date = today_qdate
|
||||
window.editor.setPlainText(alarm_text)
|
||||
|
||||
# Clear any existing timers
|
||||
window._reminder_timers = []
|
||||
|
||||
# Trigger alarm parsing - should not crash
|
||||
window._rebuild_reminders_for_today()
|
||||
|
||||
# No timer should be created for invalid time
|
||||
assert len(window._reminder_timers) == 0
|
||||
|
||||
|
||||
def test_parse_today_alarms_past_time(qtbot, app, tmp_db_cfg, fresh_db):
|
||||
"""Test that past alarms are skipped."""
|
||||
from PySide6.QtCore import QTime
|
||||
|
||||
s = get_settings()
|
||||
s.setValue("db/default_db", str(tmp_db_cfg.path))
|
||||
s.setValue("db/key", tmp_db_cfg.key)
|
||||
s.setValue("ui/idle_minutes", 0)
|
||||
s.setValue("ui/theme", "light")
|
||||
s.setValue("ui/move_todos", True)
|
||||
s.setValue("ui/tags", True)
|
||||
s.setValue("ui/time_log", True)
|
||||
s.setValue("ui/reminders", True)
|
||||
s.setValue("ui/locale", "en")
|
||||
s.setValue("ui/font_size", 11)
|
||||
|
||||
themes = ThemeManager(app, ThemeConfig(theme=Theme.LIGHT))
|
||||
window = MainWindow(themes=themes)
|
||||
qtbot.addWidget(window)
|
||||
window.show()
|
||||
|
||||
# Open today's date
|
||||
today_qdate = QDate.currentDate()
|
||||
window._open_date_in_tab(today_qdate)
|
||||
|
||||
# Set content with past time
|
||||
past_time = QTime.currentTime().addSecs(-3600) # 1 hour ago
|
||||
alarm_text = f"Do something ⏰ {past_time.hour():02d}:{past_time.minute():02d}"
|
||||
|
||||
window.editor.current_date = today_qdate
|
||||
window.editor.setPlainText(alarm_text)
|
||||
|
||||
# Clear any existing timers
|
||||
window._reminder_timers = []
|
||||
|
||||
# Trigger alarm parsing
|
||||
window._rebuild_reminders_for_today()
|
||||
|
||||
# Past alarms should not create timers
|
||||
assert len(window._reminder_timers) == 0
|
||||
|
||||
|
||||
def test_parse_today_alarms_no_text(qtbot, app, tmp_db_cfg, fresh_db):
|
||||
"""Test alarm with no text before emoji uses fallback."""
|
||||
from PySide6.QtCore import QTime
|
||||
|
||||
s = get_settings()
|
||||
s.setValue("db/default_db", str(tmp_db_cfg.path))
|
||||
s.setValue("db/key", tmp_db_cfg.key)
|
||||
s.setValue("ui/idle_minutes", 0)
|
||||
s.setValue("ui/theme", "light")
|
||||
s.setValue("ui/move_todos", True)
|
||||
s.setValue("ui/tags", True)
|
||||
s.setValue("ui/time_log", True)
|
||||
s.setValue("ui/reminders", True)
|
||||
s.setValue("ui/locale", "en")
|
||||
s.setValue("ui/font_size", 11)
|
||||
|
||||
themes = ThemeManager(app, ThemeConfig(theme=Theme.LIGHT))
|
||||
window = MainWindow(themes=themes)
|
||||
qtbot.addWidget(window)
|
||||
window.show()
|
||||
|
||||
# Open today's date
|
||||
today_qdate = QDate.currentDate()
|
||||
window._open_date_in_tab(today_qdate)
|
||||
|
||||
# Set content with alarm but no text
|
||||
future_time = QTime.currentTime().addSecs(3600)
|
||||
alarm_text = f"⏰ {future_time.hour():02d}:{future_time.minute():02d}"
|
||||
|
||||
window.editor.current_date = today_qdate
|
||||
window.editor.setPlainText(alarm_text)
|
||||
|
||||
# Clear any existing timers
|
||||
window._reminder_timers = []
|
||||
|
||||
# Trigger alarm parsing
|
||||
window._rebuild_reminders_for_today()
|
||||
|
||||
# Timer should be created even without text
|
||||
assert len(window._reminder_timers) > 0
|
||||
|
||||
|
||||
def test_open_history_with_editor(qtbot, app, tmp_db_cfg, fresh_db):
|
||||
"""Test opening history when editor has content."""
|
||||
from unittest.mock import patch
|
||||
|
||||
s = get_settings()
|
||||
s.setValue("db/default_db", str(tmp_db_cfg.path))
|
||||
s.setValue("db/key", tmp_db_cfg.key)
|
||||
s.setValue("ui/idle_minutes", 0)
|
||||
s.setValue("ui/theme", "light")
|
||||
s.setValue("ui/move_todos", True)
|
||||
s.setValue("ui/tags", True)
|
||||
s.setValue("ui/time_log", True)
|
||||
s.setValue("ui/reminders", True)
|
||||
s.setValue("ui/locale", "en")
|
||||
s.setValue("ui/font_size", 11)
|
||||
|
||||
themes = ThemeManager(app, ThemeConfig(theme=Theme.LIGHT))
|
||||
window = MainWindow(themes=themes)
|
||||
qtbot.addWidget(window)
|
||||
window.show()
|
||||
|
||||
# Create some history
|
||||
today = date.today().isoformat()
|
||||
fresh_db.save_new_version(today, "v1", "note1")
|
||||
fresh_db.save_new_version(today, "v2", "note2")
|
||||
|
||||
# Open today's date
|
||||
window._open_date_in_tab(QDate.fromString(today, "yyyy-MM-dd"))
|
||||
|
||||
# Open history
|
||||
with patch("bouquin.history_dialog.HistoryDialog.exec") as mock_exec:
|
||||
mock_exec.return_value = False # User cancels
|
||||
window._open_history()
|
||||
|
||||
# HistoryDialog should have been created and shown
|
||||
mock_exec.assert_called_once()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import base64
|
||||
import pytest
|
||||
|
||||
from PySide6.QtCore import Qt, QPoint
|
||||
from PySide6.QtCore import Qt, QPoint, QMimeData, QUrl
|
||||
from PySide6.QtGui import (
|
||||
QImage,
|
||||
QColor,
|
||||
|
|
@ -2216,3 +2216,243 @@ def test_markdown_highlighter_theme_change(qtbot, app):
|
|||
# Highlighter should update
|
||||
# We can't directly test the visual change, but verify it doesn't crash
|
||||
assert highlighter is not None
|
||||
|
||||
|
||||
def test_auto_pair_skip_closing_bracket(editor, qtbot):
|
||||
"""Test skipping over closing brackets when auto-pairing."""
|
||||
# Insert opening bracket
|
||||
editor.insertPlainText("(")
|
||||
|
||||
# Type closing bracket - should skip over the auto-inserted one
|
||||
event = QKeyEvent(QKeyEvent.KeyPress, Qt.Key_ParenRight, Qt.NoModifier, ")")
|
||||
editor.keyPressEvent(event)
|
||||
|
||||
# Should have only one pair of brackets
|
||||
text = editor.toPlainText()
|
||||
assert text.count("(") == 1
|
||||
assert text.count(")") == 1
|
||||
|
||||
|
||||
def test_apply_heading(editor, qtbot):
|
||||
"""Test applying heading to text."""
|
||||
# Insert some text
|
||||
editor.insertPlainText("Heading Text")
|
||||
cursor = editor.textCursor()
|
||||
cursor.movePosition(QTextCursor.StartOfLine)
|
||||
editor.setTextCursor(cursor)
|
||||
|
||||
# Apply heading - size >= 24 creates level 1 heading
|
||||
editor.apply_heading(24)
|
||||
|
||||
text = editor.toPlainText()
|
||||
assert text.startswith("#")
|
||||
|
||||
|
||||
def test_handle_return_in_code_block(editor, qtbot):
|
||||
"""Test pressing return inside a code block."""
|
||||
# Create a code block
|
||||
editor.insertPlainText("```python\nprint('hello')")
|
||||
|
||||
# Place cursor at end
|
||||
cursor = editor.textCursor()
|
||||
cursor.movePosition(QTextCursor.End)
|
||||
editor.setTextCursor(cursor)
|
||||
|
||||
# Press return - should maintain indentation
|
||||
event = QKeyEvent(QKeyEvent.KeyPress, Qt.Key_Return, Qt.NoModifier, "\n")
|
||||
editor.keyPressEvent(event)
|
||||
|
||||
# Should have added a new line
|
||||
text = editor.toPlainText()
|
||||
assert text.count("\n") >= 2
|
||||
|
||||
|
||||
def test_handle_return_in_list_empty_item(editor, qtbot):
|
||||
"""Test pressing return in an empty list item."""
|
||||
# Create list with empty item
|
||||
editor.insertPlainText("- item\n- ")
|
||||
|
||||
# Place cursor at end of empty item
|
||||
cursor = editor.textCursor()
|
||||
cursor.movePosition(QTextCursor.End)
|
||||
editor.setTextCursor(cursor)
|
||||
|
||||
# Press return - should end the list
|
||||
event = QKeyEvent(QKeyEvent.KeyPress, Qt.Key_Return, Qt.NoModifier, "\n")
|
||||
editor.keyPressEvent(event)
|
||||
|
||||
text = editor.toPlainText()
|
||||
# Should have processed the empty list marker
|
||||
lines = text.split("\n")
|
||||
assert len(lines) >= 2
|
||||
|
||||
|
||||
def test_handle_backspace_in_empty_list_item(editor, qtbot):
|
||||
"""Test pressing backspace in an empty list item."""
|
||||
# Create list with cursor after marker
|
||||
editor.insertPlainText("- ")
|
||||
|
||||
# Place cursor at end
|
||||
cursor = editor.textCursor()
|
||||
cursor.movePosition(QTextCursor.End)
|
||||
editor.setTextCursor(cursor)
|
||||
|
||||
# Press backspace - should remove list marker
|
||||
event = QKeyEvent(QKeyEvent.KeyPress, Qt.Key_Backspace, Qt.NoModifier, "")
|
||||
editor.keyPressEvent(event)
|
||||
|
||||
text = editor.toPlainText()
|
||||
# List marker handling
|
||||
assert len(text) <= 2
|
||||
|
||||
|
||||
def test_tab_key_handling(editor, qtbot):
|
||||
"""Test tab key handling in editor."""
|
||||
# Create a list item
|
||||
editor.insertPlainText("- item")
|
||||
|
||||
# Place cursor in the item
|
||||
cursor = editor.textCursor()
|
||||
cursor.movePosition(QTextCursor.End)
|
||||
editor.setTextCursor(cursor)
|
||||
|
||||
# Press tab
|
||||
event = QKeyEvent(QKeyEvent.KeyPress, Qt.Key_Tab, Qt.NoModifier, "\t")
|
||||
editor.keyPressEvent(event)
|
||||
|
||||
# Should have processed the tab
|
||||
text = editor.toPlainText()
|
||||
assert len(text) >= 6 # At least "- item" plus tab
|
||||
|
||||
|
||||
def test_drag_enter_with_urls(editor, qtbot):
|
||||
"""Test drag and drop with URLs."""
|
||||
from PySide6.QtGui import QDragEnterEvent
|
||||
|
||||
# Create mime data with URLs
|
||||
mime_data = QMimeData()
|
||||
mime_data.setUrls([QUrl("file:///tmp/test.txt")])
|
||||
|
||||
# Create drag enter event
|
||||
event = QDragEnterEvent(
|
||||
editor.rect().center(), Qt.CopyAction, mime_data, Qt.LeftButton, Qt.NoModifier
|
||||
)
|
||||
|
||||
# Handle drag enter
|
||||
editor.dragEnterEvent(event)
|
||||
|
||||
# Should accept the event
|
||||
assert event.isAccepted()
|
||||
|
||||
|
||||
def test_drag_enter_with_text(editor, qtbot):
|
||||
"""Test drag and drop with plain text."""
|
||||
from PySide6.QtGui import QDragEnterEvent
|
||||
|
||||
# Create mime data with text
|
||||
mime_data = QMimeData()
|
||||
mime_data.setText("dragged text")
|
||||
|
||||
# Create drag enter event
|
||||
event = QDragEnterEvent(
|
||||
editor.rect().center(), Qt.CopyAction, mime_data, Qt.LeftButton, Qt.NoModifier
|
||||
)
|
||||
|
||||
# Handle drag enter
|
||||
editor.dragEnterEvent(event)
|
||||
|
||||
# Should accept text drag
|
||||
assert event.isAccepted()
|
||||
|
||||
|
||||
def test_highlighter_dark_mode_code_blocks(app, qtbot, tmp_path):
|
||||
"""Test code block highlighting in dark mode."""
|
||||
# Get theme manager and set dark mode
|
||||
theme_manager = ThemeManager(app, ThemeConfig(theme=Theme.DARK))
|
||||
|
||||
# Create editor with dark theme
|
||||
editor = MarkdownEditor(theme_manager)
|
||||
qtbot.addWidget(editor)
|
||||
|
||||
# Insert code block
|
||||
editor.setPlainText("```python\nprint('hello')\n```")
|
||||
|
||||
# Force rehighlight
|
||||
editor.highlighter.rehighlight()
|
||||
|
||||
# Verify no crash - actual color verification is difficult in tests
|
||||
|
||||
|
||||
def test_highlighter_code_block_with_language(editor, qtbot):
|
||||
"""Test syntax highlighting inside fenced code blocks with language."""
|
||||
# Insert code block with language
|
||||
editor.setPlainText('```python\ndef hello():\n print("world")\n```')
|
||||
|
||||
# Force rehighlight
|
||||
editor.highlighter.rehighlight()
|
||||
|
||||
# Verify syntax highlighting was applied (lines 186-193)
|
||||
# We can't easily verify the exact formatting, but we ensure no crash
|
||||
|
||||
|
||||
def test_highlighter_bold_italic_overlap_detection(editor, qtbot):
|
||||
"""Test that bold/italic formatting detects overlaps correctly."""
|
||||
# Insert text with overlapping bold and triple-asterisk
|
||||
editor.setPlainText("***bold and italic***")
|
||||
|
||||
# Force rehighlight
|
||||
editor.highlighter.rehighlight()
|
||||
|
||||
# The overlap detection (lines 252, 264) should prevent issues
|
||||
|
||||
|
||||
def test_highlighter_italic_edge_cases(editor, qtbot):
|
||||
"""Test italic formatting edge cases."""
|
||||
# Test edge case: avoiding stealing markers that are part of double
|
||||
# This tests lines 267-270
|
||||
editor.setPlainText("**not italic* text**")
|
||||
|
||||
# Force rehighlight
|
||||
editor.highlighter.rehighlight()
|
||||
|
||||
# Test another edge case
|
||||
editor.setPlainText("*italic but next to double**")
|
||||
editor.highlighter.rehighlight()
|
||||
|
||||
|
||||
def test_highlighter_multiple_markdown_elements(editor, qtbot):
|
||||
"""Test highlighting document with multiple markdown elements."""
|
||||
# Complex document with various elements
|
||||
text = """# Heading 1
|
||||
## Heading 2
|
||||
|
||||
**bold text** and *italic text*
|
||||
|
||||
```python
|
||||
def test():
|
||||
return True
|
||||
```
|
||||
|
||||
- list item
|
||||
- [ ] task item
|
||||
|
||||
[link](http://example.com)
|
||||
"""
|
||||
|
||||
editor.setPlainText(text)
|
||||
editor.highlighter.rehighlight()
|
||||
|
||||
# Verify no crashes with complex formatting
|
||||
|
||||
|
||||
def test_highlighter_inline_code_vs_fence(editor, qtbot):
|
||||
"""Test that inline code and fenced blocks are distinguished."""
|
||||
text = """Inline `code` here
|
||||
|
||||
```
|
||||
fenced block
|
||||
```
|
||||
"""
|
||||
|
||||
editor.setPlainText(text)
|
||||
editor.highlighter.rehighlight()
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ from bouquin.reminders import (
|
|||
ManageRemindersDialog,
|
||||
)
|
||||
from PySide6.QtCore import QDate, QTime
|
||||
from PySide6.QtWidgets import QDialog, QMessageBox
|
||||
from PySide6.QtWidgets import QDialog, QMessageBox, QWidget
|
||||
|
||||
from datetime import date, timedelta
|
||||
|
||||
|
||||
def test_reminder_type_enum(app):
|
||||
|
|
@ -655,3 +657,174 @@ def test_reminder_with_inactive_status(qtbot, app, fresh_db):
|
|||
for i in range(widget.reminder_list.count()):
|
||||
item = widget.reminder_list.item(i)
|
||||
assert "Inactive" not in item.text() or "No upcoming" in item.text()
|
||||
|
||||
|
||||
def test_reminder_triggers_and_deactivates(qtbot, fresh_db):
|
||||
"""Test that ONCE reminders deactivate after firing."""
|
||||
# Add a ONCE reminder for right now
|
||||
now = QTime.currentTime()
|
||||
hour = now.hour()
|
||||
minute = now.minute()
|
||||
|
||||
reminder = Reminder(
|
||||
id=None,
|
||||
text="Test once reminder",
|
||||
reminder_type=ReminderType.ONCE,
|
||||
time_str=f"{hour:02d}:{minute:02d}",
|
||||
date_iso=date.today().isoformat(),
|
||||
active=True,
|
||||
)
|
||||
reminder_id = fresh_db.save_reminder(reminder)
|
||||
|
||||
reminders_widget = UpcomingRemindersWidget(fresh_db)
|
||||
qtbot.addWidget(reminders_widget)
|
||||
|
||||
# Set up signal spy
|
||||
triggered_texts = []
|
||||
reminders_widget.reminderTriggered.connect(
|
||||
lambda text: triggered_texts.append(text)
|
||||
)
|
||||
|
||||
# Trigger the check
|
||||
reminders_widget._check_reminders()
|
||||
|
||||
# Verify reminder was triggered
|
||||
assert len(triggered_texts) > 0
|
||||
assert "Test once reminder" in triggered_texts
|
||||
|
||||
# Verify reminder was deactivated
|
||||
reminders = fresh_db.get_all_reminders()
|
||||
deactivated = [r for r in reminders if r.id == reminder_id][0]
|
||||
assert deactivated.active is False
|
||||
|
||||
|
||||
def test_reminder_not_active_skipped(qtbot, fresh_db):
|
||||
"""Test that inactive reminders are not triggered."""
|
||||
now = QTime.currentTime()
|
||||
hour = now.hour()
|
||||
minute = now.minute()
|
||||
|
||||
reminder = Reminder(
|
||||
id=None,
|
||||
text="Inactive reminder",
|
||||
reminder_type=ReminderType.ONCE,
|
||||
time_str=f"{hour:02d}:{minute:02d}",
|
||||
date_iso=date.today().isoformat(),
|
||||
active=False, # Not active
|
||||
)
|
||||
fresh_db.save_reminder(reminder)
|
||||
|
||||
reminders_widget = UpcomingRemindersWidget(fresh_db)
|
||||
qtbot.addWidget(reminders_widget)
|
||||
|
||||
# Set up signal spy
|
||||
triggered_texts = []
|
||||
reminders_widget.reminderTriggered.connect(
|
||||
lambda text: triggered_texts.append(text)
|
||||
)
|
||||
|
||||
# Trigger the check
|
||||
reminders_widget._check_reminders()
|
||||
|
||||
# Should not trigger inactive reminder
|
||||
assert len(triggered_texts) == 0
|
||||
|
||||
|
||||
def test_reminder_not_today_skipped(qtbot, fresh_db):
|
||||
"""Test that reminders not scheduled for today are skipped."""
|
||||
now = QTime.currentTime()
|
||||
hour = now.hour()
|
||||
minute = now.minute()
|
||||
|
||||
# Schedule for tomorrow
|
||||
tomorrow = date.today() + timedelta(days=1)
|
||||
|
||||
reminder = Reminder(
|
||||
id=None,
|
||||
text="Tomorrow's reminder",
|
||||
reminder_type=ReminderType.ONCE,
|
||||
time_str=f"{hour:02d}:{minute:02d}",
|
||||
date_iso=tomorrow.isoformat(),
|
||||
active=True,
|
||||
)
|
||||
fresh_db.save_reminder(reminder)
|
||||
|
||||
reminders_widget = UpcomingRemindersWidget(fresh_db)
|
||||
qtbot.addWidget(reminders_widget)
|
||||
|
||||
# Set up signal spy
|
||||
triggered_texts = []
|
||||
reminders_widget.reminderTriggered.connect(
|
||||
lambda text: triggered_texts.append(text)
|
||||
)
|
||||
|
||||
# Trigger the check
|
||||
reminders_widget._check_reminders()
|
||||
|
||||
# Should not trigger tomorrow's reminder
|
||||
assert len(triggered_texts) == 0
|
||||
|
||||
|
||||
def test_reminder_context_menu_single_item(qtbot, fresh_db):
|
||||
"""Test context menu for a single reminder item."""
|
||||
reminder = Reminder(
|
||||
id=None,
|
||||
text="Test reminder",
|
||||
reminder_type=ReminderType.ONCE,
|
||||
time_str="14:30",
|
||||
date_iso=date.today().isoformat(),
|
||||
active=True,
|
||||
)
|
||||
fresh_db.save_reminder(reminder)
|
||||
|
||||
reminders_widget = UpcomingRemindersWidget(fresh_db)
|
||||
qtbot.addWidget(reminders_widget)
|
||||
reminders_widget.show()
|
||||
|
||||
# Refresh to populate the list
|
||||
reminders_widget.refresh()
|
||||
|
||||
# Select the first item
|
||||
if reminders_widget.reminder_list.count() > 0:
|
||||
reminders_widget.reminder_list.setCurrentRow(0)
|
||||
|
||||
# Show context menu (won't actually display in tests)
|
||||
reminders_widget._show_reminder_context_menu(
|
||||
reminders_widget.reminder_list.pos()
|
||||
)
|
||||
|
||||
|
||||
def test_reminder_context_menu_no_selection(qtbot, fresh_db):
|
||||
"""Test context menu with no selection returns early."""
|
||||
reminders_widget = UpcomingRemindersWidget(fresh_db)
|
||||
qtbot.addWidget(reminders_widget)
|
||||
|
||||
# Clear selection
|
||||
reminders_widget.reminder_list.clearSelection()
|
||||
|
||||
# Show context menu - should return early
|
||||
reminders_widget._show_reminder_context_menu(reminders_widget.reminder_list.pos())
|
||||
|
||||
|
||||
def test_edit_reminder_dialog(qtbot, fresh_db):
|
||||
"""Test editing a reminder through the dialog."""
|
||||
reminder = Reminder(
|
||||
id=None,
|
||||
text="Original text",
|
||||
reminder_type=ReminderType.DAILY,
|
||||
time_str="14:30",
|
||||
date_iso=None,
|
||||
active=True,
|
||||
)
|
||||
fresh_db.save_reminder(reminder)
|
||||
|
||||
widget = QWidget()
|
||||
|
||||
# Create edit dialog
|
||||
reminder_obj = fresh_db.get_all_reminders()[0]
|
||||
dlg = ReminderDialog(fresh_db, widget, reminder=reminder_obj)
|
||||
qtbot.addWidget(dlg)
|
||||
|
||||
# Verify fields are populated
|
||||
assert dlg.text_edit.text() == "Original text"
|
||||
assert dlg.time_edit.time().toString("HH:mm") == "14:30"
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@ from datetime import datetime, timedelta, date
|
|||
|
||||
from bouquin import strings
|
||||
|
||||
from PySide6.QtCore import Qt, QPoint
|
||||
from PySide6.QtWidgets import QLabel
|
||||
from PySide6.QtCore import Qt, QPoint, QDate
|
||||
from PySide6.QtWidgets import QLabel, QWidget
|
||||
from PySide6.QtTest import QTest
|
||||
from PySide6.QtCore import QDate
|
||||
|
||||
from bouquin.statistics_dialog import DateHeatmap, StatisticsDialog
|
||||
|
||||
|
|
@ -515,3 +514,123 @@ def test_statistics_dialog_metric_changes(qtbot, tmp_db_cfg, fresh_db):
|
|||
for i in range(dialog.metric_combo.count()):
|
||||
dialog.metric_combo.setCurrentIndex(i)
|
||||
qtbot.wait(50)
|
||||
|
||||
|
||||
def test_heatmap_date_beyond_end(qtbot, fresh_db):
|
||||
"""Test clicking on a date beyond the end date in heatmap."""
|
||||
# Create entries spanning a range
|
||||
today = date.today()
|
||||
start = today - timedelta(days=30)
|
||||
|
||||
data = {}
|
||||
for i in range(20):
|
||||
d = start + timedelta(days=i)
|
||||
fresh_db.save_new_version(d.isoformat(), f"Entry {i}", f"note {i}")
|
||||
data[d] = 1
|
||||
|
||||
w = QWidget()
|
||||
qtbot.addWidget(w)
|
||||
|
||||
heatmap = DateHeatmap()
|
||||
qtbot.addWidget(heatmap)
|
||||
heatmap.show()
|
||||
|
||||
# Set data
|
||||
heatmap.set_data(data)
|
||||
|
||||
# Try to click beyond the end date - should return early
|
||||
# Calculate a position that would be beyond the end
|
||||
if heatmap._start and heatmap._end:
|
||||
cell_span = heatmap._cell + heatmap._gap
|
||||
weeks = ((heatmap._end - heatmap._start).days + 6) // 7
|
||||
|
||||
# Click beyond the last week
|
||||
x = heatmap._margin_left + (weeks + 1) * cell_span + 5
|
||||
y = heatmap._margin_top + 3 * cell_span + 5
|
||||
|
||||
QTest.mouseClick(heatmap, Qt.LeftButton, Qt.NoModifier, QPoint(int(x), int(y)))
|
||||
|
||||
|
||||
def test_heatmap_click_outside_grid(qtbot, fresh_db):
|
||||
"""Test clicking outside the heatmap grid area."""
|
||||
today = date.today()
|
||||
start = today - timedelta(days=7)
|
||||
|
||||
data = {}
|
||||
for i in range(7):
|
||||
d = start + timedelta(days=i)
|
||||
fresh_db.save_new_version(d.isoformat(), f"Entry {i}", f"note {i}")
|
||||
data[d] = 1
|
||||
|
||||
w = QWidget()
|
||||
qtbot.addWidget(w)
|
||||
|
||||
heatmap = DateHeatmap()
|
||||
qtbot.addWidget(heatmap)
|
||||
heatmap.show()
|
||||
heatmap.set_data(data)
|
||||
|
||||
# Click in the margin (outside grid)
|
||||
x = heatmap._margin_left - 10 # Before the grid
|
||||
y = heatmap._margin_top - 10 # Above the grid
|
||||
|
||||
QTest.mouseClick(heatmap, Qt.LeftButton, Qt.NoModifier, QPoint(int(x), int(y)))
|
||||
|
||||
# Should not crash, just return early
|
||||
|
||||
|
||||
def test_heatmap_click_invalid_row(qtbot, fresh_db):
|
||||
"""Test clicking on an invalid row (>= 7)."""
|
||||
today = date.today()
|
||||
start = today - timedelta(days=7)
|
||||
|
||||
data = {}
|
||||
for i in range(7):
|
||||
d = start + timedelta(days=i)
|
||||
fresh_db.save_new_version(d.isoformat(), f"Entry {i}", f"note {i}")
|
||||
data[d] = 1
|
||||
|
||||
w = QWidget()
|
||||
qtbot.addWidget(w)
|
||||
|
||||
heatmap = DateHeatmap()
|
||||
qtbot.addWidget(heatmap)
|
||||
heatmap.show()
|
||||
heatmap.set_data(data)
|
||||
|
||||
# Click below row 6 (day of week > Sunday)
|
||||
cell_span = heatmap._cell + heatmap._gap
|
||||
x = heatmap._margin_left + 5
|
||||
y = heatmap._margin_top + 7 * cell_span + 5 # Row 7, which is invalid
|
||||
|
||||
QTest.mouseClick(heatmap, Qt.LeftButton, Qt.NoModifier, QPoint(int(x), int(y)))
|
||||
|
||||
# Should return early, not crash
|
||||
|
||||
|
||||
def test_heatmap_month_label_continuation(qtbot, fresh_db):
|
||||
"""Test that month labels don't repeat when continuing in same month."""
|
||||
# Create a date range that spans multiple weeks within the same month
|
||||
today = date.today()
|
||||
# Use a date that's guaranteed to be mid-month
|
||||
start = date(today.year, today.month, 1)
|
||||
|
||||
data = {}
|
||||
for i in range(21):
|
||||
d = start + timedelta(days=i)
|
||||
fresh_db.save_new_version(d.isoformat(), f"Entry {i}", f"note {i}")
|
||||
data[d] = 1
|
||||
|
||||
w = QWidget()
|
||||
qtbot.addWidget(w)
|
||||
|
||||
heatmap = DateHeatmap()
|
||||
qtbot.addWidget(heatmap)
|
||||
heatmap.show()
|
||||
heatmap.set_data(data)
|
||||
|
||||
# Force a repaint to execute paintEvent
|
||||
heatmap.repaint()
|
||||
|
||||
# The month continuation logic (line 175) should prevent duplicate labels
|
||||
# We can't easily test the visual output, but we ensure no crash
|
||||
|
|
|
|||
|
|
@ -477,15 +477,6 @@ def test_time_report_empty(fresh_db):
|
|||
# ============================================================================
|
||||
|
||||
|
||||
def test_time_log_widget_creation(qtbot, fresh_db):
|
||||
"""TimeLogWidget can be created."""
|
||||
widget = TimeLogWidget(fresh_db)
|
||||
qtbot.addWidget(widget)
|
||||
assert widget is not None
|
||||
assert not widget.toggle_btn.isChecked()
|
||||
assert not widget.body.isVisible()
|
||||
|
||||
|
||||
def test_time_log_widget_toggle(qtbot, fresh_db):
|
||||
"""Toggle expands/collapses the widget."""
|
||||
widget = TimeLogWidget(fresh_db)
|
||||
|
|
@ -2556,3 +2547,52 @@ def test_time_report_dialog_very_large_hours(qtbot, fresh_db):
|
|||
|
||||
# Check total label
|
||||
assert "166" in dialog.total_label.text() or "167" in dialog.total_label.text()
|
||||
|
||||
|
||||
def test_time_log_widget_creation(qtbot, fresh_db):
|
||||
"""TimeLogWidget can be created."""
|
||||
widget = TimeLogWidget(fresh_db)
|
||||
qtbot.addWidget(widget)
|
||||
assert widget is not None
|
||||
assert not widget.toggle_btn.isChecked()
|
||||
assert not widget.body.isVisible()
|
||||
|
||||
|
||||
def test_time_log_set_current_date(qtbot, fresh_db):
|
||||
"""Test setting the current date on the time log widget."""
|
||||
widget = TimeLogWidget(fresh_db)
|
||||
qtbot.addWidget(widget)
|
||||
|
||||
today = date.today().isoformat()
|
||||
widget.set_current_date(today)
|
||||
|
||||
# Verify the current date was set
|
||||
assert widget._current_date == today
|
||||
|
||||
|
||||
def test_time_log_with_entry(qtbot, fresh_db):
|
||||
"""Test time log widget with a time entry."""
|
||||
# Add a project
|
||||
proj_id = fresh_db.add_project("Test Project")
|
||||
# Add activity
|
||||
act_id = fresh_db.add_activity("Test Activity")
|
||||
|
||||
# Add a time log entry
|
||||
today = date.today().isoformat()
|
||||
fresh_db.add_time_log(
|
||||
date_iso=today,
|
||||
project_id=proj_id,
|
||||
activity_id=act_id,
|
||||
minutes=150,
|
||||
note="Test note",
|
||||
)
|
||||
|
||||
widget = TimeLogWidget(fresh_db)
|
||||
qtbot.addWidget(widget)
|
||||
widget.show()
|
||||
|
||||
# Set the date to today
|
||||
widget.set_current_date(today)
|
||||
|
||||
# Widget should have been created successfully
|
||||
assert widget is not None
|
||||
|
|
|
|||
|
|
@ -510,3 +510,25 @@ def test_download_file_invalid_content_length(qtbot, app, tmp_path):
|
|||
checker._download_file("http://example.com/file", dest_path)
|
||||
|
||||
assert dest_path.exists()
|
||||
|
||||
|
||||
def test_version_checker_creation(qtbot):
|
||||
"""Test creating a VersionChecker instance."""
|
||||
widget = QWidget()
|
||||
qtbot.addWidget(widget)
|
||||
|
||||
checker = VersionChecker(widget)
|
||||
assert checker is not None
|
||||
|
||||
|
||||
def test_current_version(qtbot):
|
||||
"""Test getting the current version."""
|
||||
widget = QWidget()
|
||||
qtbot.addWidget(widget)
|
||||
|
||||
checker = VersionChecker(widget)
|
||||
version = checker.current_version()
|
||||
|
||||
# Version should be a string
|
||||
assert isinstance(version, str)
|
||||
assert len(version) > 0
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue