From 71bb2245245fc34bb29d64db799e224f07540973 Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Tue, 2 Sep 2025 21:55:47 +0200 Subject: [PATCH] Fix some tests --- app/services/location_search/point_finder.rb | 25 ++++++++++++++++-- .../location_search/result_aggregator.rb | 5 +++- .../location_search/geocoding_service_spec.rb | 19 +++++++++++++- .../location_search/result_aggregator_spec.rb | 26 ++++++++++++++----- 4 files changed, 64 insertions(+), 11 deletions(-) diff --git a/app/services/location_search/point_finder.rb b/app/services/location_search/point_finder.rb index cf1b2a1f..594153b5 100644 --- a/app/services/location_search/point_finder.rb +++ b/app/services/location_search/point_finder.rb @@ -73,16 +73,18 @@ module LocationSearch # Debug: Log the geocoded location Rails.logger.info "LocationSearch: Searching for points near #{location[:name]} at [#{location[:lat]}, #{location[:lon]}]" + search_radius = @radius_override || determine_search_radius(location[:type]) + matching_points = spatial_matcher.find_points_near( @user, location[:lat], location[:lon], - @radius_override || 500, # Allow radius override, default 500 meters + search_radius, date_filter_options ) # Debug: Log the number of matching points found - Rails.logger.info "LocationSearch: Found #{matching_points.length} points within #{@radius_override || 500}m radius" + Rails.logger.info "LocationSearch: Found #{matching_points.length} points within #{search_radius}m radius" if matching_points.empty? # Try with a larger radius to see if there are any points nearby @@ -137,6 +139,25 @@ module LocationSearch } end + def determine_search_radius(location_type) + case location_type.to_s.downcase + when 'shop', 'store', 'retail' + 75 # Small radius for specific shops + when 'restaurant', 'cafe', 'food' + 75 # Small radius for specific restaurants + when 'building', 'house', 'address' + 50 # Very small radius for specific addresses + when 'street', 'road' + 50 # Very small radius for streets + when 'neighbourhood', 'neighborhood', 'district', 'suburb' + 300 # Medium radius for neighborhoods + when 'city', 'town', 'village' + 1000 # Large radius for cities + else + 500 # Default radius for unknown types + end + end + def empty_result { query: @query, diff --git a/app/services/location_search/result_aggregator.rb b/app/services/location_search/result_aggregator.rb index cd557690..0c28000a 100644 --- a/app/services/location_search/result_aggregator.rb +++ b/app/services/location_search/result_aggregator.rb @@ -10,10 +10,13 @@ module LocationSearch def group_points_into_visits(points) return [] if points.empty? + # Sort points by timestamp to handle unordered input + sorted_points = points.sort_by { |p| p[:timestamp] } + visits = [] current_visit_points = [] - points.each do |point| + sorted_points.each do |point| if current_visit_points.empty? || within_visit_threshold?(current_visit_points.last, point) current_visit_points << point else diff --git a/spec/services/location_search/geocoding_service_spec.rb b/spec/services/location_search/geocoding_service_spec.rb index 7c09c8ae..dbfdd5a3 100644 --- a/spec/services/location_search/geocoding_service_spec.rb +++ b/spec/services/location_search/geocoding_service_spec.rb @@ -166,7 +166,24 @@ RSpec.describe LocationSearch::GeocodingService do end before do - allow(service).to receive(:perform_geocoding_search).and_return(duplicate_results) + # Create mock geocoder results that will be normalized and deduplicated + mock_geocoder_results = duplicate_results.map do |result| + double( + latitude: result[:lat], + longitude: result[:lon], + address: result[:address], + data: { + 'display_name' => result[:name], + 'type' => result[:type], + 'properties' => { + 'name' => result[:name], + 'osm_key' => result[:type] + } + } + ) + end + + allow(Geocoder).to receive(:search).and_return(mock_geocoder_results) end it 'removes locations within 100m of each other' do diff --git a/spec/services/location_search/result_aggregator_spec.rb b/spec/services/location_search/result_aggregator_spec.rb index 952de38a..99d85d24 100644 --- a/spec/services/location_search/result_aggregator_spec.rb +++ b/spec/services/location_search/result_aggregator_spec.rb @@ -165,8 +165,8 @@ RSpec.describe LocationSearch::ResultAggregator do result = service.group_points_into_visits(separate_visits_points) expect(result.length).to eq(2) - expect(result.first[:points_count]).to eq(2) - expect(result.last[:points_count]).to eq(1) + expect(result.first[:points_count]).to eq(1) # Most recent visit (20:15) + expect(result.last[:points_count]).to eq(2) # Earlier visit (18:45-19:15) end it 'orders visits by timestamp descending (most recent first)' do @@ -182,13 +182,21 @@ RSpec.describe LocationSearch::ResultAggregator do base_time = 1711814700 [ - # Short visit (25 minutes) + # Short visit (25 minutes) - 2 points 25 minutes apart { id: 1, timestamp: base_time, accuracy: 10, coordinates: [52.5200, 13.4050], distance_meters: 50, date: '2024-03-20T18:45:00Z' }, { id: 2, timestamp: base_time + 25 * 60, accuracy: 10, coordinates: [52.5200, 13.4050], distance_meters: 50, date: '2024-03-20T19:10:00Z' }, - # Long visit (2 hours 15 minutes) - starts 45 minutes after previous to create gap + # Long visit (2 hours 15 minutes) - points every 15 minutes to stay within 30min threshold { id: 3, timestamp: base_time + 70 * 60, accuracy: 10, coordinates: [52.5300, 13.4100], distance_meters: 30, date: '2024-03-20T19:55:00Z' }, - { id: 4, timestamp: base_time + 205 * 60, accuracy: 10, coordinates: [52.5300, 13.4100], distance_meters: 30, date: '2024-03-20T22:10:00Z' } + { id: 4, timestamp: base_time + 85 * 60, accuracy: 10, coordinates: [52.5300, 13.4100], distance_meters: 30, date: '2024-03-20T20:10:00Z' }, + { id: 5, timestamp: base_time + 100 * 60, accuracy: 10, coordinates: [52.5300, 13.4100], distance_meters: 30, date: '2024-03-20T20:25:00Z' }, + { id: 6, timestamp: base_time + 115 * 60, accuracy: 10, coordinates: [52.5300, 13.4100], distance_meters: 30, date: '2024-03-20T20:40:00Z' }, + { id: 7, timestamp: base_time + 130 * 60, accuracy: 10, coordinates: [52.5300, 13.4100], distance_meters: 30, date: '2024-03-20T20:55:00Z' }, + { id: 8, timestamp: base_time + 145 * 60, accuracy: 10, coordinates: [52.5300, 13.4100], distance_meters: 30, date: '2024-03-20T21:10:00Z' }, + { id: 9, timestamp: base_time + 160 * 60, accuracy: 10, coordinates: [52.5300, 13.4100], distance_meters: 30, date: '2024-03-20T21:25:00Z' }, + { id: 10, timestamp: base_time + 175 * 60, accuracy: 10, coordinates: [52.5300, 13.4100], distance_meters: 30, date: '2024-03-20T21:40:00Z' }, + { id: 11, timestamp: base_time + 190 * 60, accuracy: 10, coordinates: [52.5300, 13.4100], distance_meters: 30, date: '2024-03-20T21:55:00Z' }, + { id: 12, timestamp: base_time + 205 * 60, accuracy: 10, coordinates: [52.5300, 13.4100], distance_meters: 30, date: '2024-03-20T22:10:00Z' } ] end @@ -207,10 +215,14 @@ RSpec.describe LocationSearch::ResultAggregator do end it 'formats duration correctly for hours only' do - # Create points exactly 2 hours apart + # Create points within threshold but exactly 2 hours apart from first to last exact_hour_points = [ { id: 1, timestamp: 1711814700, accuracy: 10, coordinates: [52.5200, 13.4050], distance_meters: 50, date: '2024-03-20T18:45:00Z' }, - { id: 2, timestamp: 1711814700 + 120 * 60, accuracy: 10, coordinates: [52.5200, 13.4050], distance_meters: 50, date: '2024-03-20T20:45:00Z' } + { id: 2, timestamp: 1711814700 + 25 * 60, accuracy: 10, coordinates: [52.5200, 13.4050], distance_meters: 50, date: '2024-03-20T19:10:00Z' }, + { id: 3, timestamp: 1711814700 + 50 * 60, accuracy: 10, coordinates: [52.5200, 13.4050], distance_meters: 50, date: '2024-03-20T19:35:00Z' }, + { id: 4, timestamp: 1711814700 + 75 * 60, accuracy: 10, coordinates: [52.5200, 13.4050], distance_meters: 50, date: '2024-03-20T20:00:00Z' }, + { id: 5, timestamp: 1711814700 + 100 * 60, accuracy: 10, coordinates: [52.5200, 13.4050], distance_meters: 50, date: '2024-03-20T20:25:00Z' }, + { id: 6, timestamp: 1711814700 + 120 * 60, accuracy: 10, coordinates: [52.5200, 13.4050], distance_meters: 50, date: '2024-03-20T20:45:00Z' } ] result = service.group_points_into_visits(exact_hour_points)