added segments
This commit is contained in:
115
FitnessSync/backend/tests/test_segments_verification.py
Normal file
115
FitnessSync/backend/tests/test_segments_verification.py
Normal file
@@ -0,0 +1,115 @@
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
import sys
|
||||
|
||||
# Mock fitdecode before imports since it might not be installed in local env (running in docker)
|
||||
sys.modules['fitdecode'] = MagicMock()
|
||||
|
||||
import pytest
|
||||
from src.utils.geo import ramer_douglas_peucker, haversine_distance, calculate_bounds
|
||||
from src.services.segment_matcher import SegmentMatcher
|
||||
from src.models.activity import Activity
|
||||
from src.models.segment import Segment
|
||||
from datetime import datetime, timedelta
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
|
||||
def test_haversine():
|
||||
# Dist between (0,0) and (0,1) deg is ~111km
|
||||
d = haversine_distance(0, 0, 0, 1)
|
||||
# 1 deg lat ~ 111.32 km
|
||||
assert 110000 < d < 112000
|
||||
|
||||
def test_rdp_simple():
|
||||
# Points on a line
|
||||
points = [[0,0], [1,1], [2,2]]
|
||||
# Should simplify to [0,0], [2,2]
|
||||
simplified = ramer_douglas_peucker(points, epsilon=0.1)
|
||||
assert len(simplified) == 2
|
||||
assert simplified[0] == [0,0]
|
||||
assert simplified[1] == [2,2]
|
||||
|
||||
def test_rdp_peak():
|
||||
# Triangle
|
||||
points = [[0,0], [1,10], [2,0]] # [lon, lat] note: RDP expects [lon, lat] usually?
|
||||
# My RDP implementation uses x,y so order doesn't matter for geometric shape
|
||||
simplified = ramer_douglas_peucker(points, epsilon=1.0)
|
||||
assert len(simplified) == 3
|
||||
|
||||
def test_bounds():
|
||||
points = [[0,0], [10, 10], [-5, 5]]
|
||||
bounds = calculate_bounds(points)
|
||||
assert bounds['min_lat'] == 0 # wait, index 1 is lat? check utils
|
||||
# If points are [lon, lat]
|
||||
# 0,0: lat=0
|
||||
# 10,10: lat=10
|
||||
# -5,5: lat=5
|
||||
# bounds are min_lat=0, max_lat=10. min_lon=-5, max_lon=10
|
||||
|
||||
# My calculate_bounds implementation assumes [lon, lat]
|
||||
assert bounds['min_lat'] == 0
|
||||
assert bounds['max_lat'] == 10
|
||||
assert bounds['min_lon'] == -5
|
||||
assert bounds['max_lon'] == 10
|
||||
|
||||
def test_matcher_logic():
|
||||
# Mock DB session
|
||||
mock_session = MagicMock()
|
||||
|
||||
# Create segment [0,0] -> [0, 0.01] (approx 1.1km north)
|
||||
segment_points = [[0,0], [0, 0.01]]
|
||||
segment = Segment(
|
||||
id=1,
|
||||
name="Test Seg",
|
||||
points=json.dumps(segment_points),
|
||||
bounds=json.dumps(calculate_bounds(segment_points)),
|
||||
distance=1110.0,
|
||||
activity_type='cycling'
|
||||
)
|
||||
|
||||
mock_session.query.return_value.filter.return_value.all.return_value = [segment]
|
||||
|
||||
matcher = SegmentMatcher(mock_session)
|
||||
|
||||
# Create activity trace that covers this
|
||||
# 0,0 at T=0
|
||||
# 0,0.01 at T=100s
|
||||
act_points = [[0,0], [0, 0.005], [0, 0.01]]
|
||||
|
||||
# Mock activity
|
||||
activity = Activity(id=100, activity_start_time=datetime.now())
|
||||
# Matcher needs to use parsers internally? Or uses slice of points?
|
||||
# Matcher logic (_match_segment) uses points list passed to match_activity
|
||||
|
||||
# Wait, _match_segment needs timestamps to calc elapsed time.
|
||||
# We need to mock extract_timestamps_from_file or patch it
|
||||
from unittest.mock import patch
|
||||
|
||||
with patch('src.services.segment_matcher.extract_timestamps_from_file') as mock_extract:
|
||||
# 0,0@T0, 0,0.005@T50, 0,0.01@T100
|
||||
start_time = datetime.now()
|
||||
timestamps = [start_time, start_time + timedelta(seconds=50), start_time + timedelta(seconds=100)]
|
||||
mock_extract.return_value = timestamps
|
||||
|
||||
# Add dummy content
|
||||
activity.file_content = b'dummy'
|
||||
activity.file_type = 'fit'
|
||||
|
||||
# Run match
|
||||
efforts = matcher.match_activity(activity, act_points)
|
||||
|
||||
assert len(efforts) == 1
|
||||
effort = efforts[0]
|
||||
assert effort.segment_id == 1
|
||||
assert effort.elapsed_time == 100.0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# verification
|
||||
try:
|
||||
test_haversine()
|
||||
test_rdp_simple()
|
||||
test_bounds()
|
||||
print("Geo Utils Passed")
|
||||
except Exception as e:
|
||||
print(f"Failed: {e}")
|
||||
Reference in New Issue
Block a user