Files
cursor-flasher/tests/test_config.py
cottongin 5b71b2275b Restructure config for per-mode style/sound and fix pulse dismiss
Major changes:
- Add StyleConfig dataclass with independent color, width, opacity,
  duration, pulse_speed, sound, and volume per mode (running/completed)
- Replace flat flash_*/sound_*/play_on config with running: and
  completed: YAML sections
- Replace CGEventTap (silently fails in forked daemon) with
  CGEventSourceSecondsSinceLastEventType polling for reliable
  input-based pulse dismissal when Cursor is already frontmost
- Update overlay, sound, and daemon to pass StyleConfig per call
- Rewrite tests for new config shape and dismiss mechanism

Made-with: Cursor
2026-03-10 07:01:52 -04:00

120 lines
3.8 KiB
Python

from cursor_flasher.config import Config, StyleConfig, load_config
class TestDefaultConfig:
def test_running_defaults(self):
c = Config()
assert c.running.color == "#FF9500"
assert c.running.width == 4
assert c.running.duration == 1.5
assert c.running.opacity == 0.85
assert c.running.pulse_speed == 1.5
assert c.running.sound == "Glass"
assert c.running.volume == 0.5
def test_completed_defaults(self):
c = Config()
assert c.completed.color == "#FF9500"
assert c.completed.width == 4
assert c.completed.sound == ""
assert c.completed.volume == 0.0
def test_has_approval_tools(self):
c = Config()
assert c.approval_tools == ["Shell", "Write", "Delete"]
def test_has_cooldown(self):
c = Config()
assert c.cooldown == 2.0
def test_has_flash_mode(self):
c = Config()
assert c.flash_mode == "screen"
class TestLoadConfig:
def test_missing_file_returns_defaults(self, tmp_path):
c = load_config(tmp_path / "nope.yaml")
assert c == Config()
def test_empty_file_returns_defaults(self, tmp_path):
p = tmp_path / "config.yaml"
p.write_text("")
c = load_config(p)
assert c == Config()
def test_loads_running_overrides(self, tmp_path):
p = tmp_path / "config.yaml"
p.write_text(
"running:\n color: '#00FF00'\n duration: 2.0\n sound: Ping\n"
)
c = load_config(p)
assert c.running.color == "#00FF00"
assert c.running.duration == 2.0
assert c.running.sound == "Ping"
assert c.running.width == 4
def test_loads_completed_overrides(self, tmp_path):
p = tmp_path / "config.yaml"
p.write_text(
"completed:\n color: '#0000FF'\n sound: Hero\n volume: 0.8\n"
)
c = load_config(p)
assert c.completed.color == "#0000FF"
assert c.completed.sound == "Hero"
assert c.completed.volume == 0.8
def test_loads_flash_mode(self, tmp_path):
p = tmp_path / "config.yaml"
p.write_text("flash:\n mode: allscreens\n")
c = load_config(p)
assert c.flash_mode == "allscreens"
def test_loads_general_overrides(self, tmp_path):
p = tmp_path / "config.yaml"
p.write_text("general:\n cooldown: 5.0\n approval_delay: 3.0\n")
c = load_config(p)
assert c.cooldown == 5.0
assert c.approval_delay == 3.0
def test_loads_approval_tools(self, tmp_path):
p = tmp_path / "config.yaml"
p.write_text("approval_tools:\n - Shell\n - MCP\n")
c = load_config(p)
assert c.approval_tools == ["Shell", "MCP"]
def test_full_config(self, tmp_path):
p = tmp_path / "config.yaml"
p.write_text(
"running:\n"
" color: '#FF0000'\n"
" width: 6\n"
" opacity: 0.9\n"
" pulse_speed: 2.0\n"
" sound: Glass\n"
" volume: 0.8\n"
"completed:\n"
" color: '#00FF00'\n"
" sound: ''\n"
"flash:\n"
" mode: window\n"
"general:\n"
" approval_delay: 1.0\n"
" cooldown: 3.0\n"
"approval_tools:\n"
" - Shell\n"
)
c = load_config(p)
assert c.running.color == "#FF0000"
assert c.running.width == 6
assert c.running.opacity == 0.9
assert c.running.pulse_speed == 2.0
assert c.running.sound == "Glass"
assert c.running.volume == 0.8
assert c.completed.color == "#00FF00"
assert c.completed.sound == ""
assert c.flash_mode == "window"
assert c.approval_delay == 1.0
assert c.cooldown == 3.0
assert c.approval_tools == ["Shell"]