import logging import os from unittest.mock import MagicMock, create_autospec import pytest from GramAddict.core.device_facade import DeviceFacade from GramAddict.core.telepathic_engine import TelepathicEngine 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 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) mock.shell.return_value = "" # Ensure SendEventInjector detection gets a string 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.find_best_node.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"): import os import yaml from GramAddict.core.device_facade import create_device 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.behaviors import PluginRegistry from GramAddict.core.goap import GoalExecutor from GramAddict.core.physics.biomechanics import PhysicsBody from GramAddict.core.physics.sendevent_injector import SendEventInjector from GramAddict.core.qdrant_memory import QdrantBase from GramAddict.core.situational_awareness import SituationalAwarenessEngine from GramAddict.core.telepathic_engine import TelepathicEngine TelepathicEngine.reset() GoalExecutor.reset() SituationalAwarenessEngine.reset() PluginRegistry.reset() PhysicsBody.reset() SendEventInjector.reset() QdrantBase._connection_failed_logged = False from GramAddict.core.dojo_engine import DojoEngine if hasattr(DojoEngine, "reset"): DojoEngine.reset() else: DojoEngine._instance = None # 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 # Post-test cleanup PhysicsBody.reset() SendEventInjector.reset() @pytest.fixture(autouse=True) def telepathic_mock(monkeypatch, request): if request.config.getoption("--live") or "e2e" in str(request.node.fspath): # TelepathicEngine is a singleton, allow it to run natively in e2e or live mode 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