from __future__ import annotations import unittest from scripts.generate_history import load_release_statuses, release_history from scripts.release_lib import ReleaseToolError import json from pathlib import Path import tempfile def gitea_release(tag: str, *, prerelease: bool) -> dict[str, object]: return { "id": 42, "tag_name": tag, "name": f"Release {tag}", "draft": False, "prerelease": prerelease, "published_at": "2026-09-08T12:00:00Z", "html_url": f"https://gitea.example.test/owner/project/releases/tag/{tag}", "assets": [ { "name": "manifest.json", "browser_download_url": ( f"https://gitea.example.test/owner/project/releases/download/" f"{tag}/manifest.json" ), }, { "name": "manifest.json.sig", "browser_download_url": ( f"https://gitea.example.test/owner/project/releases/download/" f"{tag}/manifest.json.sig" ), }, ], } class ReleaseHistoryTests(unittest.TestCase): def test_history_uses_only_installable_immutable_releases(self) -> None: stable = gitea_release("v1.8.0", prerelease=False) beta = gitea_release("v1.9.0-beta.2", prerelease=True) wrong_flag = gitea_release("v2.0.0-beta.1", prerelease=False) draft = gitea_release("v2.0.0", prerelease=False) draft["draft"] = True history = release_history( [stable, wrong_flag, draft, beta], "2026-09-08T12:01:00Z", ) releases = history["releases"] assert isinstance(releases, list) self.assertEqual( [release["version"] for release in releases], ["1.9.0-beta.2", "1.8.0"], ) self.assertEqual(releases[0]["channel"], "prerelease") self.assertEqual(releases[1]["channel"], "stable") self.assertTrue(releases[0]["manifest_url"].endswith("/manifest.json")) def test_history_rejects_an_invalid_generation_timestamp(self) -> None: with self.assertRaisesRegex(ReleaseToolError, "timestamp"): release_history([], "today") def test_history_applies_signed_release_status_overrides(self) -> None: history = release_history( [gitea_release("v1.9.0-beta.2", prerelease=True)], "2026-09-08T12:01:00Z", {"v1.9.0-beta.2": "withdrawn"}, ) releases = history["releases"] assert isinstance(releases, list) self.assertEqual(releases[0]["status"], "withdrawn") self.assertEqual( releases[0]["compatibility"], {"config_schema": 1, "minimum_config_schema": 1}, ) def test_history_supports_explicit_config_compatibility(self) -> None: history = release_history( [gitea_release("v2.0.0", prerelease=False)], "2026-09-08T12:01:00Z", { "v2.0.0": { "status": "active", "config_schema": 3, "minimum_config_schema": 2, } }, ) releases = history["releases"] assert isinstance(releases, list) self.assertEqual( releases[0]["compatibility"], {"config_schema": 3, "minimum_config_schema": 2}, ) def test_status_file_rejects_unknown_fields_and_unsafe_schema_ranges(self) -> None: with tempfile.TemporaryDirectory() as temporary: path = Path(temporary) / "statuses.json" path.write_text( json.dumps( { "schema": 1, "releases": { "v2.0.0": { "status": "active", "config_schema": 1, "minimum_config_schema": 2, } }, } ), encoding="utf-8", ) with self.assertRaisesRegex(ReleaseToolError, "exceeds"): load_release_statuses(path) path.write_text( '{"schema":1,"releases":{"v2.0.0":{"status":"active","note":"x"}}}', encoding="utf-8", ) with self.assertRaisesRegex(ReleaseToolError, "unknown"): load_release_statuses(path) def test_history_rejects_an_unknown_status(self) -> None: with self.assertRaisesRegex(ReleaseToolError, "invalid status"): release_history( [gitea_release("v1.8.0", prerelease=False)], "2026-09-08T12:01:00Z", {"v1.8.0": "broken"}, ) def test_history_rejects_status_override_for_a_missing_release(self) -> None: with self.assertRaisesRegex(ReleaseToolError, "do not match"): release_history( [gitea_release("v1.8.0", prerelease=False)], "2026-09-08T12:01:00Z", {"v1.9.0-beta.1": "withdrawn"}, ) def test_history_rejects_duplicate_release_tags(self) -> None: release = gitea_release("v1.8.0", prerelease=False) with self.assertRaisesRegex(ReleaseToolError, "duplicate"): release_history( [release, dict(release)], "2026-09-08T12:01:00Z", ) if __name__ == "__main__": unittest.main()