Skip to content

Commit 68ebdd0

Browse files
committed
claude(scanning-git-for-tils): move tests into subfolders
1 parent dc18f49 commit 68ebdd0

File tree

3 files changed

+265
-228
lines changed

3 files changed

+265
-228
lines changed

tools/claude/config/skills/scanning-git-for-tils/test_pure_functions.py renamed to tools/claude/config/skills/scanning-git-for-tils/git/tests/test_formatting.py

Lines changed: 3 additions & 228 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,20 @@
11
#!/usr/bin/env python3
22
# /// script
33
# requires-python = ">=3.11"
4-
# dependencies = ["pytest", "notion-client", "pydantic", "ruff", "mypy"]
4+
# dependencies = ["pytest"]
55
# ///
6-
"""
7-
Tests for pure functions in TIL workflow scripts.
8-
9-
Run with: uv run test_pure_functions.py
10-
Or: uv run pytest test_pure_functions.py -v
11-
"""
6+
"""Tests for git formatting utilities."""
127

138
from __future__ import annotations
149

1510
import sys
1611
from pathlib import Path
17-
from unittest.mock import patch
1812

1913
# Add parent directory to path for imports
20-
sys.path.insert(0, str(Path(__file__).parent))
14+
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
2115

2216
from git.formatting import format_markdown, format_relative_date, should_skip_commit
2317
from git.types import Commit
24-
from notion.blocks import extract_page_id, markdown_to_blocks
25-
from notion.commits import get_assessed_commits_from_notion
2618

2719

2820
class TestFormatRelativeDate:
@@ -287,223 +279,6 @@ def test_shows_review_status_when_some_already_reviewed(self) -> None:
287279
assert "(1 new, 4 already reviewed)" in result
288280

289281

