"""Tests for arborist.read.open_sessions / SessionsView.""" from __future__ import annotations from pathlib import Path import pytest from arborist.qa.session import SessionStore from arborist.read import open_sessions @pytest.fixture def sessions_db(tmp_path: Path) -> Path: db = tmp_path / "sessions.db" store = SessionStore.open(db) a = store.create_session(sid="A") a.add_node("who is spider man?", "ck1", "STRICT", answer_text="Spider-Man is from Marvel.\n " '[E1 | Spider-Man | abc123: "..."]') a.add_node("who created him?", "ck2", "STRICT", answer_text="Stan Lee.\n " '[E1 | Spider-Man | abc123: "..."]') b = store.create_session(sid="B") b.add_node("how do you cook risotto?", "ck3", "HYBRID", answer_text="Stir constantly.") store.close() return db def test_counts(sessions_db: Path): v = open_sessions(sessions_db) c = v.counts() assert c.n_sessions == 2 assert c.n_nodes == 3 # synthetic roots excluded assert c.n_audit_events >= 5 # 2 init + 3 added v.close() def test_list_sessions(sessions_db: Path): v = open_sessions(sessions_db) sids = {s.sid for s in v.list_sessions()} assert sids == {"A", "B"} a = v.get_session("A") assert a is not None assert a.n_nodes == 2 assert a.session_root # non-empty hex v.close() def test_get_node_and_path_to_root(sessions_db: Path): v = open_sessions(sessions_db) n = v.get_node("A-000002") assert n is not None assert n.question == "who created him?" assert n.cited_titles == ["Spider-Man"] path = v.path_to_root("A-000002") assert [p.bates for p in path] == ["A-000002", "A-000001", "A-000000"] v.close() def test_find_fts5_across_sessions(sessions_db: Path): v = open_sessions(sessions_db) hits = v.find("spider") assert {h.sid for h in hits} == {"A"} hits = v.find("risotto") assert {h.sid for h in hits} == {"B"} v.close() def test_find_skips_synthetic_root(sessions_db: Path): v = open_sessions(sessions_db) hits = v.find("anything that wouldn't match") assert hits == [] # Even targeting empty content the synth root never surfaces. v.close() def test_chain_check_intact(sessions_db: Path): v = open_sessions(sessions_db) intact, breaks = v.chain_check() assert breaks == 0 assert intact >= 5 v.close() def test_missing_db_returns_empty_view(tmp_path: Path): """Open a path that doesn't exist yet — view is created (the bootstrap inside SessionsView ensures the schema), but everything reads back empty rather than erroring.""" db = tmp_path / "fresh.db" v = open_sessions(db) assert v.is_open assert v.counts().n_sessions == 0 assert v.list_sessions() == [] assert v.find("anything") == [] assert v.chain_check() == (0, 0) v.close() def test_branches_in_session(sessions_db: Path): """Sanity: with two single-line sessions and no forks, branches=[].""" v = open_sessions(sessions_db) assert v.branches_in_session("A") == [] assert v.branches_in_session("B") == [] v.close() def test_find_by_cache_key(sessions_db: Path): v = open_sessions(sessions_db) hits = v.find_by_cache_key("ck1") assert len(hits) == 1 assert hits[0].sid == "A" v.close()