2026-04-10 21:07:48 +02:00
|
|
|
import sys
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.skipif(sys.platform != "win32", reason="Tray nur auf Windows")
|
|
|
|
|
class TestCreateIcon:
|
|
|
|
|
def test_returns_image_for_each_state(self):
|
|
|
|
|
from PIL import Image
|
|
|
|
|
from whisper_local.tray._tray import AppState
|
|
|
|
|
from whisper_local.tray._icon import create_icon
|
|
|
|
|
|
|
|
|
|
for state in AppState:
|
|
|
|
|
img = create_icon(state)
|
|
|
|
|
assert isinstance(img, Image.Image)
|
|
|
|
|
assert img.size == (64, 64)
|
|
|
|
|
assert img.mode == "RGBA"
|
|
|
|
|
|
|
|
|
|
def test_different_states_have_different_colors(self):
|
|
|
|
|
from whisper_local.tray._tray import AppState
|
|
|
|
|
from whisper_local.tray._icon import create_icon
|
|
|
|
|
|
|
|
|
|
waiting = create_icon(AppState.WAITING)
|
|
|
|
|
recording = create_icon(AppState.RECORDING)
|
|
|
|
|
assert waiting.tobytes() != recording.tobytes()
|
2026-04-10 21:09:10 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.skipif(sys.platform != "win32", reason="Tray nur auf Windows")
|
|
|
|
|
class TestWin32TrayApp:
|
|
|
|
|
def test_set_state_updates_icon(self):
|
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
|
from whisper_local.tray._tray import AppState, Win32TrayApp
|
|
|
|
|
|
|
|
|
|
app = Win32TrayApp(on_settings=MagicMock(), on_quit=MagicMock())
|
|
|
|
|
|
|
|
|
|
mock_icon = MagicMock()
|
|
|
|
|
app._icon = mock_icon
|
|
|
|
|
|
|
|
|
|
app.set_state(AppState.RECORDING)
|
|
|
|
|
|
|
|
|
|
assert mock_icon.icon is not None
|
|
|
|
|
|
|
|
|
|
def test_set_state_before_start_is_safe(self):
|
|
|
|
|
from unittest.mock import MagicMock
|
|
|
|
|
from whisper_local.tray._tray import AppState, Win32TrayApp
|
|
|
|
|
|
|
|
|
|
app = Win32TrayApp(on_settings=MagicMock(), on_quit=MagicMock())
|
|
|
|
|
app.set_state(AppState.WAITING) # kein Fehler, _icon ist None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestNoOpTray:
|
|
|
|
|
def test_start_does_nothing(self):
|
|
|
|
|
from whisper_local.tray._tray import AppState, NoOpTray
|
|
|
|
|
tray = NoOpTray()
|
|
|
|
|
tray.start() # kein Fehler
|
|
|
|
|
|
|
|
|
|
def test_set_state_does_nothing(self):
|
|
|
|
|
from whisper_local.tray._tray import AppState, NoOpTray
|
|
|
|
|
tray = NoOpTray()
|
|
|
|
|
tray.set_state(AppState.RECORDING) # kein Fehler
|
2026-04-10 21:11:18 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.skipif(sys.platform != "win32", reason="Theme nur auf Windows")
|
|
|
|
|
class TestApplySystemTheme:
|
|
|
|
|
def test_applies_light_theme(self):
|
|
|
|
|
import tkinter as tk
|
|
|
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
|
from whisper_local.tray._theme import apply_system_theme
|
|
|
|
|
|
|
|
|
|
root = tk.Tk()
|
|
|
|
|
root.withdraw()
|
|
|
|
|
try:
|
|
|
|
|
with patch("darkdetect.theme", return_value="Light"), \
|
|
|
|
|
patch("sv_ttk.set_theme") as mock_set:
|
|
|
|
|
apply_system_theme(root)
|
|
|
|
|
mock_set.assert_called_once_with("light")
|
|
|
|
|
finally:
|
|
|
|
|
root.destroy()
|
|
|
|
|
|
|
|
|
|
def test_applies_dark_theme(self):
|
|
|
|
|
import tkinter as tk
|
|
|
|
|
from unittest.mock import patch
|
|
|
|
|
from whisper_local.tray._theme import apply_system_theme
|
|
|
|
|
|
|
|
|
|
root = tk.Tk()
|
|
|
|
|
root.withdraw()
|
|
|
|
|
try:
|
|
|
|
|
with patch("darkdetect.theme", return_value="Dark"), \
|
|
|
|
|
patch("sv_ttk.set_theme") as mock_set:
|
|
|
|
|
apply_system_theme(root)
|
|
|
|
|
mock_set.assert_called_once_with("dark")
|
|
|
|
|
finally:
|
|
|
|
|
root.destroy()
|
|
|
|
|
|
|
|
|
|
def test_falls_back_to_light_when_none(self):
|
|
|
|
|
import tkinter as tk
|
|
|
|
|
from unittest.mock import patch
|
|
|
|
|
from whisper_local.tray._theme import apply_system_theme
|
|
|
|
|
|
|
|
|
|
root = tk.Tk()
|
|
|
|
|
root.withdraw()
|
|
|
|
|
try:
|
|
|
|
|
with patch("darkdetect.theme", return_value=None), \
|
|
|
|
|
patch("sv_ttk.set_theme") as mock_set:
|
|
|
|
|
apply_system_theme(root)
|
|
|
|
|
mock_set.assert_called_once_with("light")
|
|
|
|
|
finally:
|
|
|
|
|
root.destroy()
|