test: add edge case tests for unicode, empty repos, malformed API

Add tests for unicode descriptions, repos with no commits and no
release, malformed JSON responses, HTML responses, control characters
in names, empty and very long descriptions.

fixes #13

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
sylvain
2026-03-12 19:16:06 +01:00
parent b40dea32f4
commit 2ef7ec175e
4 changed files with 114 additions and 0 deletions

View File

@@ -287,6 +287,41 @@ class TestGetWithRetry429:
assert mock_sleep.call_count == 2 assert mock_sleep.call_count == 2
class TestGetPaginatedEdgeCases:
"""Test edge cases for API responses."""
def _make_client(self):
return GiteaClient("http://gitea.local:3000", "tok")
def test_get_paginated_malformed_json(self):
"""Response with invalid JSON raises JSONDecodeError."""
import json
client = self._make_client()
mock_resp = MagicMock()
mock_resp.raise_for_status = MagicMock()
mock_resp.json.side_effect = json.JSONDecodeError("Expecting value", "", 0)
with patch.object(client.session, "get", return_value=mock_resp):
with pytest.raises(json.JSONDecodeError):
client._get_paginated("/api/v1/user/repos")
def test_get_repos_html_response(self):
"""HTML response (status 200 but HTML content) raises on json parsing."""
import json
client = self._make_client()
mock_resp = MagicMock()
mock_resp.raise_for_status = MagicMock()
mock_resp.json.side_effect = json.JSONDecodeError(
"Expecting value", "<html>Maintenance</html>", 0
)
with patch.object(client.session, "get", return_value=mock_resp):
with pytest.raises(json.JSONDecodeError):
client.get_repos()
class TestGetLatestCommit: class TestGetLatestCommit:
"""Test get_latest_commit method.""" """Test get_latest_commit method."""

View File

@@ -178,6 +178,40 @@ class TestCollectAllLastCommit:
assert result[0].last_commit_date is None assert result[0].last_commit_date is None
class TestRepoDataEdgeCases:
"""Test RepoData with edge case data."""
def test_repo_data_unicode_description(self):
"""RepoData with full unicode description (accents, CJK, emojis)."""
repo = RepoData(
name="unicode-test",
full_name="admin/unicode-test",
description="Projet avec accents : e, a, u, CJK: 中文, emojis: 🚀🎉",
open_issues=0,
is_fork=False,
is_archived=False,
is_mirror=False,
latest_release=None,
milestones=[],
last_commit_date=None,
)
assert "🚀" in repo.description
assert "中文" in repo.description
def test_collect_all_repo_zero_commits_and_no_release(self):
"""Repo with no commits AND no release produces valid RepoData."""
client = MagicMock()
client.get_repos.return_value = [_make_repo()]
client.get_latest_release.return_value = None
client.get_milestones.return_value = []
client.get_latest_commit.return_value = None
result = collect_all(client)
assert result[0].last_commit_date is None
assert result[0].latest_release is None
class TestCollectAllFiltering: class TestCollectAllFiltering:
"""Test collect_all filtering (include/exclude).""" """Test collect_all filtering (include/exclude)."""

View File

@@ -230,6 +230,31 @@ class TestRenderDashboardEmpty:
assert "Aucun repo" in output assert "Aucun repo" in output
class TestRenderDashboardEdgeCases:
"""Test edge cases for dashboard rendering."""
def test_render_dashboard_unicode_description(self):
"""Repo with unicode description renders without crash."""
console, buf = _make_console()
repos = [_make_repo(name="unicode", description="Projet 🚀 avec accents eaiu 中文")]
render_dashboard(repos, console=console)
output = buf.getvalue()
assert "unicode" in output
def test_render_dashboard_control_chars_in_name(self):
"""Repo with control characters in name renders without crash."""
console, buf = _make_console()
repos = [_make_repo(name="test\x00repo")]
render_dashboard(repos, console=console)
output = buf.getvalue()
# Rich may strip or display the control char, but must not crash
assert "test" in output
class TestColorizeMilestoneDue: class TestColorizeMilestoneDue:
"""Test _colorize_milestone_due function.""" """Test _colorize_milestone_due function."""

View File

@@ -93,6 +93,26 @@ class TestSanitizeControlChars:
assert result[0]["full_name"] == "admin/testrepo" assert result[0]["full_name"] == "admin/testrepo"
class TestExportJsonEdgeCases:
"""Test edge cases for JSON export."""
def test_export_json_empty_description(self):
"""Empty description produces valid JSON."""
repo = _make_repo(description="")
output = export_json([repo])
parsed = json.loads(output)
assert parsed[0]["description"] == ""
def test_export_json_very_long_description(self):
"""Very long description (10000 chars) produces valid JSON."""
repo = _make_repo(description="x" * 10000)
output = export_json([repo])
parsed = json.loads(output)
assert len(parsed[0]["description"]) == 10000
class TestExportJson: class TestExportJson:
"""Test export_json function.""" """Test export_json function."""