personal memory agent
0

Configure Feed

Select the types of activity you want to include in your feed.

solstone / tests / test_calendar_schema.py
4.9 kB 156 lines
1# SPDX-License-Identifier: AGPL-3.0-only 2# Copyright (c) 2026 sol pbc 3 4import json 5from pathlib import Path 6from unittest.mock import AsyncMock, patch 7 8import pytest 9from jsonschema import Draft202012Validator 10 11from solstone.observe import describe as describe_mod 12from solstone.observe.categories import calendar as calendar_mod 13from solstone.think.batch import Batch 14from solstone.think.schema_bounds import unbounded_nodes 15 16 17def _load_schema() -> dict: 18 return json.loads( 19 ( 20 Path(describe_mod.__file__).resolve().parent 21 / "categories" 22 / "calendar.schema.json" 23 ).read_text(encoding="utf-8") 24 ) 25 26 27def _valid_payload() -> dict: 28 return { 29 "app": "Google Calendar", 30 "view": "week", 31 "range": "Apr 13 - Apr 19, 2026", 32 "events": [ 33 { 34 "title": "Planning review", 35 "start": "Tue 10:00 AM", 36 "end": "11:00 AM", 37 "location": "Conference Room A", 38 "conferencing": "Google Meet", 39 "guests": ["Alice", "Bob"], 40 "status": "accepted", 41 "recurrence": None, 42 "calendar": "Work", 43 "description": "Visible event notes", 44 }, 45 ], 46 "availability": ["Tue 2:00 PM"], 47 "notes": "Timezone: America/Denver", 48 } 49 50 51def test_calendar_schema_file_is_valid_draft_2020_12(): 52 Draft202012Validator.check_schema(_load_schema()) 53 54 55def test_calendar_schema_accepts_and_rejects_expected_values(): 56 validator = Draft202012Validator(_load_schema()) 57 58 assert validator.is_valid(_valid_payload()) 59 60 bad_enum = _valid_payload() 61 bad_enum["view"] = "list" 62 assert not validator.is_valid(bad_enum) 63 64 extra_property = _valid_payload() 65 extra_property["extra"] = True 66 assert not validator.is_valid(extra_property) 67 68 missing_required = _valid_payload() 69 del missing_required["events"] 70 assert not validator.is_valid(missing_required) 71 72 wrong_item_type = _valid_payload() 73 wrong_item_type["events"] = ["Planning review"] 74 assert not validator.is_valid(wrong_item_type) 75 76 77def test_discover_categories_attaches_calendar_schema(): 78 expected = _load_schema() 79 80 assert describe_mod.CATEGORIES["calendar"]["json_schema"] == expected 81 assert describe_mod.CATEGORIES["calendar"]["output"] == "json" 82 83 84@pytest.mark.asyncio 85@patch("solstone.think.batch.agenerate_with_result", new_callable=AsyncMock) 86async def test_calendar_extract_batch_call_passes_schema(mock_agenerate): 87 mock_agenerate.return_value = { 88 "text": json.dumps(_valid_payload()), 89 "finish_reason": "stop", 90 } 91 92 cat_meta = describe_mod.CATEGORIES["calendar"] 93 batch = Batch(max_concurrent=1) 94 req = batch.create( 95 contents="Analyze this calendar screenshot.", 96 context=cat_meta["context"], 97 json_schema=cat_meta["json_schema"], 98 ) 99 batch.add(req) 100 101 results = [] 102 async for completed_req in batch.drain_batch(): 103 results.append(completed_req) 104 105 assert len(results) == 1 106 assert mock_agenerate.call_args.kwargs["json_schema"] == _load_schema() 107 108 109def test_calendar_schema_has_no_unbounded_nodes(): 110 assert unbounded_nodes(_load_schema()) == [] 111 112 113def test_calendar_formatter_renders_valid_dict(): 114 result = calendar_mod.format(_valid_payload(), {}) 115 116 assert "**Calendar** (Google Calendar - week)" in result 117 assert "*Apr 13 - Apr 19, 2026*" in result 118 assert "- **Planning review** (Tue 10:00 AM - 11:00 AM) [accepted]" in result 119 assert " - Location: Conference Room A" in result 120 assert " - Conferencing: Google Meet" in result 121 assert " - Guests: Alice, Bob" in result 122 assert " - Calendar: Work" in result 123 assert " - Description: Visible event notes" in result 124 assert "**Availability:** Tue 2:00 PM" in result 125 assert "Timezone: America/Denver" in result 126 127 128def test_calendar_formatter_returns_empty_for_non_dict(): 129 assert calendar_mod.format("# [Calendar - Week]", {}) == "" 130 131 132def test_calendar_formatter_skips_non_dict_event(caplog): 133 payload = _valid_payload() 134 payload["events"] = [ 135 "Planning review", 136 { 137 "title": "Follow-up", 138 "start": None, 139 "end": None, 140 "location": None, 141 "conferencing": None, 142 "guests": [], 143 "status": "unknown", 144 "recurrence": None, 145 "calendar": None, 146 "description": None, 147 }, 148 ] 149 150 with caplog.at_level("WARNING", logger="solstone.observe.categories.calendar"): 151 result = calendar_mod.format(payload, {}) 152 153 assert "**Calendar** (Google Calendar - week)" in result 154 assert "- **Follow-up**" in result 155 assert "Planning review" not in result 156 assert "skipping non-dict event" in caplog.text