Files
gitea-dashboard/tests/test_exporter.py
sylvain ebf72c9a56 test(v1.4.0-p2): add failing tests for milestones and columns
RED phase: 5 tests in test_collector.py (collect_milestones),
10 tests in test_display.py (render_milestones, parse_columns),
2 tests in test_exporter.py (milestones JSON), 7 tests in
test_cli.py (--milestones, --columns).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 03:46:09 +01:00

169 lines
5.4 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) == []
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) == []