Skip to content

Commit 12ebbae

Browse files
committed
tests
1 parent bbe6a5e commit 12ebbae

11 files changed

Lines changed: 2639 additions & 772 deletions

tests/test_astCommandLine.py

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
"""
2+
Tests for AST command line interface functionality.
3+
Converted and adapted from CPython's ASTMainTests.
4+
"""
5+
6+
import ast
7+
import os
8+
import pytest
9+
import subprocess
10+
import sys
11+
import tempfile
12+
13+
class TestASTCommandLine:
14+
"""Tests for ast module command line interface."""
15+
16+
def testCLIFileInput(self):
17+
"""Test ast module CLI with file input."""
18+
code = "print(1, 2, 3)"
19+
expected = ast.dump(ast.parse(code), indent=3)
20+
21+
with tempfile.TemporaryDirectory() as tmpDir:
22+
filename = os.path.join(tmpDir, "test_module.py")
23+
with open(filename, "w", encoding="utf-8") as fileHandle:
24+
fileHandle.write(code)
25+
26+
# Run python -m ast on the file
27+
result = subprocess.run(
28+
[sys.executable, "-m", "ast", filename],
29+
capture_output=True,
30+
text=True
31+
)
32+
33+
assert result.returncode == 0
34+
assert result.stderr == ""
35+
36+
# Compare output lines (ignoring trailing whitespace)
37+
expectedLines = expected.splitlines()
38+
actualLines = result.stdout.strip().splitlines()
39+
assert expectedLines == actualLines
40+
41+
def testCLIStdinInput(self):
42+
"""Test ast module CLI with stdin input."""
43+
code = "x = 42"
44+
expected = ast.dump(ast.parse(code), indent=3)
45+
46+
# Run python -m ast with stdin input
47+
result = subprocess.run(
48+
[sys.executable, "-m", "ast"],
49+
input=code,
50+
capture_output=True,
51+
text=True
52+
)
53+
54+
assert result.returncode == 0
55+
assert result.stderr == ""
56+
57+
expectedLines = expected.splitlines()
58+
actualLines = result.stdout.strip().splitlines()
59+
assert expectedLines == actualLines
60+
61+
def testCLIWithIndent(self):
62+
"""Test ast module CLI with custom indent."""
63+
code = "def func(): pass"
64+
65+
# Test with different indent levels
66+
for indentLevel in [1, 2, 4]:
67+
result = subprocess.run(
68+
[sys.executable, "-m", "ast", "--indent", str(indentLevel)],
69+
input=code,
70+
capture_output=True,
71+
text=True
72+
)
73+
74+
assert result.returncode == 0
75+
assert result.stderr == ""
76+
77+
# Verify the output uses the specified indent
78+
output = result.stdout
79+
lines = output.splitlines()
80+
81+
# Find an indented line and check its indentation
82+
indentedLines = [line for line in lines if line.startswith(' ')]
83+
if indentedLines:
84+
firstIndentedLine = indentedLines[0]
85+
actualIndent = len(firstIndentedLine) - len(firstIndentedLine.lstrip())
86+
assert actualIndent == indentLevel
87+
def testCLIWithOptimization(self):
88+
"""Test ast module CLI behavior (optimization is internal)."""
89+
code = "1 + 2"
90+
91+
# Test basic functionality - optimization is handled internally
92+
result = subprocess.run(
93+
[sys.executable, "-m", "ast"],
94+
input=code,
95+
capture_output=True,
96+
text=True
97+
)
98+
99+
assert result.returncode == 0
100+
output = result.stdout
101+
102+
# The output should contain the AST representation
103+
assert "Module" in output
104+
assert "body" in output
105+
106+
def testCLIErrorHandling(self):
107+
"""Test ast module CLI error handling."""
108+
# Test with invalid Python code
109+
invalidCode = "def func(\n" # Incomplete function definition
110+
111+
result = subprocess.run(
112+
[sys.executable, "-m", "ast"],
113+
input=invalidCode,
114+
capture_output=True,
115+
text=True
116+
)
117+
118+
# Should exit with error code
119+
assert result.returncode != 0
120+
assert result.stderr != ""
121+
assert "SyntaxError" in result.stderr
122+
123+
def testCLIInvalidFile(self):
124+
"""Test ast module CLI with non-existent file."""
125+
result = subprocess.run(
126+
[sys.executable, "-m", "ast", "non_existent_file.py"],
127+
capture_output=True,
128+
text=True
129+
)
130+
131+
assert result.returncode != 0
132+
assert result.stderr != ""
133+
134+
def testCLIHelpMessage(self):
135+
"""Test ast module CLI help message."""
136+
result = subprocess.run(
137+
[sys.executable, "-m", "ast", "--help"],
138+
capture_output=True,
139+
text=True
140+
)
141+
142+
assert result.returncode == 0
143+
helpOutput = result.stdout
144+
145+
# Check for expected help content
146+
assert "usage:" in helpOutput.lower() or "Usage:" in helpOutput
147+
assert "ast" in helpOutput
148+
assert "--indent" in helpOutput or "-i" in helpOutput
149+
def testCLIMode(self):
150+
"""Test ast module CLI with different parsing modes."""
151+
# Test eval mode
152+
evalCode = "1 + 2"
153+
result = subprocess.run(
154+
[sys.executable, "-m", "ast", "--mode", "eval"],
155+
input=evalCode,
156+
capture_output=True,
157+
text=True
158+
)
159+
160+
assert result.returncode == 0
161+
output = result.stdout
162+
assert "Expression(" in output
163+
164+
# Test exec mode (default)
165+
execCode = "x = 1"
166+
result = subprocess.run(
167+
[sys.executable, "-m", "ast", "--mode", "exec"],
168+
input=execCode,
169+
capture_output=True,
170+
text=True
171+
)
172+
173+
assert result.returncode == 0
174+
output = result.stdout
175+
assert "Module(" in output
176+
177+
def testCLIIncludeAttributes(self):
178+
"""Test ast module CLI with include attributes option."""
179+
code = "x = 42"
180+
181+
# Test with attributes included
182+
result = subprocess.run(
183+
[sys.executable, "-m", "ast", "--include-attributes"],
184+
input=code,
185+
capture_output=True,
186+
text=True
187+
)
188+
189+
assert result.returncode == 0
190+
output = result.stdout
191+
192+
# Should include line numbers and column offsets
193+
assert "lineno=" in output
194+
assert "col_offset=" in output
195+
196+
# Test without attributes (default)
197+
result = subprocess.run(
198+
[sys.executable, "-m", "ast"],
199+
input=code,
200+
capture_output=True,
201+
text=True
202+
)
203+
204+
assert result.returncode == 0
205+
output = result.stdout
206+
207+
# Should not include attributes by default
208+
assert "lineno=" not in output
209+
assert "col_offset=" not in output
210+
211+
212+
class TestASTToolIntegration:
213+
"""Tests for integration with astToolkit functionality."""
214+
215+
def testCLIWithAstToolkitCompatibility(self):
216+
"""Test that CLI output is compatible with astToolkit parsing."""
217+
code = """
218+
def example_function(parameterA, parameterB=None):
219+
\"\"\"Example function for testing.\"\"\"
220+
if parameterA:
221+
return parameterA + (parameterB or 0)
222+
return 0
223+
"""
224+
225+
# Get AST dump from command line
226+
result = subprocess.run(
227+
[sys.executable, "-m", "ast"],
228+
input=code,
229+
capture_output=True,
230+
text=True
231+
)
232+
233+
assert result.returncode == 0
234+
astDump = result.stdout.strip() # Verify the AST output contains expected elements
235+
236+
# The dumps should represent the same AST structure
237+
# (though formatting might differ slightly)
238+
assert "FunctionDef" in astDump
239+
assert "example_function" in astDump
240+
assert "parameterA" in astDump
241+
assert "parameterB" in astDump
242+
243+
def testCLIComplexCode(self):
244+
"""Test CLI with complex Python code structures."""
245+
complexCode = """
246+
class ExampleClass:
247+
\"\"\"Example class with various features.\"\"\"
248+
249+
classAttribute = "value"
250+
251+
def __init__(self, initialValue):
252+
self.instanceValue = initialValue
253+
254+
def methodWithDecorator(self):
255+
@property
256+
def innerProperty(self):
257+
return self.instanceValue
258+
259+
return innerProperty
260+
261+
async def asyncMethod(self):
262+
await some_async_operation()
263+
yield "result"
264+
265+
def methodWithComprehension(self):
266+
return [x**2 for x in range(10) if x % 2 == 0]
267+
268+
try:
269+
example = ExampleClass(42)
270+
result = example.methodWithComprehension()
271+
except Exception as error:
272+
print(f"Error: {error}")
273+
finally:
274+
print("Cleanup complete")
275+
"""
276+
277+
result = subprocess.run(
278+
[sys.executable, "-m", "ast", "--indent", "2"],
279+
input=complexCode,
280+
capture_output=True,
281+
text=True
282+
)
283+
284+
assert result.returncode == 0
285+
output = result.stdout
286+
287+
# Verify key structures are present
288+
assert "ClassDef" in output
289+
assert "ExampleClass" in output
290+
assert "AsyncFunctionDef" in output
291+
assert "ListComp" in output
292+
assert "Try" in output
293+
assert "ExceptHandler" in output

