95 lines
4.3 KiB
Python
95 lines
4.3 KiB
Python
"""A13: >100-line method inventory (17 items, checkable in code).
|
||
|
||
The split summary's section 4 listed 16 >100-line methods; the
|
||
missing 17th is ``FullAutoMixin._full_auto_execute``
|
||
(``cloud/handler_fullauto.py:182-304``, 123 lines). This test
|
||
pins the full 17-method list by AST over ``cloud/handler_*.py``
|
||
plus ``cloud/server.py`` -- no external summary document is the
|
||
source of truth, the code itself is.
|
||
|
||
Reconcile re-pin (code-to10-reconcile): the unified line keeps
|
||
the target's 6-mixin split, so 16 of the 17 methods live in
|
||
``cloud/server.py`` (``CloudControlPlaneHandler``) rather than in
|
||
the source line's lifecycle/core/admin/browser/webhook mixins;
|
||
the method NAMES are the same 17, only their homes differ, and
|
||
no method was split or dropped to reach this list. The
|
||
module-level >100-line definition likewise lives in
|
||
``cloud/server.py`` (``migrate_tasks_table``, 114 lines) on this
|
||
line, not in ``handler_support.py``.
|
||
|
||
Counting rule, stated because a naive AST count gives 18:
|
||
the 17 are class methods. The 18th >100-line definition,
|
||
``server.migrate_tasks_table`` (module-level function,
|
||
not a mixin method), is asserted separately as the ONLY
|
||
module-level >100-line definition, so the 17/18 difference is
|
||
explained, not hidden. No method is split by this batch:
|
||
internal splitting stays at 0 items.
|
||
"""
|
||
|
||
import ast
|
||
import unittest
|
||
from pathlib import Path
|
||
|
||
EXPECTED_METHODS = {
|
||
("server.py", "CloudControlPlaneHandler._task_pr"),
|
||
("server.py", "CloudControlPlaneHandler._metrics"),
|
||
("server.py", "CloudControlPlaneHandler._browser_stream"),
|
||
("server.py", "CloudControlPlaneHandler._create_task"),
|
||
("server.py", "CloudControlPlaneHandler._create_followup"),
|
||
("handler_fullauto.py", "FullAutoMixin._full_auto_execute"),
|
||
("server.py", "CloudControlPlaneHandler._task_thread_read"),
|
||
("server.py", "CloudControlPlaneHandler._deliver_to_thread"),
|
||
("server.py", "CloudControlPlaneHandler._task_wait"),
|
||
("server.py", "CloudControlPlaneHandler._merge_task"),
|
||
("server.py", "CloudControlPlaneHandler._loop_run"),
|
||
("server.py", "CloudControlPlaneHandler._release_task"),
|
||
("server.py", "CloudControlPlaneHandler._continue_task"),
|
||
("server.py", "CloudControlPlaneHandler._handle_github_webhook"),
|
||
("server.py", "CloudControlPlaneHandler._dispatch_task_route"),
|
||
("server.py", "CloudControlPlaneHandler._dispatch"),
|
||
("server.py", "CloudControlPlaneHandler._dispatch_project"),
|
||
# 演练注:main 侧 _routing_shadow(233 行)为第 18 个长方法;
|
||
# 另 2 个 main 侧新增方法均 <=100 行,不进清单。
|
||
("server.py", "CloudControlPlaneHandler._routing_shadow"),
|
||
}
|
||
|
||
|
||
class LongFuncInventoryTestCase(unittest.TestCase):
|
||
def test_eighteen_long_methods_including_full_auto_execute(self):
|
||
cloud_dir = Path(__file__).resolve().parents[1]
|
||
methods = set()
|
||
module_funcs = set()
|
||
for path in sorted(cloud_dir.glob("handler_*.py")) + [
|
||
cloud_dir / "server.py"]:
|
||
tree = ast.parse(path.read_text(encoding="utf-8"))
|
||
for node in tree.body:
|
||
if isinstance(node, ast.ClassDef):
|
||
for member in node.body:
|
||
if isinstance(member, (ast.FunctionDef,
|
||
ast.AsyncFunctionDef)):
|
||
lines = (member.end_lineno
|
||
- member.lineno + 1)
|
||
if lines > 100:
|
||
methods.add(
|
||
(path.name,
|
||
"%s.%s" % (node.name, member.name)))
|
||
elif isinstance(node, (ast.FunctionDef,
|
||
ast.AsyncFunctionDef)):
|
||
lines = node.end_lineno - node.lineno + 1
|
||
if lines > 100:
|
||
module_funcs.add((path.name, node.name))
|
||
self.assertEqual(len(EXPECTED_METHODS), 18)
|
||
self.assertIn(
|
||
("handler_fullauto.py", "FullAutoMixin._full_auto_execute"),
|
||
EXPECTED_METHODS)
|
||
self.assertEqual(methods, EXPECTED_METHODS)
|
||
# The single non-method >100-line definition, documented
|
||
# rather than silently dropped from the count.
|
||
self.assertEqual(
|
||
module_funcs,
|
||
{("server.py", "migrate_tasks_table")})
|
||
|
||
|
||
if __name__ == "__main__":
|
||
unittest.main()
|