/
/
/
1"""Tests for the method-ordering check."""
2
3import ast
4
5from scripts.check_method_order import _class_violations, _is_private, main
6
7
8def _first_class(source: str) -> ast.ClassDef:
9 """Return the first ``ast.ClassDef`` node in a source snippet."""
10 return next(node for node in ast.walk(ast.parse(source)) if isinstance(node, ast.ClassDef))
11
12
13def _names(source: str) -> list[str]:
14 """Return the names of the misplaced methods in the first class of a snippet."""
15 return [name for _lineno, name in _class_violations(_first_class(source))]
16
17
18def test_is_private_classification() -> None:
19 """Underscore-prefixed non-dunder names are private; dunders and public names are not."""
20 assert _is_private("_helper") is True
21 assert _is_private("__mangled") is True
22 assert _is_private("__init__") is False
23 assert _is_private("__repr__") is False
24 assert _is_private("public") is False
25
26
27def test_public_below_private_is_flagged() -> None:
28 """A public method defined after a private one is reported."""
29 source = (
30 "class C:\n"
31 " def public_a(self): ...\n"
32 " def _helper(self): ...\n"
33 " def public_b(self): ...\n"
34 )
35 assert _names(source) == ["public_b"]
36
37
38def test_dunder_below_private_is_flagged() -> None:
39 """A dunder defined after a private method is reported (dunders belong at the top)."""
40 source = "class C:\n def _helper(self): ...\n def __repr__(self): ...\n"
41 assert _names(source) == ["__repr__"]
42
43
44def test_private_methods_at_bottom_is_clean() -> None:
45 """Public and dunder methods above private methods produce no violations."""
46 source = (
47 "class C:\n"
48 " def __init__(self): ...\n"
49 " def public(self): ...\n"
50 " def _helper_a(self): ...\n"
51 " def _helper_b(self): ...\n"
52 )
53 assert _names(source) == []
54
55
56def test_nested_function_is_ignored() -> None:
57 """A function nested inside a method does not affect the class ordering check."""
58 source = (
59 "class C:\n"
60 " def _helper(self):\n"
61 " def inner(): ...\n"
62 " return inner\n"
63 " def public(self): ...\n"
64 )
65 assert _names(source) == ["public"]
66
67
68def test_real_tree_matches_baseline() -> None:
69 """The shipped tree has no misplaced methods beyond the grandfathered baseline."""
70 assert main([]) == 0
71