290-
class TestExtractPageId:
291-
"""Test Notion URL page ID extraction."""
292-
293-
def test_extracts_from_standard_url(self) -> None:
294-
url = "https://www.notion.so/Page-Title-abc123def456"
295-
result = extract_page_id(url)
296-
assert result == "abc123def456"
297-
298-
def test_extracts_from_url_with_query_params(self) -> None:
299-
url = "https://www.notion.so/Page-Title-abc123def456?v=xyz"
300-
result = extract_page_id(url)
301-
assert result == "abc123def456"
302-
303-
def test_extracts_from_short_url(self) -> None:
304-
url = "https://notion.so/abc123def456"
305-
result = extract_page_id(url)
306-
assert result == "abc123def456"
307-
308-
def test_handles_trailing_slash(self) -> None:
309-
url = "https://www.notion.so/Page-Title-abc123def456/"
310-
result = extract_page_id(url)
311-
assert result == "abc123def456"
312-
313-
def test_handles_empty_string(self) -> None:
314-
result = extract_page_id("")
315-
assert result == ""
316-
317-
def test_extracts_uuid_with_dashes(self) -> None:
318-
# Notion IDs can have dashes in UUID format
319-
url = "https://www.notion.so/12345678-90ab-cdef-1234-567890abcdef"
320-
result = extract_page_id(url)
321-
# Should get the whole UUID including trailing segment
322-
assert len(result) > 0
323-
324-
325-
def make_notion_page(commit_hash: str) -> dict:
326-
"""Helper: create a mock Notion page with a commit hash."""
327-
return {
328-
"id": f"page-{commit_hash}",
329-
"url": f"https://notion.so/page-{commit_hash}",
330-
"properties": {"Commit Hash": {"title": [{"plain_text": commit_hash}]}},
331-
}
332-
333-
334-
def make_notion_response(
335-
hashes: list[str], has_more: bool = False, next_cursor: str | None = None
336-
) -> dict:
337-
"""Helper: create a mock Notion SDK response."""
338-
return {
339-
"results": [make_notion_page(h) for h in hashes],
340-
"has_more": has_more,
341-
"next_cursor": next_cursor,
342-
}
343-
344-
345-
def mock_collect_paginated_api(pages: list[dict]) -> list[dict]:
346-
"""Helper: mock collect_paginated_api to return all pages as a flat list."""
347-
all_results: list[dict] = []
348-
for page_response in pages:
349-
all_results.extend(page_response["results"])
350-
return all_results
351-
352-
353-
class TestGetAssessedCommitsFromNotion:
354-
"""Test fetching assessed commits from Notion."""
355-
356-
def test_returns_empty_set_when_no_token(self) -> None:
357-
with patch("notion.commits.get_op_secret", side_effect=RuntimeError("Failed")):
358-
result = get_assessed_commits_from_notion()
359-
assert result == set()
360-
361-
def test_returns_commit_hashes_from_single_page(self) -> None:
362-
with (
363-
patch("notion.commits.get_op_secret", return_value="fake-token"),
364-
patch("notion_client.Client"),
365-
patch("notion_client.helpers.collect_paginated_api") as mock_paginate,
366-
):
367-
pages = [make_notion_response(["abc123", "def456", "ghi789"])]
368-
mock_paginate.return_value = mock_collect_paginated_api(pages)
369-
370-
result = get_assessed_commits_from_notion()
371-
assert result == {"abc123", "def456", "ghi789"}
372-
373-
def test_handles_pagination(self) -> None:
374-
with (
375-
patch("notion.commits.get_op_secret", return_value="fake-token"),
376-
patch("notion_client.Client"),
377-
patch("notion_client.helpers.collect_paginated_api") as mock_paginate,
378-
):
379-
# First page with more results
380-
first_response = make_notion_response(
381-
["abc123", "def456"], has_more=True, next_cursor="cursor-1"
382-
)
383-
# Second page, final
384-
second_response = make_notion_response(["ghi789", "jkl012"], has_more=False)
385-
386-
# collect_paginated_api handles pagination internally, returns all results
387-
pages = [first_response, second_response]
388-
mock_paginate.return_value = mock_collect_paginated_api(pages)
389-
390-
result = get_assessed_commits_from_notion()
391-
assert result == {"abc123", "def456", "ghi789", "jkl012"}
392-
393-
def test_handles_client_error_gracefully(self) -> None:
394-
with (
395-
patch("notion.commits.get_op_secret", return_value="fake-token"),
396-
patch("notion_client.Client") as MockClient,
397-
):
398-
MockClient.side_effect = Exception("Connection error")
399-
400-
result = get_assessed_commits_from_notion()
401-
assert result == set()
402-
403-
def test_handles_query_error_gracefully(self) -> None:
404-
with (
405-
patch("notion.commits.get_op_secret", return_value="fake-token"),
406-
patch("notion_client.Client"),
407-
patch("notion_client.helpers.collect_paginated_api") as mock_paginate,
408-
):
409-
mock_paginate.side_effect = Exception("Query error")
410-
411-
result = get_assessed_commits_from_notion()
412-
assert result == set()
413-
414-
def test_skips_pages_without_commit_hash(self) -> None:
415-
with (
416-
patch("notion.commits.get_op_secret", return_value="fake-token"),
417-
patch("notion_client.Client"),
418-
patch("notion_client.helpers.collect_paginated_api") as mock_paginate,
419-
):
420-
response = {
421-
"results": [
422-
make_notion_page("abc123"),
423-
{ # Empty title
424-
"id": "page-empty",
425-
"url": "https://notion.so/page-empty",
426-
"properties": {"Commit Hash": {"title": []}},
427-
},
428-
make_notion_page("def456"),
429-
],
430-
"has_more": False,
431-
"next_cursor": None,
432-
}
433-
434-
mock_paginate.return_value = mock_collect_paginated_api([response])
435-
436-
result = get_assessed_commits_from_notion()
437-
assert result == {"abc123", "def456"}
438-
439-
440-
class TestMarkdownToBlocks:
441-
"""Test markdown to Notion blocks conversion."""
442-
443-
def test_converts_code_blocks(self) -> None:
444-
markdown = "```python\nprint('hello')\n```"
445-
blocks = markdown_to_blocks(markdown)
446-
447-
assert len(blocks) == 1
448-
assert blocks[0]["type"] == "code"
449-
assert blocks[0]["code"]["language"] == "python"
450-
assert blocks[0]["code"]["rich_text"][0]["text"]["content"] == "print('hello')"
451-
452-
def test_maps_language_aliases(self) -> None:
453-
markdown = "```js\nconsole.log('test')\n```"
454-
blocks = markdown_to_blocks(markdown)
455-
456-
assert blocks[0]["code"]["language"] == "javascript"
457-
458-
def test_converts_headings(self) -> None:
459-
markdown = "# H1\n## H2\n### H3"
460-
blocks = markdown_to_blocks(markdown)
461-
462-
assert len(blocks) == 3
463-
assert blocks[0]["type"] == "heading_1"
464-
assert blocks[1]["type"] == "heading_2"
465-
assert blocks[2]["type"] == "heading_3"
466-
467-
def test_converts_bullet_lists(self) -> None:
468-
markdown = "- Item 1\n- Item 2"
469-
blocks = markdown_to_blocks(markdown)
470-
471-
assert len(blocks) == 2
472-
assert blocks[0]["type"] == "bulleted_list_item"
473-
assert blocks[0]["bulleted_list_item"]["rich_text"][0]["text"]["content"] == "Item 1"
474-
475-
def test_converts_numbered_lists(self) -> None:
476-
markdown = "1. First\n2. Second"
477-
blocks = markdown_to_blocks(markdown)
478-
479-
assert len(blocks) == 2
480-
assert blocks[0]["type"] == "numbered_list_item"
481-
assert blocks[1]["type"] == "numbered_list_item"
482-
483-
def test_converts_paragraphs(self) -> None:
484-
markdown = "This is a paragraph"
485-
blocks = markdown_to_blocks(markdown)
486-
487-
assert len(blocks) == 1
488-
assert blocks[0]["type"] == "paragraph"
489-
assert blocks[0]["paragraph"]["rich_text"][0]["text"]["content"] == "This is a paragraph"
490-
491-
def test_handles_empty_lines(self) -> None:
492-
markdown = "Line 1\n\nLine 2"
493-
blocks = markdown_to_blocks(markdown)
494-
495-
assert len(blocks) == 3
496-
assert blocks[1]["type"] == "paragraph"
497-
assert blocks[1]["paragraph"]["rich_text"] == []
498-
499-
def test_handles_multiline_code_blocks(self) -> None:
500-
markdown = "```python\nline1\nline2\nline3\n```"
501-
blocks = markdown_to_blocks(markdown)
502-
503-
assert len(blocks) == 1
504-
assert "line1\nline2\nline3" in blocks[0]["code"]["rich_text"][0]["text"]["content"]
505-
506-
507282
if __name__ == "__main__":
508283
import pytest
509284

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#!/usr/bin/env python3
2+
# /// script
3+
# requires-python = ">=3.11"
4+
# dependencies = ["pytest"]
5+
# ///
6+
"""Tests for Notion blocks utilities."""
7+
8+
from __future__ import annotations
9+
10+
import sys
11+
from pathlib import Path
12+
13+
# Add parent directory to path for imports
14+
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
15+
16+
from notion.blocks import extract_page_id, markdown_to_blocks
17+
18+
19+
class TestExtractPageId:
20+
"""Test Notion URL page ID extraction."""
21+
22+
def test_extracts_from_standard_url(self) -> None:
23+
url = "https://www.notion.so/Page-Title-abc123def456"
24+
result = extract_page_id(url)
25+
assert result == "abc123def456"
26+
27+
def test_extracts_from_url_with_query_params(self) -> None:
28+
url = "https://www.notion.so/Page-Title-abc123def456?v=xyz"
29+
result = extract_page_id(url)
30+
assert result == "abc123def456"
31+
32+
def test_extracts_from_short_url(self) -> None:
33+
url = "https://notion.so/abc123def456"
34+
result = extract_page_id(url)
35+
assert result == "abc123def456"
36+
37+
def test_handles_trailing_slash(self) -> None:
38+
url = "https://www.notion.so/Page-Title-abc123def456/"
39+
result = extract_page_id(url)
40+
assert result == "abc123def456"
41+
42+
def test_handles_empty_string(self) -> None:
43+
result = extract_page_id("")
44+
assert result == ""
45+
46+
def test_extracts_uuid_with_dashes(self) -> None:
47+
# Notion IDs can have dashes in UUID format
48+
url = "https://www.notion.so/12345678-90ab-cdef-1234-567890abcdef"
49+
result = extract_page_id(url)
50+
# Should get the whole UUID including trailing segment
51+
assert len(result) > 0
52+
53+
54+
class TestMarkdownToBlocks:
55+
"""Test markdown to Notion blocks conversion."""
56+
57+
def test_converts_code_blocks(self) -> None:
58+
markdown = "```python\nprint('hello')\n```"
59+
blocks = markdown_to_blocks(markdown)
60+
61+
assert len(blocks) == 1
62+
assert blocks[0]["type"] == "code"
63+
assert blocks[0]["code"]["language"] == "python"
64+
assert blocks[0]["code"]["rich_text"][0]["text"]["content"] == "print('hello')"
65+
66+
def test_maps_language_aliases(self) -> None:
67+
markdown = "```js\nconsole.log('test')\n```"
68+
blocks = markdown_to_blocks(markdown)
69+
70+
assert blocks[0]["code"]["language"] == "javascript"
71+
72+
def test_converts_headings(self) -> None:
73+
markdown = "# H1\n## H2\n### H3"
74+
blocks = markdown_to_blocks(markdown)
75+
76+
assert len(blocks) == 3
77+
assert blocks[0]["type"] == "heading_1"
78+
assert blocks[1]["type"] == "heading_2"
79+
assert blocks[2]["type"] == "heading_3"
80+
81+
def test_converts_bullet_lists(self) -> None:
82+
markdown = "- Item 1\n- Item 2"
83+
blocks = markdown_to_blocks(markdown)
84+
85+
assert len(blocks) == 2
86+
assert blocks[0]["type"] == "bulleted_list_item"
87+
assert blocks[0]["bulleted_list_item"]["rich_text"][0]["text"]["content"] == "Item 1"
88+
89+
def test_converts_numbered_lists(self) -> None:
90+
markdown = "1. First\n2. Second"
91+
blocks = markdown_to_blocks(markdown)
92+
93+
assert len(blocks) == 2
94+
assert blocks[0]["type"] == "numbered_list_item"
95+
assert blocks[1]["type"] == "numbered_list_item"
96+
97+
def test_converts_paragraphs(self) -> None:
98+
markdown = "This is a paragraph"
99+
blocks = markdown_to_blocks(markdown)
100+
101+
assert len(blocks) == 1
102+
assert blocks[0]["type"] == "paragraph"
103+
assert blocks[0]["paragraph"]["rich_text"][0]["text"]["content"] == "This is a paragraph"
104+
105+
def test_handles_empty_lines(self) -> None:
106+
markdown = "Line 1\n\nLine 2"
107+
blocks = markdown_to_blocks(markdown)
108+
109+
assert len(blocks) == 3
110+
assert blocks[1]["type"] == "paragraph"
111+
assert blocks[1]["paragraph"]["rich_text"] == []
112+
113+
def test_handles_multiline_code_blocks(self) -> None:
114+
markdown = "```python\nline1\nline2\nline3\n```"
115+
blocks = markdown_to_blocks(markdown)
116+
117+
assert len(blocks) == 1
118+
assert "line1\nline2\nline3" in blocks[0]["code"]["rich_text"][0]["text"]["content"]
119+
120+
121+
if __name__ == "__main__":
122+
import pytest
123+
124+
sys.exit(pytest.main([__file__, "-v"]))

0 commit comments

Comments
 (0)