Files
RustNotMC/tests/test_roadmap.py
SashegDev 874b6f20c2 Клиент: начальный импорт кодовой базы
Основа — Horizon (MIT). История апстрима не переносится: этот репозиторий ведёт свою.
2026-10-29 22:04:28 +03:00

240 lines
9.8 KiB
Python

import copy
import datetime
import json
import tomllib
import unittest
from unittest import mock
from tools import roadmap
SAMPLE = '''[overview]
today_plain = "a"
today_dev = "b"
help_plain = "c"
help_dev = "d"
[[area]]
id = "performance"
name = "Performance"
# ---- Now
[[item]]
id = "fast"
title = "Fast"
status = "now"
area = "performance"
focus = true
plain = "Faster."
dev = """Multiply, \\
not divide (#10)."""
links = ["#10"]
[[item]]
id = "faster"
title = "Faster"
status = "now"
area = "performance"
focus = true
plain = "Even faster."
dev = "More (#11)."
links = ["#11", "#12"]
[[item]]
id = "fastest"
title = "Fastest"
status = "now"
area = "performance"
focus = true
ongoing = true
plain = "The fastest."
dev = "Most (#13)."
links = ["#13"]
# ---- Shipped
[[item]]
id = "old"
title = "Old"
status = "shipped"
shipped_in = "v0.2.1"
area = "performance"
plain = "Done."
dev = "Done (#1)."
links = ["#1"]
'''
def pull(state, merged_at=None, paths=("crates/horizon-client/src/game.rs",)):
return {"kind": "PullRequest", "state": state, "merged_at": merged_at, "merge_commit": "abc" if merged_at else None,
"paths": list(paths)}
def issue(state):
return {"kind": "Issue", "state": state, "merged_at": None, "merge_commit": None, "paths": []}
class RepositoryRoadmap(unittest.TestCase):
def test_the_roadmap_keeps_its_rules(self):
self.assertEqual(roadmap.validate(roadmap.load()), [])
def test_generated_files_match_the_toml(self):
for path, text in roadmap.outputs(roadmap.load()).items():
self.assertEqual(path.read_text(), text, f"{path.name} is out of date: run `python3 tools/roadmap.py build`")
def test_site_data_has_every_item_in_one_line_text(self):
data = json.loads(roadmap.site_data(tomllib.loads(SAMPLE)))
self.assertEqual([item["id"] for item in data["items"]], ["fast", "faster", "fastest", "old"])
self.assertEqual(data["items"][0]["dev"], "Multiply, not divide (#10).")
self.assertEqual(data["areas"], [{"id": "performance", "name": "Performance"}])
class Rules(unittest.TestCase):
def setUp(self):
self.data = tomllib.loads(SAMPLE)
def problems(self, **changes):
data = copy.deepcopy(self.data)
data["item"][0].update(changes)
return roadmap.validate(data)
def test_the_sample_is_valid(self):
self.assertEqual(roadmap.validate(self.data), [])
def test_unknown_status_area_and_key(self):
self.assertTrue(any("status" in p for p in self.problems(status="soon")))
self.assertTrue(any("area" in p for p in self.problems(area="nowhere")))
self.assertTrue(any("unknown key" in p for p in self.problems(eta="soon")))
def test_plain_fits_a_post(self):
self.assertTrue(any("at most 240" in p for p in self.problems(plain="x" * 241)))
self.assertTrue(any("post" in p for p in self.problems(post="x" * 241)))
def test_shipped_needs_its_release(self):
self.assertTrue(any("shipped_in" in p for p in self.problems(status="shipped", focus=False)))
self.assertTrue(any("only shipped" in p for p in self.problems(shipped_in="v0.2.3")))
self.assertTrue(any("not a release" in p for p in self.problems(status="shipped", focus=False,
shipped_in="soon")))
def test_links_are_issues_urls_or_repository_paths(self):
self.assertEqual(self.problems(links=["#4", "https://playhorizon.dev", "docs/benchmark.md"]), [])
self.assertTrue(any("link" in p for p in self.problems(links=["docs/nothing-here.md"])))
self.assertTrue(any("link" in p for p in self.problems(links=["http://example.com"])))
def test_ids_are_free_anchors_of_the_hub(self):
for taken in ("roadmap", "now", "h-next", "tab-board"):
self.assertTrue(any("taken by the hub page" in p for p in self.problems(id=taken)), taken)
def test_flags_are_true_or_false(self):
self.assertEqual(self.problems(announce=True), [])
self.assertTrue(any("announce is true or false" in p for p in self.problems(announce="yes")))
def test_three_to_five_items_in_focus(self):
self.assertTrue(any("focus" in p for p in self.problems(focus=False)))
def test_no_dates(self):
for text in ("Ready in March.", "Before 2027.", "In Q3.", "Next week.", "In 3 weeks.", "By the end of it."):
self.assertTrue(roadmap.dated(text), text)
for text in ("Coming soon.", "Pull request #2026.", "Java 26.3.", "Mobs march on.", "It may land."):
self.assertIsNone(roadmap.dated(text), text)
self.assertTrue(any("date" in p for p in self.problems(plain="Done in October.")))
class Render(unittest.TestCase):
def test_sections_links_and_the_overview(self):
text = roadmap.render(tomllib.loads(SAMPLE))
self.assertIn("## Now", text)
self.assertIn("## Recently shipped", text)
self.assertNotIn("## Later", text)
self.assertIn("- **Fast**: Faster.", text)
self.assertIn("Multiply, not divide ([#10](https://github.com/horizon-rust/horizon/issues/10)).", text)
# A link the technical text already gives isn't repeated; the others are listed after it.
self.assertIn("More: [#12](https://github.com/horizon-rust/horizon/issues/12)", text)
self.assertIn("- **Old** (v0.2.1): Done.", text)
class GitHubState(unittest.TestCase):
now = datetime.datetime(2030, 1, 20, tzinfo=datetime.timezone.utc)
def test_a_now_item_without_live_pull_requests_is_stale(self):
data = tomllib.loads(SAMPLE)
states = {1: pull("MERGED", "2029-12-01T00:00:00Z"), 10: pull("OPEN"),
11: pull("MERGED", "2029-11-01T00:00:00Z"), 12: issue("OPEN"),
13: pull("MERGED", "2030-01-19T00:00:00Z")}
problems, notes = roadmap.online_problems(data, states, self.now)
self.assertEqual(len(problems), 1)
self.assertIn("faster: stale", problems[0])
self.assertTrue(any("fastest: ongoing" in note for note in notes))
def test_missing_numbers_are_reported(self):
problems, _ = roadmap.online_problems(tomllib.loads(SAMPLE), {}, self.now)
self.assertTrue(any("#10 is neither" in p for p in problems))
class Journal(unittest.TestCase):
def test_weekly_summaries_newest_first_with_their_monday(self):
import tempfile
from pathlib import Path
with tempfile.TemporaryDirectory() as folder:
folder = Path(folder)
(folder / "2026-43.md").write_text("# A week\n\nPlain\nwords.\n\n## Technical\n\nDev (#1).\n")
(folder / "2026-42.md").write_text("# Older\n\nPlain.\n\n## Technical\n\nDev.\n")
(folder / "week-44.md").write_text("# Bad name\n")
(folder / "2026-45.md").write_text("# No technical part\n\nPlain.\n")
entries, problems = roadmap.weeks(folder)
self.assertEqual([e["week"] for e in entries], ["2026-43", "2026-42"])
self.assertEqual(entries[0], {"week": "2026-43", "date": "2026-10-19", "title": "A week",
"plain": "Plain words.", "dev": "Dev (#1)."})
self.assertEqual(len(problems), 2)
class Labels(unittest.TestCase):
def test_creates_updates_and_adds_labels(self):
data = tomllib.loads(SAMPLE)
existing = {"roadmap:fast": {"color": "5B3FD6", "description": "Roadmap, now: Fast"},
"roadmap:faster": {"color": "000000", "description": "old"},
"roadmap:gone": {"color": "000000", "description": ""}}
states = {10: dict(pull("OPEN"), labels=["roadmap:fast"]), 11: dict(pull("OPEN"), labels=[]),
13: dict(pull("MERGED", "2030-01-01T00:00:00Z"), labels=[])}
changes, stale = roadmap.label_changes(data, existing, states)
self.assertEqual([(action, target) for action, target, _ in changes],
[("update", "roadmap:faster"), ("add", 11), ("create", "roadmap:fastest"),
("create", "roadmap:old")])
self.assertEqual(changes[0][2]["color"], "5b3fd6")
self.assertEqual(stale, ["roadmap:gone"])
class Sync(unittest.TestCase):
def test_family_of_a_change(self):
self.assertEqual(roadmap.family(["launcher/src/main.rs"]), "launcher")
self.assertEqual(roadmap.family(["website/src/main.js"]), "website")
self.assertEqual(roadmap.family(["launcher/src/main.rs", "crates/x/src/lib.rs"]), "game")
def test_merged_and_released_items_move_to_the_top_of_shipped(self):
data = tomllib.loads(SAMPLE)
states = {10: pull("MERGED", "2030-01-02T00:00:00Z"), 11: pull("MERGED", "2030-01-03T00:00:00Z"),
12: issue("OPEN"), 13: pull("MERGED", "2030-01-03T00:00:00Z")}
with mock.patch.object(roadmap, "first_release", return_value="v0.2.9") as release:
text, log = roadmap.sync(data, SAMPLE, states)
release.assert_called_once_with("abc", "game")
# "faster" keeps an open issue and "fastest" is ongoing: only "fast" ships.
self.assertEqual(log, ["fast: shipped in v0.2.9"])
new = tomllib.loads(text)
self.assertEqual([item["id"] for item in new["item"]], ["faster", "fastest", "fast", "old"])
fast = new["item"][2]
self.assertEqual((fast["status"], fast["shipped_in"]), ("shipped", "v0.2.9"))
self.assertNotIn("focus", fast)
self.assertEqual(fast["dev"], "Multiply, not divide (#10).")
self.assertIn("# ---- Shipped\n\n[[item]]\nid = \"fast\"", text)
def test_merged_but_unreleased_items_wait(self):
states = {10: pull("MERGED", "2030-01-02T00:00:00Z")}
with mock.patch.object(roadmap, "first_release", return_value=None):
text, log = roadmap.sync(tomllib.loads(SAMPLE), SAMPLE, states)
self.assertEqual(text, SAMPLE)
self.assertEqual(log, ["fast: merged, waiting for a release"])
if __name__ == "__main__":
unittest.main()