"""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) == [] class TestExportMilestonesJson: """Test milestones JSON export.""" def test_export_milestones_json_basic(self): """MilestoneData list produces valid JSON.""" from gitea_dashboard.collector import MilestoneData from gitea_dashboard.exporter import export_milestones_json milestones = [ MilestoneData("repo", "v1.0", 2, 8, 80, "2026-04-01T00:00:00Z", "open"), ] output = export_milestones_json(milestones) parsed = json.loads(output) assert len(parsed) == 1 assert parsed[0]["repo_name"] == "repo" assert parsed[0]["title"] == "v1.0" assert parsed[0]["progress_pct"] == 80 def test_export_milestones_json_empty(self): """Empty milestone list produces '[]'.""" from gitea_dashboard.exporter import export_milestones_json output = export_milestones_json([]) assert json.loads(output) == []