Files
gitea-dashboard/tests/test_exporter.py
sylvain 2ef7ec175e 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>
2026-03-12 19:16:06 +01:00

141 lines
4.5 KiB
Python

"""Tests for JSON exporter module."""
import json
from gitea_dashboard.exporter import export_json, repos_to_dicts
from tests.helpers import make_repo as _make_repo
class TestReposToDicts:
"""Test repos_to_dicts function."""
def test_basic_conversion(self):
"""Converts a RepoData to dict with correct values."""
repo = _make_repo(name="test-repo", open_issues=5)
result = repos_to_dicts([repo])
assert len(result) == 1
assert result[0]["name"] == "test-repo"
assert result[0]["open_issues"] == 5
def test_empty_list(self):
"""Empty input returns empty list."""
assert repos_to_dicts([]) == []
def test_preserves_all_fields(self):
"""All RepoData fields are present in the output dict."""
repo = _make_repo(
name="full",
full_name="admin/full",
description="desc",
open_issues=2,
is_fork=True,
is_archived=False,
is_mirror=True,
latest_release={"tag_name": "v1.0", "published_at": "2026-01-01"},
milestones=[{"title": "v2.0"}],
last_commit_date="2026-03-10T00:00:00Z",
)
result = repos_to_dicts([repo])
d = result[0]
expected_fields = [
"name",
"full_name",
"description",
"open_issues",
"is_fork",
"is_archived",
"is_mirror",
"latest_release",
"milestones",
"last_commit_date",
]
for field in expected_fields:
assert field in d, f"Missing field: {field}"
class TestSanitizeControlChars:
"""Test control character sanitization in export."""
def test_export_json_sanitizes_control_chars(self):
"""Description with control chars (0x00, 0x01, 0x02) produces valid JSON without them."""
repo = _make_repo(description="hello\x00\x01\x02world")
output = export_json([repo])
parsed = json.loads(output)
assert parsed[0]["description"] == "helloworld"
def test_export_json_preserves_newlines_tabs(self):
"""Newlines and tabs are preserved in JSON export (they are valid JSON escapes)."""
repo = _make_repo(description="line1\nline2\ttab")
output = export_json([repo])
parsed = json.loads(output)
assert parsed[0]["description"] == "line1\nline2\ttab"
def test_export_json_unicode_safe(self):
"""Description with emojis and accents produces valid JSON."""
repo = _make_repo(description="Projet avec accents : e, a et emojis 🚀🎉")
output = export_json([repo])
parsed = json.loads(output)
assert "🚀" in parsed[0]["description"]
assert "accents" in parsed[0]["description"]
def test_sanitize_name_and_full_name(self):
"""Control chars in name and full_name fields are also sanitized."""
repo = _make_repo(name="test\x00repo", full_name="admin/test\x01repo")
result = repos_to_dicts([repo])
assert result[0]["name"] == "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:
"""Test export_json function."""
def test_valid_json(self):
"""Output is valid JSON (json.loads does not raise)."""
repos = [_make_repo(name="repo-a"), _make_repo(name="repo-b")]
output = export_json(repos)
parsed = json.loads(output)
assert isinstance(parsed, list)
assert len(parsed) == 2
def test_indented(self):
"""JSON output is indented by default."""
repos = [_make_repo()]
output = export_json(repos)
# Indented JSON has newlines and spaces
assert "\n" in output
assert " " in output
def test_empty_list(self):
"""Empty repo list produces '[]'."""
output = export_json([])
assert json.loads(output) == []