mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-11 17:51:39 -05:00
223 lines
6.7 KiB
Ruby
223 lines
6.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'rails_helper'
|
|
|
|
RSpec.describe LocationSearch::SpatialMatcher do
|
|
let(:service) { described_class.new }
|
|
let(:user) { create(:user) }
|
|
let(:latitude) { 52.5200 }
|
|
let(:longitude) { 13.4050 }
|
|
let(:radius_meters) { 100 }
|
|
|
|
describe '#find_points_near' do
|
|
let!(:near_point) do
|
|
create(:point,
|
|
user: user,
|
|
lonlat: "POINT(13.4051 52.5201)",
|
|
timestamp: 1.hour.ago.to_i,
|
|
city: 'Berlin',
|
|
country: 'Germany',
|
|
altitude: 100,
|
|
accuracy: 5
|
|
)
|
|
end
|
|
|
|
let!(:far_point) do
|
|
create(:point,
|
|
user: user,
|
|
lonlat: "POINT(13.5000 52.6000)",
|
|
timestamp: 2.hours.ago.to_i
|
|
)
|
|
end
|
|
|
|
let!(:other_user_point) do
|
|
create(:point,
|
|
user: create(:user),
|
|
lonlat: "POINT(13.4051 52.5201)",
|
|
timestamp: 30.minutes.ago.to_i
|
|
)
|
|
end
|
|
|
|
context 'with points within radius' do
|
|
it 'returns points within the specified radius' do
|
|
results = service.find_points_near(user, latitude, longitude, radius_meters)
|
|
|
|
expect(results.length).to eq(1)
|
|
expect(results.first[:id]).to eq(near_point.id)
|
|
end
|
|
|
|
it 'excludes points outside the radius' do
|
|
results = service.find_points_near(user, latitude, longitude, radius_meters)
|
|
|
|
point_ids = results.map { |r| r[:id] }
|
|
expect(point_ids).not_to include(far_point.id)
|
|
end
|
|
|
|
it 'only includes points from the specified user' do
|
|
results = service.find_points_near(user, latitude, longitude, radius_meters)
|
|
|
|
point_ids = results.map { |r| r[:id] }
|
|
expect(point_ids).not_to include(other_user_point.id)
|
|
end
|
|
|
|
it 'includes calculated distance' do
|
|
results = service.find_points_near(user, latitude, longitude, radius_meters)
|
|
|
|
expect(results.first[:distance_meters]).to be_a(Float)
|
|
expect(results.first[:distance_meters]).to be < radius_meters
|
|
end
|
|
|
|
it 'includes point attributes' do
|
|
results = service.find_points_near(user, latitude, longitude, radius_meters)
|
|
|
|
point = results.first
|
|
expect(point).to include(
|
|
id: near_point.id,
|
|
timestamp: near_point.timestamp,
|
|
coordinates: [52.5201, 13.4051],
|
|
city: 'Berlin',
|
|
country: 'Germany',
|
|
altitude: 100,
|
|
accuracy: 5
|
|
)
|
|
end
|
|
|
|
it 'includes ISO8601 formatted date' do
|
|
results = service.find_points_near(user, latitude, longitude, radius_meters)
|
|
|
|
expect(results.first[:date]).to match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
|
|
end
|
|
|
|
it 'orders results by timestamp descending (most recent first)' do
|
|
# Create another nearby point with older timestamp
|
|
older_point = create(:point,
|
|
user: user,
|
|
lonlat: "POINT(13.4049 52.5199)",
|
|
timestamp: 3.hours.ago.to_i
|
|
)
|
|
|
|
results = service.find_points_near(user, latitude, longitude, radius_meters)
|
|
|
|
expect(results.first[:id]).to eq(near_point.id) # More recent
|
|
expect(results.last[:id]).to eq(older_point.id) # Older
|
|
end
|
|
end
|
|
|
|
context 'with date filtering' do
|
|
let(:date_options) do
|
|
{
|
|
date_from: 2.days.ago.to_date,
|
|
date_to: Date.current
|
|
}
|
|
end
|
|
|
|
let!(:old_point) do
|
|
create(:point,
|
|
user: user,
|
|
lonlat: "POINT(13.4051 52.5201)",
|
|
timestamp: 1.week.ago.to_i
|
|
)
|
|
end
|
|
|
|
it 'filters points by date range' do
|
|
results = service.find_points_near(user, latitude, longitude, radius_meters, date_options)
|
|
|
|
point_ids = results.map { |r| r[:id] }
|
|
expect(point_ids).to include(near_point.id)
|
|
expect(point_ids).not_to include(old_point.id)
|
|
end
|
|
|
|
context 'with only date_from' do
|
|
let(:date_options) { { date_from: 2.hours.ago.to_date } }
|
|
|
|
it 'includes points after date_from' do
|
|
results = service.find_points_near(user, latitude, longitude, radius_meters, date_options)
|
|
|
|
point_ids = results.map { |r| r[:id] }
|
|
expect(point_ids).to include(near_point.id)
|
|
end
|
|
end
|
|
|
|
context 'with only date_to' do
|
|
let(:date_options) { { date_to: 2.days.ago.to_date } }
|
|
|
|
it 'includes points before date_to' do
|
|
results = service.find_points_near(user, latitude, longitude, radius_meters, date_options)
|
|
|
|
point_ids = results.map { |r| r[:id] }
|
|
expect(point_ids).to include(old_point.id)
|
|
expect(point_ids).not_to include(near_point.id)
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'with no points within radius' do
|
|
it 'returns empty array' do
|
|
results = service.find_points_near(user, 60.0, 30.0, 100) # Far away coordinates
|
|
|
|
expect(results).to be_empty
|
|
end
|
|
end
|
|
|
|
context 'with edge cases' do
|
|
it 'handles points at the exact radius boundary' do
|
|
# This test would require creating a point at exactly 100m distance
|
|
# For simplicity, we'll test with a very small radius that should exclude our test point
|
|
results = service.find_points_near(user, latitude, longitude, 1) # 1 meter radius
|
|
|
|
expect(results).to be_empty
|
|
end
|
|
|
|
it 'handles negative coordinates' do
|
|
# Create point with negative coordinates
|
|
negative_point = create(:point,
|
|
user: user,
|
|
lonlat: "POINT(151.2093 -33.8688)",
|
|
timestamp: 1.hour.ago.to_i
|
|
)
|
|
|
|
results = service.find_points_near(user, -33.8688, 151.2093, 1000)
|
|
|
|
expect(results.length).to eq(1)
|
|
expect(results.first[:id]).to eq(negative_point.id)
|
|
end
|
|
|
|
it 'handles coordinates near poles' do
|
|
# Create point near north pole
|
|
polar_point = create(:point,
|
|
user: user,
|
|
lonlat: "POINT(0.0 89.0)",
|
|
timestamp: 1.hour.ago.to_i
|
|
)
|
|
|
|
results = service.find_points_near(user, 89.0, 0.0, 1000)
|
|
|
|
expect(results.length).to eq(1)
|
|
expect(results.first[:id]).to eq(polar_point.id)
|
|
end
|
|
end
|
|
|
|
context 'with large datasets' do
|
|
before do
|
|
# Create many points to test performance
|
|
50.times do |i|
|
|
create(:point,
|
|
user: user,
|
|
lonlat: "POINT(#{longitude + (i * 0.0001)} #{latitude + (i * 0.0001)})", # Spread points slightly
|
|
timestamp: i.hours.ago.to_i
|
|
)
|
|
end
|
|
end
|
|
|
|
it 'efficiently queries large datasets' do
|
|
start_time = Time.current
|
|
|
|
results = service.find_points_near(user, latitude, longitude, 1000)
|
|
|
|
query_time = Time.current - start_time
|
|
expect(query_time).to be < 1.0 # Should complete within 1 second
|
|
expect(results.length).to be > 40 # Should find most of the points
|
|
end
|
|
end
|
|
end
|
|
end
|