McRogueFace/tests/unit/test_stubs.py

186 lines
5.5 KiB
Python

#!/usr/bin/env python3
"""Test that type stubs are correctly formatted and usable."""
import os
import sys
import ast
def test_stub_syntax():
"""Test that the stub file has valid Python syntax."""
stub_path = 'stubs/mcrfpy.pyi'
if not os.path.exists(stub_path):
print(f"ERROR: Stub file not found at {stub_path}")
return False
try:
with open(stub_path, 'r') as f:
content = f.read()
# Parse the stub file
tree = ast.parse(content)
print(f"✓ Stub file has valid Python syntax ({len(content)} bytes)")
# Count definitions
classes = [node for node in ast.walk(tree) if isinstance(node, ast.ClassDef)]
functions = [node for node in ast.walk(tree) if isinstance(node, ast.FunctionDef)]
print(f"✓ Found {len(classes)} class definitions")
print(f"✓ Found {len(functions)} function/method definitions")
# Check for key classes
class_names = {cls.name for cls in classes}
expected_classes = {'Frame', 'Caption', 'Sprite', 'Grid', 'Entity', 'Color', 'Vector', 'Scene', 'Window'}
missing = expected_classes - class_names
if missing:
print(f"✗ Missing classes: {missing}")
return False
else:
print("✓ All expected classes are defined")
# Check for key functions
top_level_funcs = [node.name for node in tree.body if isinstance(node, ast.FunctionDef)]
expected_funcs = {'createScene', 'setScene', 'currentScene', 'find', 'findAll', 'setTimer'}
func_set = set(top_level_funcs)
missing_funcs = expected_funcs - func_set
if missing_funcs:
print(f"✗ Missing functions: {missing_funcs}")
return False
else:
print("✓ All expected functions are defined")
return True
except SyntaxError as e:
print(f"✗ Syntax error in stub file: {e}")
return False
except Exception as e:
print(f"✗ Error parsing stub file: {e}")
return False
def test_type_annotations():
"""Test that type annotations are present and well-formed."""
stub_path = 'stubs/mcrfpy.pyi'
with open(stub_path, 'r') as f:
content = f.read()
# Check for proper type imports
if 'from typing import' not in content:
print("✗ Missing typing imports")
return False
else:
print("✓ Has typing imports")
# Check for Optional usage
if 'Optional[' in content:
print("✓ Uses Optional type hints")
# Check for Union usage
if 'Union[' in content:
print("✓ Uses Union type hints")
# Check for overload usage
if '@overload' in content:
print("✓ Uses @overload decorators")
# Check return type annotations
if '-> None:' in content and '-> int:' in content and '-> str:' in content:
print("✓ Has return type annotations")
else:
print("✗ Missing some return type annotations")
return True
def test_docstrings():
"""Test that docstrings are preserved in stubs."""
stub_path = 'stubs/mcrfpy.pyi'
with open(stub_path, 'r') as f:
content = f.read()
# Count docstrings
docstring_count = content.count('"""')
if docstring_count > 10: # Should have many docstrings
print(f"✓ Found {docstring_count // 2} docstrings")
else:
print(f"✗ Too few docstrings found: {docstring_count // 2}")
# Check for specific docstrings
if 'Core game engine interface' in content:
print("✓ Module docstring present")
if 'A rectangular frame UI element' in content:
print("✓ Frame class docstring present")
if 'Load a sound effect from a file' in content:
print("✓ Function docstrings present")
return True
def test_automation_module():
"""Test that automation module is properly defined."""
stub_path = 'stubs/mcrfpy.pyi'
with open(stub_path, 'r') as f:
content = f.read()
if 'class automation:' in content:
print("✓ automation class defined")
else:
print("✗ automation class missing")
return False
# Check for key automation methods
automation_methods = ['screenshot', 'click', 'moveTo', 'keyDown', 'typewrite']
missing = []
for method in automation_methods:
if f'def {method}' not in content:
missing.append(method)
if missing:
print(f"✗ Missing automation methods: {missing}")
return False
else:
print("✓ All key automation methods defined")
return True
def main():
"""Run all stub tests."""
print("Type Stub Validation Tests")
print("==========================\n")
all_passed = True
print("1. Syntax Test:")
if not test_stub_syntax():
all_passed = False
print()
print("2. Type Annotations Test:")
if not test_type_annotations():
all_passed = False
print()
print("3. Docstrings Test:")
if not test_docstrings():
all_passed = False
print()
print("4. Automation Module Test:")
if not test_automation_module():
all_passed = False
print()
if all_passed:
print("✅ All tests passed! Type stubs are valid and complete.")
sys.exit(0)
else:
print("❌ Some tests failed. Please review the stub file.")
sys.exit(1)
if __name__ == '__main__':
main()