Skip to content

Commit c2cfd2f

Browse files
olehermanseclaude
andcommitted
format.py: Added unit tests and docstrings
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Ole Herman Schumacher Elgesem <ole.elgesem@northern.tech>
1 parent 6c40b04 commit c2cfd2f

2 files changed

Lines changed: 94 additions & 0 deletions

File tree

src/cfengine_cli/format.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,17 @@ def update_previous(self, node):
5050

5151

5252
def stringify_children_from_strings(parts):
53+
"""Join pre-extracted string tokens into a formatted parameter list.
54+
55+
Used when formatting bundle/body headers. Comments are
56+
stripped from the parameter_list node before this function is called,
57+
so `parts` contains only the structural tokens: "(", identifiers, ","
58+
separators, and ")". The function removes any trailing comma before
59+
")", then joins the tokens with appropriate spacing (space after each
60+
comma, no space after "(" or before ")").
61+
62+
Example: ["(", "a", ",", "b", ",", ")"] -> "(a, b)"
63+
"""
5364
# Remove trailing comma before closing paren
5465
cleaned = []
5566
for i, part in enumerate(parts):
@@ -69,6 +80,19 @@ def stringify_children_from_strings(parts):
6980

7081

7182
def stringify_children(children):
83+
"""Join a list of tree-sitter nodes into a single-line string.
84+
85+
Operates on the direct child nodes of a CFEngine syntax construct
86+
(e.g. a list, call, or attribute). Each child is recursively
87+
flattened via stringify_single_line(). Spacing rules:
88+
- A space is inserted after each "," separator.
89+
- A space is inserted before and after "=>" (fat arrow).
90+
- No extra space otherwise (e.g. no space after "(" or before ")").
91+
92+
Used by stringify_single_line() to recursively flatten any node with
93+
children, and by maybe_split_generic_list() to attempt a single-line
94+
rendering before falling back to multi-line splitting.
95+
"""
7296
result = ""
7397
previous = None
7498
for child in children:

tests/unit/test_format.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from cfengine_cli.format import stringify_children_from_strings, stringify_children
2+
3+
4+
class MockNode:
5+
"""Minimal stand-in for a tree-sitter Node used by stringify_children."""
6+
7+
def __init__(self, node_type, node_text=None, children=None):
8+
self.type = node_type
9+
self.text = node_text.encode("utf-8") if node_text is not None else None
10+
self.children = children or []
11+
12+
def _leaf(node_type, node_text=None):
13+
return MockNode(node_type, node_text or node_type)
14+
15+
def test_stringify_children_from_strings():
16+
assert stringify_children_from_strings([]) == ""
17+
assert stringify_children_from_strings(["foo"]) == "foo"
18+
assert stringify_children_from_strings(["(", "a", ")"]) == "(a)"
19+
assert stringify_children_from_strings(["(", "a", ",", "b", ")"]) == "(a, b)"
20+
assert stringify_children_from_strings(["(", "a", ",", ")"]) == "(a)"
21+
assert (
22+
stringify_children_from_strings(["(", "a", ",", "b", ",", ")"])
23+
== "(a, b)"
24+
)
25+
assert stringify_children_from_strings(["a", "b", "c"]) == "a b c"
26+
assert stringify_children_from_strings(["a", ",", "b"]) == "a, b"
27+
assert stringify_children_from_strings(["(", ")"]) == "()"
28+
parts = ["(", "x", ",", "y", ",", "z", ")"]
29+
assert stringify_children_from_strings(parts) == "(x, y, z)"
30+
31+
def test_stringify_children():
32+
assert stringify_children([]) == ""
33+
assert stringify_children([_leaf("identifier", "foo")]) == "foo"
34+
35+
nodes = [_leaf("string", '"a"'), _leaf(","), _leaf("string", '"b"')]
36+
assert stringify_children(nodes) == '"a", "b"'
37+
38+
nodes = [_leaf("identifier", "lval"), _leaf("=>"), _leaf("string", '"rval"')]
39+
assert stringify_children(nodes) == 'lval => "rval"'
40+
41+
nodes = [_leaf("("), _leaf("identifier", "x"), _leaf(")")]
42+
assert stringify_children(nodes) == "(x)"
43+
44+
nodes = [
45+
_leaf("{"),
46+
_leaf("string", '"a"'),
47+
_leaf(","),
48+
_leaf("string", '"b"'),
49+
_leaf("}"),
50+
]
51+
assert stringify_children(nodes) == '{"a", "b"}'
52+
nodes = [
53+
_leaf("identifier", "package_name"),
54+
_leaf("=>"),
55+
_leaf("string", '"nginx"'),
56+
]
57+
58+
assert stringify_children(nodes) == 'package_name => "nginx"'
59+
inner = MockNode(
60+
"call",
61+
children=[
62+
_leaf("calling_identifier", "func"),
63+
_leaf("("),
64+
_leaf("string", '"arg"'),
65+
_leaf(")"),
66+
],
67+
)
68+
69+
nodes = [_leaf("identifier", "x"), _leaf("=>"), inner]
70+
assert stringify_children(nodes) == 'x => func("arg")'

0 commit comments

Comments
 (0)