265 lines
9.0 KiB
Python
265 lines
9.0 KiB
Python
"""
|
|
Test script to verify lazy proxy behavior for theGrifo1553.
|
|
|
|
This script verifies that:
|
|
1. The proxy does NOT initialize hardware at import time
|
|
2. The proxy supports all operations used in production code
|
|
3. The mock can still replace sys.modules successfully
|
|
|
|
Run this before and after changes to verify compatibility.
|
|
|
|
Usage:
|
|
# Test without hardware (should not fail on import)
|
|
python test_lazy_proxy.py --check-import
|
|
|
|
# Test that all operations are supported
|
|
python test_lazy_proxy.py --check-api
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
|
|
# Add test environment paths (same as __init__.py)
|
|
LIB_DIR = os.path.join(os.path.dirname(__file__), '..', 'env')
|
|
sys.path.insert(0, LIB_DIR)
|
|
sys.path.insert(0, os.path.join(LIB_DIR, 'site-packages'))
|
|
|
|
def test_import_no_hardware():
|
|
"""Verify that import does NOT require hardware."""
|
|
print("=" * 80)
|
|
print("TEST 1: Import without hardware initialization")
|
|
print("=" * 80)
|
|
|
|
# Mock the interpreter module to prevent immediate hardware access
|
|
import types
|
|
import warnings
|
|
warnings.filterwarnings('ignore') # Suppress warnings during test
|
|
|
|
# Create minimal mock for interpreter
|
|
mock_interpreter = types.ModuleType('interpreter')
|
|
sys.modules['interpreter'] = mock_interpreter
|
|
|
|
# Also mock potential missing stdlib modules
|
|
for missing_mod in ['uu']:
|
|
if missing_mod not in sys.modules:
|
|
sys.modules[missing_mod] = types.ModuleType(missing_mod)
|
|
|
|
# Import should succeed now
|
|
try:
|
|
# Clear any previous imports
|
|
if 'leo_grifo_1553' in sys.modules:
|
|
del sys.modules['leo_grifo_1553']
|
|
if 'leo_grifo_common' in sys.modules:
|
|
del sys.modules['leo_grifo_common']
|
|
if 'leo_grifo_core' in sys.modules:
|
|
del sys.modules['leo_grifo_core']
|
|
|
|
from leo_grifo_1553 import theGrifo1553
|
|
print("✓ Import successful - no hardware initialization triggered")
|
|
print(f" theGrifo1553 type: {type(theGrifo1553).__name__}")
|
|
print(f" theGrifo1553 repr: {repr(theGrifo1553)}")
|
|
|
|
# Check that instance is not yet initialized
|
|
if hasattr(theGrifo1553, '_instance'):
|
|
if theGrifo1553._instance is None:
|
|
print("✓ Proxy is lazy - real instance not yet created")
|
|
print(" Hardware connection will be made only on first method call")
|
|
success = True
|
|
else:
|
|
print("✗ WARNING: Real instance already created at import!")
|
|
print(" This means hardware connection happens at import time!")
|
|
print(" The lazy loading is NOT working correctly.")
|
|
success = False
|
|
else:
|
|
print("✓ theGrifo1553 does not expose _instance (might be replaced by mock)")
|
|
success = True
|
|
|
|
# Clean up mocks
|
|
for mod in ['interpreter', 'uu']:
|
|
if mod in sys.modules:
|
|
del sys.modules[mod]
|
|
|
|
return success
|
|
except ImportError as e:
|
|
print(f"✗ FAIL: Import failed with: {e}")
|
|
print("\n NOTE: Some dependencies are missing in this Python environment.")
|
|
print(" This test cannot verify lazy loading without all dependencies.")
|
|
print(" Run this test in the production environment with PlatformSimulator.")
|
|
return False
|
|
except Exception as e:
|
|
print(f"✗ FAIL: Unexpected error: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return False
|
|
|
|
|
|
def test_api_compatibility():
|
|
"""Verify that proxy supports all operations used in production code."""
|
|
print("\n")
|
|
print("=" * 80)
|
|
print("TEST 2: API compatibility checks (no actual hardware calls)")
|
|
print("=" * 80)
|
|
|
|
try:
|
|
from leo_grifo_1553 import theGrifo1553
|
|
|
|
# Check that key methods/attributes exist
|
|
api_methods = ['check', 'get', 'set', 'getInterface', 'run']
|
|
|
|
print("\nChecking API methods availability (using dir()):")
|
|
available = dir(theGrifo1553)
|
|
|
|
missing = []
|
|
for method in api_methods:
|
|
if method in available:
|
|
print(f" ✓ {method} - available")
|
|
else:
|
|
print(f" ✗ {method} - MISSING")
|
|
missing.append(method)
|
|
|
|
if missing:
|
|
print(f"\n✗ FAIL: Missing methods: {missing}")
|
|
return False
|
|
|
|
# Check hasattr (used by mock)
|
|
print("\nChecking hasattr() support:")
|
|
for method in api_methods:
|
|
result = hasattr(theGrifo1553, method)
|
|
if result:
|
|
print(f" ✓ hasattr(theGrifo1553, '{method}') = True")
|
|
else:
|
|
print(f" ✗ hasattr(theGrifo1553, '{method}') = False")
|
|
|
|
# Check truthiness
|
|
print("\nChecking truthiness:")
|
|
if theGrifo1553:
|
|
print(" ✓ bool(theGrifo1553) = True")
|
|
else:
|
|
print(" ✗ bool(theGrifo1553) = False (unexpected)")
|
|
|
|
# Check passability as parameter (type check)
|
|
print("\nChecking usability as parameter:")
|
|
|
|
def dummy_function(interface):
|
|
"""Dummy function that accepts interface parameter."""
|
|
return interface is not None
|
|
|
|
result = dummy_function(theGrifo1553)
|
|
if result:
|
|
print(" ✓ Can be passed as parameter")
|
|
else:
|
|
print(" ✗ Cannot be passed as parameter")
|
|
|
|
print("\n✓ All API compatibility checks passed")
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"\n✗ FAIL: API check failed with: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return False
|
|
|
|
|
|
def test_mock_compatibility():
|
|
"""Verify that mock can replace sys.modules successfully."""
|
|
print("\n")
|
|
print("=" * 80)
|
|
print("TEST 3: Mock replacement compatibility")
|
|
print("=" * 80)
|
|
|
|
try:
|
|
import types
|
|
|
|
# Simulate what the mock does
|
|
print("\nSimulating mock module injection...")
|
|
|
|
# Create fake mock module
|
|
class FakeMockInterface:
|
|
def __init__(self):
|
|
self.is_mock = True
|
|
|
|
def check(self, *args, **kwargs):
|
|
return True, None, None
|
|
|
|
def get(self, *args, **kwargs):
|
|
return "mock_value", None
|
|
|
|
def set(self, *args, **kwargs):
|
|
return True, None
|
|
|
|
def getInterface(self):
|
|
return self
|
|
|
|
def run(self, enable):
|
|
pass
|
|
|
|
# Replace sys.modules (like setup_simulation does)
|
|
mock_leo_grifo_1553 = types.ModuleType('leo_grifo_1553')
|
|
mock_leo_grifo_1553.theGrifo1553 = FakeMockInterface()
|
|
original_module = sys.modules.get('leo_grifo_1553')
|
|
sys.modules['leo_grifo_1553'] = mock_leo_grifo_1553
|
|
|
|
print(" ✓ Mock module injected into sys.modules")
|
|
|
|
# Re-import should get mock
|
|
from leo_grifo_1553 import theGrifo1553
|
|
|
|
print(f" theGrifo1553 type after mock: {type(theGrifo1553)}")
|
|
|
|
# Check if it's the mock
|
|
if hasattr(theGrifo1553, 'is_mock') and theGrifo1553.is_mock:
|
|
print(" ✓ Re-import successfully retrieved mock object")
|
|
else:
|
|
print(" ✗ Re-import did NOT get mock (got original)")
|
|
|
|
# Test mock methods work
|
|
result = theGrifo1553.check("test")
|
|
print(f" ✓ Mock method call successful: check() returned {result}")
|
|
|
|
# Restore original module
|
|
if original_module:
|
|
sys.modules['leo_grifo_1553'] = original_module
|
|
print(" ✓ Original module restored")
|
|
|
|
print("\n✓ Mock compatibility test passed")
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"\n✗ FAIL: Mock compatibility test failed: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return False
|
|
|
|
|
|
def main():
|
|
"""Run all tests based on command line arguments."""
|
|
if len(sys.argv) < 2 or '--check-import' in sys.argv:
|
|
success1 = test_import_no_hardware()
|
|
|
|
if not success1:
|
|
sys.exit(1)
|
|
|
|
if len(sys.argv) < 2 or '--check-api' in sys.argv:
|
|
success2 = test_api_compatibility()
|
|
success3 = test_mock_compatibility()
|
|
|
|
if not (success2 and success3):
|
|
sys.exit(1)
|
|
|
|
print("\n")
|
|
print("=" * 80)
|
|
print("ALL TESTS PASSED ✓")
|
|
print("=" * 80)
|
|
print("\nThe lazy proxy implementation:")
|
|
print(" ✓ Does not initialize hardware at import time")
|
|
print(" ✓ Supports all API methods used in production code")
|
|
print(" ✓ Is compatible with mock module injection")
|
|
print("\nYou can now safely run:")
|
|
print(" - Production mode: python GRIFO_M_PBIT.py (on target reale)")
|
|
print(" - Simulation mode: python GRIFO_M_PBIT.py --simulate")
|
|
print()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|