diff --git a/tests/README.md b/tests/README.md index 1911a3c..e0d2333 100644 --- a/tests/README.md +++ b/tests/README.md @@ -10,6 +10,21 @@ This directory contains all test scripts for the HereIAm application. - `test_logging.py` - Tests logging configuration - `test_restart.py` - Tests application restart functionality +### Mouse Movement & PyAutoGUI Tests +- `test_pyautogui_permissions.py` - Comprehensive PyAutoGUI permissions and functionality test +- `test_mouse_behavior.py` - Tests basic mouse movement monitoring behavior +- `test_original_logic.py` - Tests the original mouse.py script logic +- `test_enhanced_mouse.py` - Tests enhanced mouse movement with additional features +- `test_fixed_mouse_logic.py` - Tests the fixed mouse movement logic +- `test_updated_logic.py` - Tests updated mouse movement detection logic + +### UI & Integration Tests +- `test_visual_dialog.py` - Visual test for options dialog +- `test_startup.py` - Tests launch agent functionality + +### Debug Tools +- `debug_mouse_detection.py` - Debug tool for mouse movement detection issues + ### Shell Scripts - `test_app.sh` - Tests the built macOS application bundle diff --git a/tests/debug_mouse_detection.py b/tests/debug_mouse_detection.py new file mode 100644 index 0000000..a313bdb --- /dev/null +++ b/tests/debug_mouse_detection.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +""" +Debug script to test mouse movement detection +""" + +import sys +import os +import time + +# Add src directory to path +sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'src')) + +import pyautogui +from logging_config import setup_logging, get_logger + +def test_mouse_detection(): + """Test mouse movement detection logic""" + setup_logging(debug=True) + logger = get_logger(__name__) + + print("πŸ§ͺ Testing Mouse Movement Detection") + print("========================================") + print("Move your mouse around and watch the detection...") + print("Press Ctrl+C to stop") + print("") + + # Initialize position tracking + xold, yold = pyautogui.position() + print(f"Initial position: ({xold}, {yold})") + + movement_threshold = 2 + countdown = 30 # 30 second test countdown + + try: + while countdown > 0: + x, y = pyautogui.position() + + # Calculate movement + x_diff = abs(x - xold) if xold is not None else movement_threshold + 1 + y_diff = abs(y - yold) if yold is not None else movement_threshold + 1 + + if x_diff <= movement_threshold and y_diff <= movement_threshold: + # Mouse is idle + print(f"⏸️ IDLE: pos=({x},{y}), last=({xold},{yold}), diff=({x_diff},{y_diff}), countdown={countdown}") + countdown -= 1 + else: + # Mouse moved + print(f"🐭 MOVED: pos=({x},{y}), last=({xold},{yold}), diff=({x_diff},{y_diff}), TIMER RESET!") + countdown = 30 # Reset for testing + xold = x + yold = y + + time.sleep(1) + + except KeyboardInterrupt: + print("\n⏹️ Test stopped by user") + + print("βœ… Test completed!") + +if __name__ == "__main__": + test_mouse_detection() diff --git a/tests/test_enhanced_mouse.py b/tests/test_enhanced_mouse.py new file mode 100644 index 0000000..1019fb3 --- /dev/null +++ b/tests/test_enhanced_mouse.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +""" +Quick test to verify the enhanced mouse movement behavior +""" + +import sys +import os + +# Add src directory to path +sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'src')) + +from mouse_mover import MouseMover +from logging_config import setup_logging, get_logger +import time + +def quick_test(): + """Quick test of mouse movement""" + setup_logging(debug=True) + logger = get_logger(__name__) + + print("πŸ§ͺ Quick Mouse Movement Test") + print("========================================") + + # Create mouse mover with very short wait time for testing + mouse_mover = MouseMover(wait_time=5, move_px=15) # 5 second wait, 15px movement + + print("Testing enhanced mouse movement...") + print("Mouse should move automatically every 5 seconds when idle") + print("This includes: vertical movement, wiggle, and F15 key press") + print("Watch the console for debug messages...") + print("") + + try: + mouse_mover.start() + + # Let it run for 30 seconds + for i in range(30): + status = mouse_mover.get_status() + print(f"⏱️ Time: {i}s, Countdown: {status['countdown']}s") + time.sleep(1) + + except KeyboardInterrupt: + print("\n⏹️ Interrupted by user") + finally: + mouse_mover.stop() + print("βœ… Test completed!") + +if __name__ == "__main__": + quick_test() diff --git a/tests/test_fixed_mouse_logic.py b/tests/test_fixed_mouse_logic.py new file mode 100644 index 0000000..dc1ac84 --- /dev/null +++ b/tests/test_fixed_mouse_logic.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +""" +Test the fixed mouse movement detection logic +""" + +import sys +import os +import time + +# Add src directory to path +sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'src')) + +from mouse_mover import MouseMover +from logging_config import setup_logging, get_logger + +def test_fixed_mouse_logic(): + """Test the updated mouse movement logic""" + setup_logging(debug=True) + logger = get_logger(__name__) + + print("πŸ§ͺ Testing Fixed Mouse Movement Logic") + print("========================================") + print("This should now behave like your original mouse.py script") + print("- Mouse movement should reset the timer immediately") + print("- Uses the same OR logic: (x == xold or y == yold)") + print("- Only updates yold, keeps xold at 0") + print("") + print("Starting with 30-second timer for testing...") + print("Move your mouse to test timer reset") + print("Press Ctrl+C to stop") + print("") + + # Create mouse mover with short wait time for testing + mouse_mover = MouseMover(wait_time=30, move_px=15) # 30 second wait for testing + + try: + mouse_mover.start() + + # Let it run and monitor + for i in range(60): # Run for 1 minute max + status = mouse_mover.get_status() + print(f"⏱️ Time: {i:2d}s, Countdown: {status['countdown']:2d}s, Running: {status['running']}") + time.sleep(1) + + # If countdown gets very low, the user isn't moving the mouse + if status['countdown'] <= 5: + print("πŸ”₯ Timer about to expire! Move your mouse to reset it!") + + except KeyboardInterrupt: + print("\n⏹️ Test interrupted by user") + finally: + mouse_mover.stop() + print("βœ… Test completed!") + print("") + print("If timer reset properly when you moved the mouse, the fix is working!") + +if __name__ == "__main__": + test_fixed_mouse_logic() diff --git a/tests/test_mouse_behavior.py b/tests/test_mouse_behavior.py new file mode 100644 index 0000000..13594be --- /dev/null +++ b/tests/test_mouse_behavior.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +""" +Test script to compare mouse movement behavior +""" + +import sys +import os +import time + +# Add src directory to path +sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'src')) + +from mouse_mover import MouseMover +from logging_config import setup_logging, get_logger + +def test_mouse_movement(): + """Test the mouse movement behavior""" + setup_logging(debug=True) + logger = get_logger(__name__) + + print("πŸ§ͺ Testing Mouse Movement Behavior") + print("========================================") + + # Create mouse mover with short wait time for testing + mouse_mover = MouseMover(wait_time=10, move_px=10) # 10 second wait for testing + + print("Starting mouse movement monitoring...") + print("Watch for automatic mouse movement every 10 seconds when idle") + print("Move your mouse to reset the timer") + print("Press Ctrl+C to stop") + + try: + mouse_mover.start() + + # Monitor for a while + for i in range(60): # Run for 1 minute + status = mouse_mover.get_status() + print(f"Status: Running={status['running']}, Countdown={status['countdown']}s") + time.sleep(1) + + except KeyboardInterrupt: + print("\nStopping...") + finally: + mouse_mover.stop() + print("Test completed!") + +if __name__ == "__main__": + test_mouse_movement() diff --git a/tests/test_original_logic.py b/tests/test_original_logic.py new file mode 100644 index 0000000..bde3f24 --- /dev/null +++ b/tests/test_original_logic.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +""" +Test to understand the original mouse.py logic exactly +""" + +import time +import pyautogui + +def test_original_logic(): + """Test the exact logic from the original mouse.py script""" + print("πŸ§ͺ Testing Original mouse.py Logic") + print("=====================================") + print("This simulates exactly what your original script does") + print("Move your mouse and watch the behavior...") + print("Press Ctrl+C to stop") + print("") + + WAITTIME = 30 # 30 seconds for testing + countdown = WAITTIME + + xold = 0 + yold = 0 + + try: + iteration = 0 + while True: + iteration += 1 + x, y = pyautogui.position() + + print(f"\n--- Iteration {iteration} ---") + print(f"Current position: ({x}, {y})") + print(f"Previous: xold={xold}, yold={yold}") + + if countdown <= 0: + print("πŸ”₯ TIMER EXPIRED - Would move mouse here") + countdown = WAITTIME + print(f"Timer reset to {WAITTIME}") + continue + + # The key condition from your original script + if x == xold or y == yold: + print(f"πŸ’€ IDLE DETECTED: (x=={xold}) = {x==xold}, (y=={yold}) = {y==yold}") + print(f"Countdown: {countdown}") + countdown -= 1 + time.sleep(1) + else: + print(f"🐭 MOVEMENT DETECTED: Mouse moved from ({xold}, {yold}) to ({x}, {y})") + print(f"Timer RESET from {countdown} to {WAITTIME}") + countdown = WAITTIME + yold = y # Only update yold! + print(f"Updated yold to {yold}, xold stays {xold}") + + except KeyboardInterrupt: + print("\n⏹️ Test stopped by user") + + print("βœ… Test completed!") + +if __name__ == "__main__": + test_original_logic() diff --git a/tests/test_pyautogui_permissions.py b/tests/test_pyautogui_permissions.py new file mode 100644 index 0000000..c466f83 --- /dev/null +++ b/tests/test_pyautogui_permissions.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +""" +Diagnostic script to test PyAutoGUI permissions and functionality +Run this both from VS Code and from the built app to compare behavior +""" + +import sys +import os + +# Add src directory to path when run from tests folder +if os.path.exists('../src'): + sys.path.insert(0, '../src') +elif os.path.exists('src'): + sys.path.insert(0, 'src') + +def test_pyautogui_permissions(): + """Test PyAutoGUI functionality and permissions""" + print("πŸ” PyAutoGUI Permissions Diagnostic") + print("=====================================") + + try: + import pyautogui + print("βœ… PyAutoGUI imported successfully") + except ImportError as e: + print(f"❌ Failed to import PyAutoGUI: {e}") + return + + # Test 1: Get mouse position + print("\nπŸ“ Test 1: Getting mouse position") + try: + x, y = pyautogui.position() + print(f"βœ… Current mouse position: ({x}, {y})") + except Exception as e: + print(f"❌ Failed to get mouse position: {e}") + print(" This indicates accessibility permission issues") + return + + # Test 2: Screen size + print("\nπŸ“ Test 2: Getting screen size") + try: + width, height = pyautogui.size() + print(f"βœ… Screen size: {width}x{height}") + except Exception as e: + print(f"❌ Failed to get screen size: {e}") + + # Test 3: Small mouse movement + print("\n🐭 Test 3: Small mouse movement") + try: + original_x, original_y = pyautogui.position() + print(f"Original position: ({original_x}, {original_y})") + + # Move mouse 1 pixel + pyautogui.moveRel(1, 0, duration=0.1) + new_x, new_y = pyautogui.position() + print(f"After move: ({new_x}, {new_y})") + + # Move back + pyautogui.moveRel(-1, 0, duration=0.1) + final_x, final_y = pyautogui.position() + print(f"After return: ({final_x}, {final_y})") + + if new_x != original_x or new_y != original_y: + print("βœ… Mouse movement successful!") + else: + print("❌ Mouse movement failed - position didn't change") + print(" This indicates the app doesn't have permission to control the mouse") + except Exception as e: + print(f"❌ Failed to move mouse: {e}") + print(" This indicates accessibility permission issues") + + # Test 4: Key press + print("\n⌨️ Test 4: Key press (F15)") + try: + pyautogui.press('f15') + print("βœ… Key press successful (F15 sent)") + except Exception as e: + print(f"❌ Failed to send key press: {e}") + + # Test 5: Check running environment + print("\nπŸ”§ Test 5: Environment information") + print(f"Python executable: {sys.executable}") + print(f"Running from: {os.getcwd()}") + print(f"Script path: {__file__ if '__file__' in globals() else 'Unknown'}") + + if getattr(sys, 'frozen', False): + print("🎁 Running as PyInstaller bundle") + print(f"Bundle path: {sys._MEIPASS}") + else: + print("🐍 Running as Python script") + + # Test 6: Recommendations + print("\nπŸ’‘ Recommendations:") + print("1. Check System Preferences > Privacy & Security > Accessibility") + print("2. Ensure the app (or Terminal/VS Code) has accessibility permissions") + print("3. If running from built app, try self-signing:") + print(" codesign --force --deep --sign - /path/to/HereIAm.app") + print("4. Check Console.app for any security-related error messages") + +if __name__ == "__main__": + test_pyautogui_permissions() diff --git a/tests/test_startup.py b/tests/test_startup.py new file mode 100755 index 0000000..b5dd842 --- /dev/null +++ b/tests/test_startup.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +""" +Test script for Launch Agent functionality. +""" + +import sys +import os + +# Add src directory to path +sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'src')) + +from launch_agent import get_launch_agent_manager +from logging_config import setup_logging, get_logger + +def test_launch_agent(): + """Test the launch agent functionality""" + setup_logging(debug=True) + logger = get_logger(__name__) + + print("πŸ§ͺ Testing Launch Agent Functionality") + print("=" * 40) + + # Get launch agent manager + manager = get_launch_agent_manager() + + # Check current status + is_enabled = manager.is_startup_enabled() + print(f"πŸ“‹ Current startup status: {'Enabled' if is_enabled else 'Disabled'}") + + if is_enabled: + info = manager.get_launch_agent_info() + if info: + print(f"πŸ“‚ Plist path: {info['path']}") + print(f"πŸš€ Program: {' '.join(info['program_arguments'])}") + + # Test app path detection + app_path = manager.get_app_path() + print(f"πŸ“± Detected app path: {app_path}") + + # Test plist creation (don't install it) + plist_data = manager.create_launch_agent_plist() + print(f"πŸ“„ Generated plist data:") + for key, value in plist_data.items(): + print(f" {key}: {value}") + + print("\nβœ… Launch Agent test completed!") + print("\nTo test startup functionality:") + print("1. Build the app: ./build_app.sh") + print("2. Run the app and go to Options") + print("3. Enable 'Launch at Startup'") + print("4. Log out and back in to test") + +if __name__ == "__main__": + test_launch_agent() diff --git a/tests/test_visual_dialog.py b/tests/test_visual_dialog.py new file mode 100644 index 0000000..72e8814 --- /dev/null +++ b/tests/test_visual_dialog.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +""" +Visual test for the Options Dialog with Open Logs button. +Run this to see the dialog with the new button. +""" + +import sys +import os + +# Add src directory to path +sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'src')) + +from PyQt5 import QtWidgets +from options_dialog import OptionsDialog +from logging_config import setup_logging, get_logger + +def main(): + """Show the options dialog visually for testing""" + setup_logging(debug=True) + logger = get_logger(__name__) + + print("πŸ§ͺ Visual Test: Options Dialog with Open Logs Button") + print("========================================") + print("This will open the options dialog so you can test the 'Open Logs Directory' button") + print("Click the button to open the logs directory in Finder") + print("Close the dialog when done testing") + print("") + + # Create a QApplication instance + app = QtWidgets.QApplication(sys.argv) + + # Create the options dialog + dialog = OptionsDialog( + current_wait_time=240, + current_start_enabled=True, + current_log_level="INFO", + current_move_px=10, + current_launch_at_startup=False, + parent=None + ) + + print("βœ… Options dialog created with the new 'Open Logs Directory' button") + print("πŸ“‚ The button should be visible above the Save/Cancel buttons") + + # Show the dialog + dialog.show() + result = app.exec_() + + print("βœ… Test completed!") + return result + +if __name__ == "__main__": + main()