mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-05 13:20:11 +00:00
feat(tools): select progress history by UTC date
This commit is contained in:
1 parent
f88c86bf6c
commit
a441b49334
3 files changed
+48
-2
No files matched your search
@@ -192,6 +192,9 @@ if(BUILD_TESTING)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pr_overlap.py)
|
||||
add_test(NAME pr_labels COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pr_labels.py)
|
||||
add_test(NAME progress_history_date_window COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_progress_history.py HistoryDateWindowTests)
|
||||
set_tests_properties(progress_history_date_window PROPERTIES TIMEOUT 20)
|
||||
add_test(NAME progress_history COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_progress_history.py ProgressHistoryTests)
|
||||
add_test(NAME progress_history_output COMMAND ${Python3_EXECUTABLE}
|
||||
|
||||
@@ -113,11 +113,22 @@ def save_cache(path, signature, commits):
|
||||
temporary.unlink(missing_ok=True)
|
||||
|
||||
|
||||
def collect(ref, cache=None):
|
||||
def utc_day(value):
|
||||
try:
|
||||
if date.fromisoformat(value).isoformat() == value:
|
||||
return value
|
||||
except ValueError:
|
||||
pass
|
||||
raise argparse.ArgumentTypeError("date bounds must be valid YYYY-MM-DD UTC days")
|
||||
|
||||
|
||||
def collect(ref, cache=None, since=None, until=None):
|
||||
signature = cache_signature() if cache is not None else None
|
||||
records = load_cache(cache, signature) if cache is not None else {}
|
||||
points, changed = [], False
|
||||
for day, sha in daily_commits(ref):
|
||||
if (since is not None and day < since) or (until is not None and day > until):
|
||||
continue
|
||||
if sha not in records:
|
||||
records[sha] = measure(sha)
|
||||
changed = True
|
||||
@@ -228,6 +239,8 @@ def page(points):
|
||||
|
||||
def main(argv=None):
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--since", type=utc_day, help="first UTC day to measure, inclusive (YYYY-MM-DD)")
|
||||
parser.add_argument("--until", type=utc_day, help="last UTC day to measure, inclusive (YYYY-MM-DD)")
|
||||
parser.add_argument("output", type=Path)
|
||||
parser.add_argument("--ref", default="HEAD", help="branch or commit whose first-parent history is measured")
|
||||
parser.add_argument("--cache", type=Path, help="reuse per-commit counts while the scanner, ISA list and Python version match")
|
||||
@@ -242,7 +255,9 @@ def main(argv=None):
|
||||
if any(args.cache.resolve() == path.resolve() or
|
||||
(args.cache.exists() and path.exists() and args.cache.samefile(path)) for path in outputs):
|
||||
raise ValueError("history cache must differ from generated reports")
|
||||
points = collect(args.ref, args.cache)
|
||||
if args.since and args.until and args.since > args.until:
|
||||
raise ValueError("--since must not be later than --until")
|
||||
points = collect(args.ref, args.cache, args.since, args.until)
|
||||
except (OSError, ValueError) as error:
|
||||
parser.error(str(error))
|
||||
if not points:
|
||||
|
||||
@@ -67,6 +67,34 @@ class HistoryReportOutputTests(unittest.TestCase):
|
||||
self.assertGreater((output / filename).stat().st_size, 0)
|
||||
|
||||
|
||||
class HistoryDateWindowTests(unittest.TestCase):
|
||||
def test_window_filters_days_before_measurement_and_reuses_cache(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
subprocess.run(["git", "init", "-q", directory], check=True)
|
||||
for day, time, name in (("2026-01-01", "23:59:59Z", "A"), ("2026-01-02", "00:00:00Z", "B"), ("2026-01-02", "23:59:59Z", "C"), ("2026-01-03", "00:00:00Z", "D")):
|
||||
commit(root, day, name, f"int APS5_VABI {name}() {{ return 0; }}\n", time)
|
||||
with patch.multiple(progress, ROOT=root, PRX=root / "core/libs/prx", OPCODES=root / OPCODES):
|
||||
all_days = progress_history.daily_commits("HEAD")
|
||||
expected = [all_days[1][1]]
|
||||
actual_measure = progress_history.measure
|
||||
with patch.object(progress_history, "measure", wraps=actual_measure) as measure:
|
||||
selected = progress_history.collect("HEAD", root / "cache", "2026-01-02", "2026-01-02")
|
||||
self.assertEqual([c.args[0] for c in measure.call_args_list], expected)
|
||||
self.assertEqual([p["date"] for p in selected], ["2026-01-02"])
|
||||
with patch.object(progress_history, "measure", side_effect=AssertionError("cache missed")):
|
||||
self.assertEqual(progress_history.collect("HEAD", root / "cache", "2026-01-02", "2026-01-02"), selected)
|
||||
self.assertEqual(len(progress_history.collect("HEAD", root / "cache")), 3)
|
||||
self.assertEqual(progress_history.collect("HEAD", since="2027-01-01"), [])
|
||||
|
||||
def test_invalid_cli_bounds(self):
|
||||
for options in (("--since", "20260201"), ("--until", "2026-02-30"), ("--since", "2026-02-02", "--until", "2026-02-01")):
|
||||
with self.subTest(options=options), contextlib.redirect_stderr(io.StringIO()), self.assertRaises(SystemExit) as error:
|
||||
progress_history.main(["unused-output", *options])
|
||||
self.assertEqual(error.exception.code, 2)
|
||||
|
||||
|
||||
|
||||
class ProgressHistoryTests(unittest.TestCase):
|
||||
@unittest.skipUnless(os.name == "nt", "requires Windows read-only replacement semantics")
|
||||
def test_readonly_cache_failure_cleans_temporary_and_can_retry(self):
|
||||
|
||||
Reference in new issue
Block a user