import tempfile from datetime import date import pytest from iobj.models import ObjectCreate, ObjectType, ObjectUpdate, SearchQuery from iobj.storage import ObjectStore @pytest.fixture def store(): with tempfile.TemporaryDirectory() as tmp: s = ObjectStore(tmp) yield s s.close() def _mk(**kwargs) -> ObjectCreate: defaults = dict( type=ObjectType.RECAP, object_date=date(2026, 7, 1), project="NordBytes", tags=["frontend"], title="Test title", body="Some body text about BDD tests", ) defaults.update(kwargs) return ObjectCreate(**defaults) def test_create_and_get_roundtrip(store): obj = store.create(_mk()) fetched = store.get(obj.id) assert fetched is not None assert fetched.id == obj.id assert fetched.title == "Test title" assert fetched.project == "NordBytes" def test_get_missing_returns_none(store): assert store.get("does-not-exist") is None def test_shard_file_created_per_month(store): store.create(_mk(object_date=date(2026, 1, 15))) store.create(_mk(object_date=date(2026, 3, 2))) shard_files = sorted(p.name for p in store.data_dir.glob("*.json")) assert shard_files == ["2026-01.json", "2026-03.json"] def test_update_changes_fields(store): obj = store.create(_mk()) updated = store.update(obj.id, ObjectUpdate(title="New title", tags=["backend"])) assert updated.title == "New title" assert updated.tags == ["backend"] assert updated.body == obj.body # untouched field preserved def test_update_moves_shard_when_date_changes(store): obj = store.create(_mk(object_date=date(2026, 1, 1))) store.update(obj.id, ObjectUpdate(object_date=date(2026, 6, 1))) shard_files = sorted(p.name for p in store.data_dir.glob("*.json")) assert "2026-06.json" in shard_files moved = store.get(obj.id) assert moved.object_date == date(2026, 6, 1) def test_update_missing_returns_none(store): assert store.update("nope", ObjectUpdate(title="x")) is None def test_delete_removes_object(store): obj = store.create(_mk()) assert store.delete(obj.id) is True assert store.get(obj.id) is None def test_delete_missing_returns_false(store): assert store.delete("nope") is False def test_search_filters_by_type(store): store.create(_mk(type=ObjectType.RECAP)) store.create(_mk(type=ObjectType.GIT_COMMIT, title="commit one")) results = store.search(SearchQuery(type=ObjectType.GIT_COMMIT)) assert len(results) == 1 assert results[0].title == "commit one" def test_search_filters_by_project_case_insensitive(store): store.create(_mk(project="NordBytes")) store.create(_mk(project="Egmont")) results = store.search(SearchQuery(project="nordbytes")) assert len(results) == 1 assert results[0].project == "NordBytes" def test_search_filters_by_tag(store): store.create(_mk(tags=["frontend", "bdd"])) store.create(_mk(tags=["backend"])) results = store.search(SearchQuery(tag="bdd")) assert len(results) == 1 def test_search_filters_by_date_range(store): store.create(_mk(object_date=date(2026, 1, 5), title="jan")) store.create(_mk(object_date=date(2026, 6, 5), title="jun")) store.create(_mk(object_date=date(2026, 12, 5), title="dec")) results = store.search(SearchQuery(date_from=date(2026, 2, 1), date_to=date(2026, 7, 1))) assert len(results) == 1 assert results[0].title == "jun" def test_search_free_text_matches_title_and_body(store): store.create(_mk(title="BDD patterns", body="irrelevant")) store.create(_mk(title="irrelevant", body="mentions BDD somewhere")) store.create(_mk(title="nothing", body="nothing")) results = store.search(SearchQuery(q="bdd")) assert len(results) == 2 def test_search_respects_limit_and_offset_and_sort_order(store): for i in range(5): store.create(_mk(object_date=date(2026, 1, 1 + i), title=f"obj{i}")) all_results = store.search(SearchQuery(limit=100)) assert [r.title for r in all_results] == ["obj4", "obj3", "obj2", "obj1", "obj0"] page = store.search(SearchQuery(limit=2, offset=1)) assert [r.title for r in page] == ["obj3", "obj2"] def test_search_combines_multiple_filters(store): store.create(_mk(project="NordBytes", tags=["bdd"], title="match", object_date=date(2026, 5, 5))) store.create(_mk(project="NordBytes", tags=["other"], title="no-tag-match", object_date=date(2026, 5, 5))) store.create(_mk(project="Egmont", tags=["bdd"], title="wrong-project", object_date=date(2026, 5, 5))) results = store.search(SearchQuery(project="NordBytes", tag="bdd")) assert len(results) == 1 assert results[0].title == "match" def test_search_no_shards_returns_empty(store): assert store.search(SearchQuery()) == []