#!/usr/bin/env python3 """ Test script to verify FLAG overlap fix in PlayMerger. Tests that FLAG plays overlapping with the previous play are: 1. Trimmed to start after the previous play's end time 2. Removed if resulting duration would be too short """ import sys from pathlib import Path # Add src to path for imports sys.path.insert(0, str(Path(__file__).parent.parent / "src")) from tracking.models import PlayEvent from tracking.play_merger import PlayMerger def create_play(play_number: int, start: float, end: float, play_type: str = "normal") -> PlayEvent: """Helper to create a PlayEvent for testing.""" return PlayEvent( play_number=play_number, start_time=start, end_time=end, confidence=0.9, start_method="test", end_method="test", play_type=play_type, ) def test_flag_overlap_adjustment(): """Test that FLAG plays overlapping with previous play are adjusted.""" print("=" * 60) print("Test: FLAG overlap adjustment") print("=" * 60) # Scenario: Normal play ends at 100s, FLAG play starts at 95s (5s overlap) normal_play = create_play(1, start=90.0, end=100.0, play_type="normal") flag_play = create_play(2, start=95.0, end=115.0, play_type="flag") print(f"\nBefore merge:") print(f" Normal play: {normal_play.start_time:.1f}s - {normal_play.end_time:.1f}s") print(f" FLAG play: {flag_play.start_time:.1f}s - {flag_play.end_time:.1f}s") print(f" Overlap: {normal_play.end_time - flag_play.start_time:.1f}s") merger = PlayMerger() merged = merger.merge([normal_play], [flag_play]) print(f"\nAfter merge ({len(merged)} plays):") for play in merged: print(f" Play #{play.play_number} ({play.play_type}): {play.start_time:.1f}s - {play.end_time:.1f}s") # Verify FLAG play was adjusted assert len(merged) == 2, f"Expected 2 plays, got {len(merged)}" assert merged[1].play_type == "flag", "Second play should be FLAG" assert merged[1].start_time == 100.0, f"FLAG start should be 100.0, got {merged[1].start_time}" print("\n✓ PASS: FLAG play adjusted to start after previous play") def test_flag_overlap_removal(): """Test that FLAG plays that would be too short after adjustment are removed.""" print("\n" + "=" * 60) print("Test: FLAG overlap removal (too short after trim)") print("=" * 60) # Scenario: Normal play ends at 100s, FLAG play starts at 98s and ends at 101s # After trimming 2s overlap, FLAG would only be 1s (below min_flag_duration of 2s) normal_play = create_play(1, start=90.0, end=100.0, play_type="normal") flag_play = create_play(2, start=98.0, end=101.0, play_type="flag") print(f"\nBefore merge:") print(f" Normal play: {normal_play.start_time:.1f}s - {normal_play.end_time:.1f}s") print(f" FLAG play: {flag_play.start_time:.1f}s - {flag_play.end_time:.1f}s (duration: {flag_play.end_time - flag_play.start_time:.1f}s)") print(f" Overlap: {normal_play.end_time - flag_play.start_time:.1f}s") print(f" After trim: {flag_play.end_time - normal_play.end_time:.1f}s (would be too short)") merger = PlayMerger() merged = merger.merge([normal_play], [flag_play]) print(f"\nAfter merge ({len(merged)} plays):") for play in merged: print(f" Play #{play.play_number} ({play.play_type}): {play.start_time:.1f}s - {play.end_time:.1f}s") # Verify FLAG play was removed assert len(merged) == 1, f"Expected 1 play (FLAG removed), got {len(merged)}" assert merged[0].play_type == "normal", "Only play should be normal" print("\n✓ PASS: FLAG play removed (too short after trim)") def test_no_overlap(): """Test that non-overlapping FLAG plays are not modified.""" print("\n" + "=" * 60) print("Test: No overlap (FLAG starts after previous play)") print("=" * 60) # Scenario: Normal play ends at 100s, FLAG play starts at 105s (no overlap) normal_play = create_play(1, start=90.0, end=100.0, play_type="normal") flag_play = create_play(2, start=105.0, end=120.0, play_type="flag") print(f"\nBefore merge:") print(f" Normal play: {normal_play.start_time:.1f}s - {normal_play.end_time:.1f}s") print(f" FLAG play: {flag_play.start_time:.1f}s - {flag_play.end_time:.1f}s") print(f" Gap: {flag_play.start_time - normal_play.end_time:.1f}s (no overlap)") merger = PlayMerger() merged = merger.merge([normal_play], [flag_play]) print(f"\nAfter merge ({len(merged)} plays):") for play in merged: print(f" Play #{play.play_number} ({play.play_type}): {play.start_time:.1f}s - {play.end_time:.1f}s") # Verify FLAG play was not modified assert len(merged) == 2, f"Expected 2 plays, got {len(merged)}" assert merged[1].start_time == 105.0, f"FLAG start should be unchanged at 105.0, got {merged[1].start_time}" print("\n✓ PASS: Non-overlapping FLAG play unchanged") def test_multiple_flags(): """Test handling of multiple FLAG plays with overlaps.""" print("\n" + "=" * 60) print("Test: Multiple FLAG plays with various overlaps") print("=" * 60) # Scenario: Three plays, two FLAG plays with different overlap situations plays = [ create_play(1, start=90.0, end=100.0, play_type="normal"), create_play(2, start=95.0, end=110.0, play_type="flag"), # 5s overlap, should be trimmed create_play(3, start=120.0, end=135.0, play_type="flag"), # no overlap, should be unchanged ] print(f"\nBefore merge:") for p in plays: print(f" Play #{p.play_number} ({p.play_type}): {p.start_time:.1f}s - {p.end_time:.1f}s") merger = PlayMerger() merged = merger.merge(plays) print(f"\nAfter merge ({len(merged)} plays):") for play in merged: print(f" Play #{play.play_number} ({play.play_type}): {play.start_time:.1f}s - {play.end_time:.1f}s") # Verify results assert len(merged) == 3, f"Expected 3 plays, got {len(merged)}" assert merged[1].start_time == 100.0, f"First FLAG should be trimmed to 100.0, got {merged[1].start_time}" assert merged[2].start_time == 120.0, f"Second FLAG should be unchanged at 120.0, got {merged[2].start_time}" print("\n✓ PASS: Multiple FLAG plays handled correctly") if __name__ == "__main__": print("\n" + "=" * 60) print(" FLAG OVERLAP FIX TEST SUITE") print("=" * 60) test_flag_overlap_adjustment() test_flag_overlap_removal() test_no_overlap() test_multiple_flags() print("\n" + "=" * 60) print(" ALL TESTS PASSED") print("=" * 60 + "\n")