test_todo_tool.py
1 """Tests for the todo tool module.""" 2 3 import json 4 5 from tools.todo_tool import TodoStore, todo_tool 6 7 8 class TestWriteAndRead: 9 def test_write_replaces_list(self): 10 store = TodoStore() 11 items = [ 12 {"id": "1", "content": "First task", "status": "pending"}, 13 {"id": "2", "content": "Second task", "status": "in_progress"}, 14 ] 15 result = store.write(items) 16 assert len(result) == 2 17 assert result[0]["id"] == "1" 18 assert result[1]["status"] == "in_progress" 19 20 def test_read_returns_copy(self): 21 store = TodoStore() 22 store.write([{"id": "1", "content": "Task", "status": "pending"}]) 23 items = store.read() 24 items[0]["content"] = "MUTATED" 25 assert store.read()[0]["content"] == "Task" 26 27 def test_write_deduplicates_duplicate_ids(self): 28 store = TodoStore() 29 result = store.write([ 30 {"id": "1", "content": "First version", "status": "pending"}, 31 {"id": "2", "content": "Other task", "status": "pending"}, 32 {"id": "1", "content": "Latest version", "status": "in_progress"}, 33 ]) 34 assert result == [ 35 {"id": "2", "content": "Other task", "status": "pending"}, 36 {"id": "1", "content": "Latest version", "status": "in_progress"}, 37 ] 38 39 40 class TestHasItems: 41 def test_empty_store(self): 42 store = TodoStore() 43 assert store.has_items() is False 44 45 def test_non_empty_store(self): 46 store = TodoStore() 47 store.write([{"id": "1", "content": "x", "status": "pending"}]) 48 assert store.has_items() is True 49 50 51 class TestFormatForInjection: 52 def test_empty_returns_none(self): 53 store = TodoStore() 54 assert store.format_for_injection() is None 55 56 def test_non_empty_has_markers(self): 57 store = TodoStore() 58 store.write([ 59 {"id": "1", "content": "Do thing", "status": "completed"}, 60 {"id": "2", "content": "Next", "status": "pending"}, 61 {"id": "3", "content": "Working", "status": "in_progress"}, 62 ]) 63 text = store.format_for_injection() 64 # Completed items are filtered out of injection 65 assert "[x]" not in text 66 assert "Do thing" not in text 67 # Active items are included 68 assert "[ ]" in text 69 assert "[>]" in text 70 assert "Next" in text 71 assert "Working" in text 72 assert "context compression" in text.lower() 73 74 75 class TestMergeMode: 76 def test_update_existing_by_id(self): 77 store = TodoStore() 78 store.write([ 79 {"id": "1", "content": "Original", "status": "pending"}, 80 ]) 81 store.write( 82 [{"id": "1", "status": "completed"}], 83 merge=True, 84 ) 85 items = store.read() 86 assert len(items) == 1 87 assert items[0]["status"] == "completed" 88 assert items[0]["content"] == "Original" 89 90 def test_merge_appends_new(self): 91 store = TodoStore() 92 store.write([{"id": "1", "content": "First", "status": "pending"}]) 93 store.write( 94 [{"id": "2", "content": "Second", "status": "pending"}], 95 merge=True, 96 ) 97 items = store.read() 98 assert len(items) == 2 99 100 101 class TestTodoToolFunction: 102 def test_read_mode(self): 103 store = TodoStore() 104 store.write([{"id": "1", "content": "Task", "status": "pending"}]) 105 result = json.loads(todo_tool(store=store)) 106 assert result["summary"]["total"] == 1 107 assert result["summary"]["pending"] == 1 108 109 def test_write_mode(self): 110 store = TodoStore() 111 result = json.loads(todo_tool( 112 todos=[{"id": "1", "content": "New", "status": "in_progress"}], 113 store=store, 114 )) 115 assert result["summary"]["in_progress"] == 1 116 117 def test_no_store_returns_error(self): 118 result = json.loads(todo_tool()) 119 assert "error" in result