tests/test_astConstant.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
Converted and adapted from CPython's ast module tests.
44
"""
55

6+
from astToolkit import Make
67
import ast
78
import dis
89
import pytest
9-
from astToolkit import Make
10-
1110

1211
class TestConstant:
1312
"""Tests for the Make.Constant node factory method."""

tests/test_astConstructors.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
Converted and adapted from CPython's ast module tests.
44
"""
55

6+
from astToolkit import Make
67
import ast
78
import pytest
89
import warnings
9-
from astToolkit import Make
10-
1110

1211
class TestASTConstructors:
1312
"""Tests for Make factory methods that construct AST nodes."""
@@ -93,7 +92,7 @@ def test_arguments(self):
9392
assert argumentsNode.args == []
9493
assert argumentsNode.vararg is None
9594
assert argumentsNode.kwonlyargs == []
96-
assert argumentsNode.kw_defaults == [None]
95+
assert argumentsNode.kw_defaults == []
9796
assert argumentsNode.kwarg is None
9897
assert argumentsNode.defaults == []
9998

tests/test_astCopy.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1+
from astToolkit import Make
2+
from test.test_ast.snippets import exec_tests
3+
from test.test_ast.utils import to_tuple
14
import ast
25
import copy
36
import pickle
47
import pytest
58
import textwrap
6-
from astToolkit import Make
7-
from test.test_ast.utils import to_tuple
8-
from test.test_ast.snippets import exec_tests
9-
109

1110
class TestCopy:
1211
"""Test copying and pickling AST nodes."""
@@ -83,11 +82,10 @@ def test_copy_make_nodes(self):
8382
# """Test copying nodes with complex nested structures."""
8483
# # Create a function definition with Make
8584
# argA = Make.arg("a", Make.Name("int", ast.Load()))
86-
# argB = Make.arg("b", Make.Name("str", ast.Load()), Make.Constant("default"))
85+
# argB = Make.arg("b", Make.Name("str", ast.Load()))
8786
# argumentsNode = Make.arguments([argA], [], [], [argB], [Make.Constant("default")], None, [])
8887

89-
# returnStmt = Make.Return(Make.BinOp(Make.Name("a", ast.Load()), ast.Add(),
90-
# Make.Constant(1)))
88+
# returnStmt = Make.Return(Make.BinOp(Make.Name("a", ast.Load()), ast.Add(), Make.Constant(1)))
9189
# functionDef = Make.FunctionDef("testFunction", argumentsNode, [returnStmt], [], None)
9290
# moduleNode = Make.Module([functionDef], [])
9391

0 commit comments

Comments
 (0)