Skip to content

Commit b4168a0

Browse files
committed
feat: add readme automation, with tests
1 parent d9b3ed8 commit b4168a0

6 files changed

Lines changed: 169 additions & 18 deletions

File tree

github_sync/readme.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ def generate(self, stats) -> Path:
2828

2929
latest = stats.get("last_problem")
3030

31-
# ---------- Languages ----------
3231
language_lines = []
3332

3433
for language, count in sorted(
@@ -40,7 +39,17 @@ def generate(self, stats) -> Path:
4039

4140
languages = "\n".join(language_lines)
4241

43-
# ---------- Latest Problem ----------
42+
recent = ""
43+
44+
for problem in stats.get(
45+
"recent_problems",
46+
[],
47+
):
48+
recent += (
49+
f'- {problem["id"]} '
50+
f'{problem["title"]}\n'
51+
)
52+
4453
if latest:
4554
latest_problem = f"""
4655
| Field | Value |
@@ -83,6 +92,12 @@ def generate(self, stats) -> Path:
8392
8493
{languages}
8594
95+
## 📚 Recent Accepted Problems
96+
97+
{recent}
98+
99+
---
100+
86101
✨ Features
87102
Automatic LeetCode synchronization
88103
Automatic Git commits

github_sync/statistics.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def _create_default(self):
2626
"medium": 0,
2727
"hard": 0,
2828
"languages": {},
29+
"recent_problems": [],
2930
"last_problem": None,
3031
"last_sync": None,
3132
}
@@ -61,7 +62,7 @@ def save(self, stats):
6162

6263
def update(self, profile, detail):
6364
"""
64-
Update statistics using latest profile and submission.
65+
Update repository statistics.
6566
"""
6667

6768
stats = self.load()
@@ -76,6 +77,7 @@ def update(self, profile, detail):
7677
stats["medium"] = solved.get("Medium", 0)
7778
stats["hard"] = solved.get("Hard", 0)
7879

80+
7981
language = detail.language_verbose
8082

8183
languages = stats.get("languages", {})
@@ -86,15 +88,36 @@ def update(self, profile, detail):
8688

8789
stats["languages"] = languages
8890

89-
stats["last_problem"] = {
91+
92+
latest = {
9093
"id": detail.question_id,
9194
"title": detail.title_slug.replace("-", " ").title(),
9295
"language": detail.language_verbose,
9396
"runtime": detail.runtime_display,
9497
"memory": detail.memory_display,
9598
}
9699

97-
stats["last_sync"] = datetime.now().isoformat()
100+
stats["last_problem"] = latest
101+
102+
103+
recent = stats.get("recent_problems", [])
104+
105+
recent.insert(
106+
0,
107+
{
108+
"id": detail.question_id,
109+
"title": detail.title_slug.replace("-", " ").title(),
110+
},
111+
)
112+
113+
114+
stats["recent_problems"] = recent[:5]
115+
116+
# ---------- Last sync ----------
117+
118+
stats["last_sync"] = datetime.now().strftime(
119+
"%Y-%m-%d %H:%M:%S"
120+
)
98121

99122
self.save(stats)
100123

tests/conftest.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ def sample_submission():
1515

1616

1717
@pytest.fixture
18-
def sample_submission_detail():
18+
def sample_submission_detail(sample_detail):
1919
"""
20-
Sample submission detail.
20+
Alias for backward compatibility.
2121
"""
22-
22+
return sample_detail
23+
@pytest.fixture
24+
def sample_detail():
2325
return SubmissionDetail(
2426
submission_id="2051842379",
2527
question_id="295",
@@ -31,11 +33,13 @@ def sample_submission_detail():
3133
memory=41264000,
3234
memory_display="41.3 MB",
3335
status_code=10,
34-
code=("class MedianFinder:\n" " pass\n"),
36+
code="print('hello')",
3537
timestamp=1782879665,
3638
)
3739

3840

41+
42+
3943
@pytest.fixture
4044
def temp_solution_dir(tmp_path):
4145
"""

tests/test_readme.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from github_sync.readme import ReadmeGenerator
2+
3+
4+
def test_generate(tmp_path):
5+
generator = ReadmeGenerator()
6+
7+
generator.readme = tmp_path / "README.md"
8+
9+
stats = {
10+
"total": 121,
11+
"easy": 63,
12+
"medium": 52,
13+
"hard": 6,
14+
"languages": {
15+
"Python3": 121,
16+
},
17+
"last_problem": {
18+
"id": "295",
19+
"title": "Find Median From Data Stream",
20+
"language": "Python3",
21+
"runtime": "177 ms",
22+
"memory": "41.3 MB",
23+
},
24+
"recent_problems": [
25+
{
26+
"id": "295",
27+
"title": "Find Median From Data Stream",
28+
}
29+
],
30+
"last_sync": "2026-07-02 10:00:00",
31+
}
32+
33+
path = generator.generate(stats)
34+
35+
assert path.exists()
36+
37+
content = path.read_text(
38+
encoding="utf-8"
39+
)
40+
41+
assert "LeetCode Sync" in content
42+
43+
assert "Find Median From Data Stream" in content
44+
45+
assert "Python3" in content

tests/test_statistics.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import json
2+
3+
from github_sync.statistics import StatisticsManager
4+
5+
6+
def test_create_default(tmp_path):
7+
manager = StatisticsManager()
8+
9+
manager.stats_file = tmp_path / "stats.json"
10+
11+
manager._create_default()
12+
13+
assert manager.stats_file.exists()
14+
15+
16+
def test_load_default(tmp_path):
17+
manager = StatisticsManager()
18+
19+
manager.stats_file = tmp_path / "stats.json"
20+
21+
manager._create_default()
22+
23+
stats = manager.load()
24+
25+
assert stats["total"] == 0
26+
assert stats["languages"] == {}
27+
assert stats["recent_problems"] == []
28+
29+
30+
def test_save(tmp_path):
31+
manager = StatisticsManager()
32+
33+
manager.stats_file = tmp_path / "stats.json"
34+
35+
manager._create_default()
36+
37+
stats = manager.load()
38+
39+
stats["total"] = 100
40+
41+
manager.save(stats)
42+
43+
loaded = manager.load()
44+
45+
assert loaded["total"] == 100
46+
47+
48+
def test_update(sample_detail):
49+
manager = StatisticsManager()
50+
51+
profile = {
52+
"submitStatsGlobal": {
53+
"acSubmissionNum": [
54+
{"difficulty": "All", "count": 121},
55+
{"difficulty": "Easy", "count": 63},
56+
{"difficulty": "Medium", "count": 52},
57+
{"difficulty": "Hard", "count": 6},
58+
]
59+
}
60+
}
61+
62+
stats = manager.update(
63+
profile,
64+
sample_detail,
65+
)
66+
67+
assert stats["total"] == 121
68+
69+
assert stats["last_problem"]["id"] == sample_detail.question_id
70+
71+
assert stats["languages"]["Python3"] >= 1

tests/test_sync_manager.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,7 @@ def test_sync_manager_run(
5151

5252
manager.downloader.download = MagicMock()
5353

54-
manager.git.add = MagicMock()
55-
56-
manager.git.commit = MagicMock()
57-
58-
manager.git.push = MagicMock()
54+
manager.git.sync = MagicMock()
5955

6056
manager.detector.update = MagicMock()
6157

@@ -69,11 +65,8 @@ def test_sync_manager_run(
6965

7066
manager.downloader.download.assert_called_once()
7167

72-
manager.git.add.assert_called_once()
73-
74-
manager.git.commit.assert_called_once()
7568

76-
manager.git.push.assert_called_once()
69+
manager.git.sync.assert_called_once()
7770

7871
manager.detector.update.assert_called_once()
7972

0 commit comments

Comments
 (0)