import pytest import logging import os from unittest.mock import MagicMock def pytest_addoption(parser): parser.addoption( "--live", action="store_true", default=False, help="run tests against a live ADB device (disable DeviceFacade mocks)" ) MagicMock.app_id = "com.instagram.android" MagicMock._get_current_app = MagicMock(return_value="com.instagram.android") class MockArgs: def __init__(self, **kwargs): for k, v in kwargs.items(): setattr(self, k, v) class MockConfigs: def __init__(self, args): self.args = args from unittest.mock import create_autospec, MagicMock from GramAddict.core.device_facade import DeviceFacade from GramAddict.core.telepathic_engine import TelepathicEngine def create_mock_device(): mock = create_autospec(DeviceFacade, instance=True) mock.app_id = "com.instagram.android" mock.device_id = "test_device" mock.info = {"displayWidth": 1080, "displayHeight": 2400} mock.get_info.return_value = {"displayWidth": 1080, "displayHeight": 2400} mock.cm_to_pixels.side_effect = lambda cm: int(cm * 10) import uuid mock.dump_hierarchy.side_effect = lambda: f"" return mock def create_mock_telepathic_engine(): mock = create_autospec(TelepathicEngine, instance=True) mock.find_best_node.return_value = {"x": 500, "y": 500, "confidence": 0.9} mock.evaluate_profile_vibe.return_value = {"quality_score": 8, "matches_niche": True, "reason": "Mocked positive vibe"} mock.evaluate_grid_visuals.return_value = {"x": 500, "y": 500, "score": 0.99, "semantic": "Mocked matching grid cell", "source": "vlm_grid"} mock._extract_semantic_nodes.return_value = [{"x": 500, "y": 500, "semantic_string": "dummy node"}] return mock @pytest.fixture def mock_logger(): return logging.getLogger("test") @pytest.fixture def device(request): if request.config.getoption("--live"): from GramAddict.core.device_facade import create_device import yaml import os device_id = "emulator-5554" app_id = "com.instagram.android" config_path = "test_config.yml" if os.path.exists(config_path): try: with open(config_path, 'r', encoding='utf-8') as f: config = yaml.safe_load(f) if config: device_id = config.get("device", device_id) app_id = config.get("app-id", app_id) except Exception as e: print(f"⚠️ Warning: Could not load {config_path}: {e}") print(f"🚀 Connecting to live device: {device_id} (App: {app_id})") return create_device(device_id, app_id) return create_mock_device() @pytest.fixture(autouse=True) def reset_singletons(): """Ensure all core engine singletons are fresh for each test.""" from GramAddict.core.telepathic_engine import TelepathicEngine from GramAddict.core.goap import GoalExecutor from GramAddict.core.situational_awareness import SituationalAwarenessEngine TelepathicEngine.reset() GoalExecutor.reset() SituationalAwarenessEngine.reset() # Aggressively wipe on-disk session files to prevent state leakage in tests for f in ["telepathic_memory.json", "telepathic_blacklist.json", "growth_brain_memory.json", "gramaddict_nav_map.json", "l2_channels_cache.json"]: if os.path.exists(f): try: os.remove(f) except Exception: pass yield @pytest.fixture(autouse=True) def telepathic_mock(monkeypatch, request): if request.config.getoption("--live"): # TelepathicEngine is a singleton, allow it to run natively return None import GramAddict.core.telepathic_engine engine = create_mock_telepathic_engine() monkeypatch.setattr(GramAddict.core.telepathic_engine.TelepathicEngine, "get_instance", lambda: engine) return engine @pytest.fixture def mock_cognitive_stack(): stack = { "dopamine": MagicMock(), "darwin": MagicMock(), "resonance": MagicMock(), "active_inference": MagicMock(), "growth_brain": MagicMock(), "swarm": MagicMock(), "radome": MagicMock(), "nav_graph": MagicMock(), "zero_engine": MagicMock(), "crm": MagicMock(), "telepathic": create_mock_telepathic_engine() } stack["radome"].sanitize_xml.side_effect = lambda x: x return stack