"""Activity-selection transitions independent from Textual widgets.""" import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).parent.parent / "src")) from fenris.activity_selection import ActivitySelection, IntervalIdentity def _interval(n): return IntervalIdentity(f"start-{n}", f"end-{n}") def test_live_selection_starts_and_stays_on_newest_interval(): selection = ActivitySelection() first = [_interval(1), _interval(2)] selection.update_live(first) assert selection.following_live assert selection.selected_live_interval == first[-1] second = first + [_interval(3)] selection.update_live(second) assert selection.selected_live_interval == second[-1] def test_keyboard_and_mouse_inspection_pin_interval_identity(): intervals = [_interval(1), _interval(2), _interval(3)] keyboard = ActivitySelection() mouse = ActivitySelection() keyboard.update_live(intervals) keyboard.move_live(intervals, -1) mouse.update_live(intervals) mouse.inspect_live(intervals, intervals[1]) assert keyboard.selected_live_interval == mouse.selected_live_interval == intervals[1] assert not keyboard.following_live assert not mouse.following_live refreshed = [_interval(2), _interval(3), _interval(4)] keyboard.update_live(refreshed) mouse.update_live(refreshed) assert keyboard.selected_live_interval == mouse.selected_live_interval == intervals[1] def test_expired_pin_explains_expiration_and_resumes_following(): selection = ActivitySelection() intervals = [_interval(1), _interval(2), _interval(3)] selection.update_live(intervals) selection.inspect_live(intervals, intervals[0]) newest = _interval(4) selection.update_live([_interval(2), _interval(3), newest]) assert selection.following_live assert selection.selected_live_interval == newest assert selection.live_interval_expired def test_today_resets_expired_pin_and_read_write_toggle_keeps_identity(): selection = ActivitySelection() intervals = [_interval(1), _interval(2)] selection.update_live(intervals) selection.inspect_live(intervals, intervals[0]) selection.update_live([intervals[1]]) newest = _interval(3) selection.update_live([intervals[1], newest]) assert selection.live_interval_expired selection.toggle_measure() assert selection.measure == "read" assert selection.selected_live_interval == newest selection.select_history_date("2026-09-27") selection.set_view("history") selection.set_view("live") assert selection.browse_date is None assert selection.following_live assert not selection.live_interval_expired def test_live_identity_uses_both_interval_boundaries(): first = IntervalIdentity("2026-09-28T10:00:00Z", "2026-09-28T10:03:00Z") changed_start = IntervalIdentity("2026-09-28T09:57:00Z", "2026-09-28T10:03:00Z") selection = ActivitySelection() selection.update_live([first]) selection.inspect_live([first], first) selection.update_live([changed_start]) assert selection.following_live assert selection.selected_live_interval == changed_start assert selection.live_interval_expired