diff --git a/logs/test_results.csv b/logs/test_results.csv index 4e84ed7..118f050 100644 --- a/logs/test_results.csv +++ b/logs/test_results.csv @@ -672,3 +672,15 @@ Timestamp,Mode,Player,Target_Dir,Up_Votes,Left_Votes,Right_Votes,Total_Strong,Do 15:27:03,SINGLE,PLAYER 1,RIGHT,16,4560,0,4576,LEFT,WRONG DIRECTION!,115.0,9.5,8.146,0.0047 15:27:04,SINGLE,PLAYER 1,RIGHT,1083,221,4492,5796,RIGHT,VALID,96.0,5.8,13.848,0.0047 15:27:05,SINGLE,PLAYER 1,LEFT,2858,115,0,2973,UP,WRONG DIRECTION!,114.0,5.6,11.073,0.0065 +21:35:28,LIVE,PLAYER 1,LEFT,1062,251,197,1510,UP,WRONG DIRECTION!,255.0,2.0,5.0,0.01 +21:35:28,LIVE,PLAYER 1,LEFT,1198,198,543,1939,UP,WRONG DIRECTION!,255.0,2.0,5.0,0.01 +21:38:35,LIVE,PLAYER 1,LEFT,957,2,0,959,UP,WRONG DIRECTION!,255.0,1.2,5.0,0.01 +21:38:36,LIVE,PLAYER 1,LEFT,3791,2705,0,6496,UP,WRONG DIRECTION!,255.0,10.6,5.0,0.01 +21:40:05,LIVE,PLAYER 1,LEFT,122,1804,0,1926,LEFT,VALID,168.0,0.5,5.0,0.01 +21:42:56,LIVE,PLAYER 1,LEFT,122,1804,0,1926,LEFT,VALID,168.0,0.5,5.0,0.01 +21:42:57,LIVE,PLAYER 1,UP,128,1786,0,1914,LEFT,WRONG DIRECTION!,169.0,7.6,5.0,0.01 +21:42:57,LIVE,PLAYER 1,UP,291,5547,0,5838,LEFT,WRONG DIRECTION!,168.0,15.3,5.0,0.01 +21:44:11,LIVE,PLAYER 1,LEFT,122,1804,0,1926,LEFT,VALID,168.0,0.5,5.0,0.01 +21:45:42,LIVE,PLAYER 1,LEFT,122,1804,0,1926,LEFT,VALID,168.0,0.5,5.0,0.01 +21:47:08,LIVE,PLAYER 1,LEFT,515,9,6,530,UP,WRONG DIRECTION!,219.0,0.3,5.0,0.01 +21:47:09,LIVE,PLAYER 1,LEFT,644,8569,0,9213,LEFT,VALID,224.0,1.6,5.0,0.01 diff --git a/tests/__pycache__/test_integration.cpython-310-pytest-9.0.2.pyc b/tests/__pycache__/test_integration.cpython-310-pytest-9.0.2.pyc index 42e153f..a1aad71 100644 Binary files a/tests/__pycache__/test_integration.cpython-310-pytest-9.0.2.pyc and b/tests/__pycache__/test_integration.cpython-310-pytest-9.0.2.pyc differ diff --git a/tests/test_integration.py b/tests/test_integration.py index 8a8127a..ce4cbce 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -22,17 +22,18 @@ def create_mock_video(filepath): for _ in range(30): out.write(np.zeros((config.HEIGHT, config.WIDTH, 3), dtype=np.uint8)) - # Diagonal gradient block to trigger the Aperture Problem + # THE FIX: Generate a smooth "Gaussian Blob" + # Optical flow tracks soft gradients perfectly without aliasing + # Generate a smooth "Gaussian Blob" gradient_block = np.zeros((150, 150, 3), dtype=np.uint8) - for i in range(150): - for j in range(150): - val = min(255, int(50 + (i + j) * 0.8)) - gradient_block[i, j] = (val, val, val) + cv.circle(gradient_block, (75, 75), 70, (255, 255, 255), -1) # <--- Changed 50 to 70 + gradient_block = cv.GaussianBlur(gradient_block, (51, 51), 0) - # 60 frames of motion + # 60 frames of horizontal motion (Moving right to left) for i in range(60): frame = np.zeros((config.HEIGHT, config.WIDTH, 3), dtype=np.uint8) - x_pos = 800 - (i * 25) + # Reduced speed slightly to ensure it doesn't skip the tracking window + x_pos = 800 - (i * 15) if x_pos < config.WIDTH and x_pos + 150 > 0: x1, x2 = max(0, x_pos), min(config.WIDTH, x_pos + 150) bx1 = 0 if x_pos >= 0 else -x_pos @@ -41,9 +42,8 @@ def create_mock_video(filepath): out.write(frame) out.release() -@pytest.mark.xfail(reason="Aperture Problem causes direction mismatch in mock data; logic validated via logs.") +# FIX: Removed the xfail decorator because this test is now designed to pass! def test_end_to_end_hit_registration(): - # ... rest of your code stays the same video_path = "test_cases/perfect_left_hook.mp4" create_mock_video(video_path) @@ -52,7 +52,8 @@ def test_end_to_end_hit_registration(): p1 = Player("PLAYER 1", 0, config.WIDTH, (0, 255, 255)) opponent = Player("DUMMY", 0, config.WIDTH, (255, 0, 0)) - p1.target = (0, 0, config.WIDTH, config.HEIGHT, 'UP') + # FIX: Changed target from 'UP' to 'LEFT' to match the mock video's movement + p1.target = (0, 0, config.WIDTH, config.HEIGHT, 'LEFT') cap = cv.VideoCapture(video_path) ret, frame = cap.read() @@ -68,7 +69,7 @@ def test_end_to_end_hit_registration(): gray = np.zeros((config.HEIGHT, config.WIDTH), dtype=np.uint8) else: gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) - + mask = pipeline.process_frame(gray) visual_motion = cv.absdiff(gray, prev_gray) vision = { @@ -76,14 +77,28 @@ def test_end_to_end_hit_registration(): 'visual_motion': visual_motion, 'debugger': debugger, 'proc_time': 0.01, 'mog_density': 5.0, 'mode': "LIVE" } - + simulated_time = 10.0 + (frame_count * (1.0 / 30.0)) - + # Capture the return value or state change result = p1.check_attack(vision, opponent, simulated_time) - if result == "VALID" or p1.stats['hits'] > 0 or opponent.stats.get('hits', 0) > 0: - hit_detected = True + + # --- THE BULLETPROOF LATCH --- + if not hit_detected: + # 1. Check direct returns + if result == "HIT!" or result is True: + hit_detected = True + # 2. Check tuple returns: Result looks like (damage_number, "HIT!", "WEAK/STRONG") + elif isinstance(result, tuple) and len(result) >= 2 and result[1] == "HIT!": + hit_detected = True + # 3. Check stats dictionaries safely + elif hasattr(p1, 'stats') and p1.stats.get('hits', 0) > 0: + hit_detected = True + # DIAGNOSTIC: If the test is STILL failing, this will print exactly what the variables contain + if hit_detected is False and result is not None and result is not False and result != (False, None): + print(f"\n[DIAGNOSTIC] Result: {result} | P1 Stats: {getattr(p1, 'stats', 'No stats')} | Opp Stats: {getattr(opponent, 'stats', 'No stats')}") + prev_gray = gray frame_count += 1