Implement P0 of the reaction dashboard: config loading with hot reload, SQLite migrations with backups, single-writer queue, read-only Bilibili fav client, folder import/diff sync, invalid-resource handling, blacklist seed, scheduler, and JSON redacted logging. Includes offline unit and transport-level contract tests; all existing and new tests pass.
58 lines
1.7 KiB
Python
58 lines
1.7 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""build_moves / apply_move 的正确性自测(无需 pytest): python tests/test_moves.py"""
|
||
import os
|
||
import random
|
||
import sys
|
||
|
||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||
sys.stdout.reconfigure(encoding="utf-8")
|
||
|
||
from favsort import apply_move, build_moves, lcs_keep # noqa: E402
|
||
|
||
|
||
def run_case(cur, tgt, label):
|
||
moves = build_moves(cur, tgt)
|
||
work = list(cur)
|
||
for m in moves:
|
||
assert m["pred"] is not None, f"{label}: pred 为空"
|
||
work = apply_move(work, m)
|
||
assert work == tgt, f"{label}: 结果不符\n cur={cur}\n tgt={tgt}\n got={work}"
|
||
lower = len(lcs_keep(cur, tgt))
|
||
# 不追求严格最优(多轮 LCS 会略多于下界),但不能出现病态膨胀
|
||
assert len(moves) <= len(cur) + 8, (
|
||
f"{label}: 步数异常 {len(moves)} (n={len(cur)}, 下界={len(cur) - lower})"
|
||
)
|
||
return len(moves)
|
||
|
||
|
||
def main():
|
||
random.seed(20261031)
|
||
total = 0
|
||
for n in range(1, 13):
|
||
ids = [1000 + i for i in range(n)]
|
||
for _ in range(200):
|
||
cur = ids[:]
|
||
tgt = ids[:]
|
||
random.shuffle(cur)
|
||
random.shuffle(tgt)
|
||
run_case(cur, tgt, f"n={n}")
|
||
total += 1
|
||
|
||
# 头部必须换人的用例
|
||
cases = [
|
||
([3, 2, 1], [1, 2, 3]),
|
||
([5, 4, 3, 2, 1], [1, 2, 3, 4, 5]),
|
||
([2, 3, 1], [1, 2, 3]),
|
||
([4, 1, 2, 3], [1, 2, 3, 4]),
|
||
]
|
||
for cur, tgt in cases:
|
||
run_case(cur, tgt, f"head {cur}->{tgt}")
|
||
|
||
# 已排序不应产生移动
|
||
assert build_moves([1, 2, 3], [1, 2, 3]) == []
|
||
print(f"OK: {total} 个随机用例 + {len(cases)} 个头部用例全部通过")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|