feat(v1.2.0): retry API, dernier commit, tri, coloration, export JSON
- client.py: _get_with_retry (max 2 retries, backoff lineaire), get_latest_commit - collector.py: champ last_commit_date dans RepoData - display.py: colonne "Dernier commit", _sort_repos (name/issues/release/activity), _colorize_milestone_due (rouge/jaune/vert selon echeance) - cli.py: options --sort/-s et --format/-f (table/json) - exporter.py: nouveau module, repos_to_dicts + export_json - 88 tests (35 nouveaux), ruff clean fixes #8, fixes #7, fixes #10, fixes #9, fixes #6 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
109
tests/test_exporter.py
Normal file
109
tests/test_exporter.py
Normal file
@@ -0,0 +1,109 @@
|
||||
"""Tests for JSON exporter module."""
|
||||
|
||||
import json
|
||||
|
||||
from gitea_dashboard.collector import RepoData
|
||||
from gitea_dashboard.exporter import export_json, repos_to_dicts
|
||||
|
||||
|
||||
def _make_repo(
|
||||
name="my-repo",
|
||||
full_name="admin/my-repo",
|
||||
description="A repo",
|
||||
open_issues=3,
|
||||
is_fork=False,
|
||||
is_archived=False,
|
||||
is_mirror=False,
|
||||
latest_release=None,
|
||||
milestones=None,
|
||||
last_commit_date=None,
|
||||
):
|
||||
"""Build a RepoData for testing."""
|
||||
return RepoData(
|
||||
name=name,
|
||||
full_name=full_name,
|
||||
description=description,
|
||||
open_issues=open_issues,
|
||||
is_fork=is_fork,
|
||||
is_archived=is_archived,
|
||||
is_mirror=is_mirror,
|
||||
latest_release=latest_release,
|
||||
milestones=milestones if milestones is not None else [],
|
||||
last_commit_date=last_commit_date,
|
||||
)
|
||||
|
||||
|
||||
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 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) == []
|
||||
Reference in New Issue
Block a user