Adds first formal test suite for Python fork — 42 tests covering memory_store,
profiles_store, scheduler_store, macros_store, llm_backend. All pass.
Tests (tests/, ~290 lines)
conftest.py — `isolated_state` fixture: rewires _PATH/_PROFILES_DIR etc to
a per-test tmp_path so concurrent runs don't touch real data.
test_memory_store.py — 9 tests: remember/recall/forget round-trip,
search by key/value, limit/empty query,
persistence across reload, build_llm_context
test_profiles_store.py — 7 tests: seeded defaults, set_active persistence,
allows_command logic (default/work/driving)
test_scheduler_store.py — 12 tests: parser (daily/at/every/in, ru units,
bad input), add/remove/clear/remove_by_text,
_next_fire for each schedule kind
test_macros_store.py — 8 tests: is_macro_control filter, start/save
round-trip, control-phrase filtering, list_names
sorted, replay unknown raises
test_llm_backend.py — 6 tests: parse_backend aliases (ru + en),
persist round-trip, auto-detect logic
Run: cd /c/Jarvis/python && python -m pytest tests/
Three new fun packs (commands.yaml: 151 → 154)
now_playing — Windows Media Session API via PowerShell
"что играет" / "что за песня" / "какой трек"
Works with Spotify, YouTube, Foobar, Yandex Music, anything
that exposes SMTC (Win10 1803+).
world_clock — worldtimeapi.org (free, no key)
"сколько времени в Токио" / "время в Лондоне"
21 Russian + world cities pre-mapped to IANA timezones.
daily_quote — zenquotes.io (free, no key) + LLM translation
"цитата дня" / "вдохнови меня"
Fetches English quote, translates to Russian via active LLM
(Groq or Ollama), speaks "text — author."
Pack count: 151 → 154. Tests: 42 pytest + ast.parse + yaml.safe_load.
87 lines
2.7 KiB
Python
87 lines
2.7 KiB
Python
"""Tests for macros_store: record/save/cancel/list/delete + control-phrase filter."""
|
|
|
|
|
|
def test_is_macro_control_filters_record_phrases(isolated_state):
|
|
m = isolated_state('macros_store', ['_PATH'])
|
|
assert m._is_control("Запиши макрос работа")
|
|
assert m._is_control("сохрани макрос")
|
|
assert m._is_control("запусти макрос работа")
|
|
assert m._is_control("Удали макрос работа")
|
|
# Regular commands NOT filtered
|
|
assert not m._is_control("открой браузер")
|
|
assert not m._is_control("установи громкость 50")
|
|
|
|
|
|
def test_start_save_round_trip(isolated_state):
|
|
m = isolated_state('macros_store', ['_PATH'])
|
|
m.start("test")
|
|
assert m.is_recording()
|
|
assert m.recording_name() == 'test'
|
|
|
|
m.record_step("открой браузер")
|
|
m.record_step("режим работа")
|
|
m.record_step("установи громкость 30")
|
|
# Control phrase should be filtered
|
|
m.record_step("запиши макрос новый")
|
|
|
|
count = m.save()
|
|
assert count == 3 # 3 + 1 filtered = 3
|
|
assert not m.is_recording()
|
|
|
|
mac = m.get('test')
|
|
assert mac is not None
|
|
assert mac['steps'] == [
|
|
'открой браузер',
|
|
'режим работа',
|
|
'установи громкость 30',
|
|
]
|
|
|
|
|
|
def test_save_without_recording_raises(isolated_state):
|
|
import pytest
|
|
m = isolated_state('macros_store', ['_PATH'])
|
|
with pytest.raises(RuntimeError):
|
|
m.save()
|
|
|
|
|
|
def test_save_empty_recording_raises(isolated_state):
|
|
import pytest
|
|
m = isolated_state('macros_store', ['_PATH'])
|
|
m.start("empty")
|
|
with pytest.raises(RuntimeError):
|
|
m.save()
|
|
|
|
|
|
def test_cancel_aborts_without_saving(isolated_state):
|
|
m = isolated_state('macros_store', ['_PATH'])
|
|
m.start("test")
|
|
m.record_step("foo")
|
|
assert m.cancel() is True
|
|
assert not m.is_recording()
|
|
assert m.get('test') is None
|
|
|
|
|
|
def test_delete(isolated_state):
|
|
m = isolated_state('macros_store', ['_PATH'])
|
|
m.start("test")
|
|
m.record_step("x")
|
|
m.save()
|
|
assert m.delete("test") is True
|
|
assert m.get('test') is None
|
|
assert m.delete("test") is False # idempotent
|
|
|
|
|
|
def test_list_names_sorted(isolated_state):
|
|
m = isolated_state('macros_store', ['_PATH'])
|
|
for name in ('zeta', 'alpha', 'beta'):
|
|
m.start(name)
|
|
m.record_step("step")
|
|
m.save()
|
|
assert m.list_names() == ['alpha', 'beta', 'zeta']
|
|
|
|
|
|
def test_replay_unknown_raises(isolated_state):
|
|
import pytest
|
|
m = isolated_state('macros_store', ['_PATH'])
|
|
with pytest.raises(KeyError):
|
|
m.replay("nonexistent", lambda s: None)
|