186 lines
5.5 KiB
Python
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() |