Skip to content

Commit d4e86b8

Browse files
committed
gh-131178: add unittest for turtledemo
1 parent d4e5802 commit d4e86b8

File tree

1 file changed

+194
-0
lines changed

1 file changed

+194
-0
lines changed

Lib/test/test_turtledemo.py

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
"""
2+
Test command line interface for turtledemo module.
3+
4+
This test suite validates the CLI functionality of the turtledemo module,
5+
which provides a GUI-based demo viewer for turtle graphics examples.
6+
"""
7+
import sys
8+
import os
9+
import importlib.util
10+
11+
12+
class SimpleTest:
13+
"""Simple test framework to avoid compatibility issues."""
14+
def __init__(self):
15+
self.passed = 0
16+
self.failed = 0
17+
18+
def assert_true(self, condition, msg=""):
19+
if condition:
20+
self.passed += 1
21+
print(f"✓ {msg}")
22+
else:
23+
self.failed += 1
24+
print(f"✗ {msg}")
25+
26+
def assert_equal(self, a, b, msg=""):
27+
if a == b:
28+
self.passed += 1
29+
print(f"✓ {msg}")
30+
else:
31+
self.failed += 1
32+
print(f"✗ {msg}: {a} != {b}")
33+
34+
def assert_in(self, item, container, msg=""):
35+
if item in container:
36+
self.passed += 1
37+
print(f"✓ {msg}")
38+
else:
39+
self.failed += 1
40+
print(f"✗ {msg}: {item} not in {container}")
41+
42+
def assert_is_instance(self, obj, expected_type, msg=""):
43+
if isinstance(obj, expected_type):
44+
self.passed += 1
45+
print(f"✓ {msg}")
46+
else:
47+
self.failed += 1
48+
print(f"✗ {msg}: {type(obj)} != {expected_type}")
49+
50+
def assert_has_attr(self, obj, attr, msg=""):
51+
if hasattr(obj, attr):
52+
self.passed += 1
53+
print(f"✓ {msg}")
54+
else:
55+
self.failed += 1
56+
print(f"✗ {msg}: {attr} not found")
57+
58+
def summary(self):
59+
total = self.passed + self.failed
60+
print(f"\nTest Summary: {self.passed}/{total} passed, {self.failed} failed")
61+
return self.failed == 0
62+
63+
64+
def test_turtledemo_cli():
65+
"""Test command line interface for turtledemo module."""
66+
test = SimpleTest()
67+
68+
print("Testing turtledemo command line interface...")
69+
70+
# Test 1: Check turtledemo directory structure
71+
demo_dir = os.path.join(os.path.dirname(__file__), '..', 'turtledemo')
72+
test.assert_true(os.path.exists(demo_dir), "turtledemo directory exists")
73+
test.assert_true(os.path.isdir(demo_dir), "turtledemo is a directory")
74+
75+
# Test 2: Check __main__.py exists
76+
main_file = os.path.join(demo_dir, '__main__.py')
77+
test.assert_true(os.path.exists(main_file), "__main__.py exists")
78+
79+
# Test 3: Check demo files exist
80+
if os.path.exists(demo_dir):
81+
demo_files = [f for f in os.listdir(demo_dir)
82+
if f.endswith('.py') and not f.startswith('_')]
83+
test.assert_true(len(demo_files) > 0, f"found {len(demo_files)} demo files")
84+
85+
# Check for known demo files
86+
expected_demos = ['bytedesign.py', 'chaos.py', 'clock.py', 'colormixer.py', 'forest.py']
87+
for demo in expected_demos:
88+
test.assert_in(demo, demo_files, f"demo file {demo} exists")
89+
90+
# Test 4: Test module import (may fail due to dependencies)
91+
try:
92+
spec = importlib.util.spec_from_file_location("turtledemo",
93+
os.path.join(demo_dir, '__init__.py'))
94+
if spec and spec.loader:
95+
turtledemo = importlib.util.module_from_spec(spec)
96+
spec.loader.exec_module(turtledemo)
97+
test.assert_true(True, "turtledemo module imported successfully")
98+
else:
99+
test.assert_true(False, "could not create spec for turtledemo")
100+
except Exception as e:
101+
test.assert_true(False, f"turtledemo import failed: {e}")
102+
103+
# Test 5: Test __main__ module structure
104+
try:
105+
main_file = os.path.join(demo_dir, '__main__.py')
106+
with open(main_file, 'r') as f:
107+
content = f.read()
108+
109+
# Check for key functions and classes
110+
test.assert_in('def main():', content, "main function defined")
111+
test.assert_in('class DemoWindow', content, "DemoWindow class defined")
112+
test.assert_in('def getExampleEntries():', content, "getExampleEntries function defined")
113+
test.assert_in('if __name__ == \'__main__\':', content, "__main__ guard present")
114+
115+
# Check for imports
116+
test.assert_in('import sys', content, "sys import present")
117+
test.assert_in('import os', content, "os import present")
118+
test.assert_in('from tkinter import', content, "tkinter import present")
119+
120+
except Exception as e:
121+
test.assert_true(False, f"failed to read __main__.py: {e}")
122+
123+
# Test 6: Test individual demo files structure
124+
demo_files_to_check = ['bytedesign.py', 'chaos.py', 'clock.py']
125+
for demo_file in demo_files_to_check:
126+
demo_path = os.path.join(demo_dir, demo_file)
127+
if os.path.exists(demo_path):
128+
try:
129+
with open(demo_path, 'r') as f:
130+
content = f.read()
131+
test.assert_in('def main():', content, f"{demo_file} has main function")
132+
has_main_guard = ('if __name__ == \'__main__\':' in content or
133+
'if __name__ == "__main__":' in content)
134+
test.assert_true(has_main_guard, f"{demo_file} has __main__ guard")
135+
except Exception as e:
136+
test.assert_true(False, f"failed to read {demo_file}: {e}")
137+
138+
# Test 7: Check configuration files
139+
config_file = os.path.join(demo_dir, 'turtle.cfg')
140+
test.assert_true(os.path.exists(config_file), "turtle.cfg exists")
141+
142+
# Test 8: Test command line execution simulation
143+
try:
144+
# Simulate what happens when running: python -m turtledemo
145+
main_file = os.path.join(demo_dir, '__main__.py')
146+
147+
# Read the file to check it's syntactically valid Python
148+
with open(main_file, 'r') as f:
149+
content = f.read()
150+
151+
# Try to compile it
152+
compile(content, main_file, 'exec')
153+
test.assert_true(True, "__main__.py is valid Python code")
154+
155+
except SyntaxError as e:
156+
test.assert_true(False, f"__main__.py has syntax error: {e}")
157+
except Exception as e:
158+
test.assert_true(False, f"failed to validate __main__.py: {e}")
159+
160+
# Test 9: Check for documentation strings
161+
try:
162+
main_file = os.path.join(demo_dir, '__main__.py')
163+
with open(main_file, 'r') as f:
164+
content = f.read()
165+
166+
# Check for module docstring
167+
test.assert_true(content.startswith('"""') or content.startswith("'''"),
168+
"__main__.py has module docstring")
169+
170+
# Check for function docstrings
171+
test.assert_in('"""', content, "contains docstrings")
172+
173+
except Exception as e:
174+
test.assert_true(False, f"failed to check docstrings: {e}")
175+
176+
# Test 10: Test CLI entry point
177+
try:
178+
# The CLI entry point should be the main() function in __main__.py
179+
main_file = os.path.join(demo_dir, '__main__.py')
180+
with open(main_file, 'r') as f:
181+
content = f.read()
182+
183+
# Check that main() is called when run as script
184+
test.assert_in('main()', content, "main() is called in __main__")
185+
186+
except Exception as e:
187+
test.assert_true(False, f"failed to check CLI entry point: {e}")
188+
189+
return test.summary()
190+
191+
192+
if __name__ == '__main__':
193+
success = test_turtledemo_cli()
194+
sys.exit(0 if success else 1)

0 commit comments

Comments
 (0)