dawarich/spec/queries/hexagon_query_spec.rb
2025-09-12 21:38:25 +02:00

245 lines
No EOL
7 KiB
Ruby

# frozen_string_literal: true
require 'rails_helper'
RSpec.describe HexagonQuery, type: :query do
let(:user) { create(:user) }
let(:min_lon) { -74.1 }
let(:min_lat) { 40.6 }
let(:max_lon) { -73.9 }
let(:max_lat) { 40.8 }
let(:hex_size) { 500 }
describe '#initialize' do
it 'sets required parameters' do
query = described_class.new(
min_lon: min_lon,
min_lat: min_lat,
max_lon: max_lon,
max_lat: max_lat,
hex_size: hex_size
)
expect(query.min_lon).to eq(min_lon)
expect(query.min_lat).to eq(min_lat)
expect(query.max_lon).to eq(max_lon)
expect(query.max_lat).to eq(max_lat)
expect(query.hex_size).to eq(hex_size)
end
it 'sets optional parameters' do
start_date = '2024-06-01T00:00:00Z'
end_date = '2024-06-30T23:59:59Z'
query = described_class.new(
min_lon: min_lon,
min_lat: min_lat,
max_lon: max_lon,
max_lat: max_lat,
hex_size: hex_size,
user_id: user.id,
start_date: start_date,
end_date: end_date
)
expect(query.user_id).to eq(user.id)
expect(query.start_date).to eq(start_date)
expect(query.end_date).to eq(end_date)
end
end
describe '#call' do
let(:query) do
described_class.new(
min_lon: min_lon,
min_lat: min_lat,
max_lon: max_lon,
max_lat: max_lat,
hex_size: hex_size,
user_id: user.id
)
end
context 'with no points' do
it 'executes without error and returns empty result' do
result = query.call
expect(result.to_a).to be_empty
end
end
context 'with points in bounding box' do
before do
# Create test points within the bounding box
create(:point,
user:,
latitude: 40.7,
longitude: -74.0,
timestamp: Time.new(2024, 6, 15, 12, 0).to_i)
create(:point,
user:,
latitude: 40.75,
longitude: -73.95,
timestamp: Time.new(2024, 6, 16, 14, 0).to_i)
end
it 'returns hexagon results with expected structure' do
result = query.call
result_array = result.to_a
expect(result_array).not_to be_empty
first_hex = result_array.first
expect(first_hex).to have_key('geojson')
expect(first_hex).to have_key('hex_i')
expect(first_hex).to have_key('hex_j')
expect(first_hex).to have_key('point_count')
expect(first_hex).to have_key('earliest_point')
expect(first_hex).to have_key('latest_point')
expect(first_hex).to have_key('id')
# Verify geojson can be parsed
geojson = JSON.parse(first_hex['geojson'])
expect(geojson).to have_key('type')
expect(geojson).to have_key('coordinates')
end
it 'filters by user_id correctly' do
other_user = create(:user)
# Create points for a different user (should be excluded)
create(:point,
user: other_user,
latitude: 40.72,
longitude: -73.98,
timestamp: Time.new(2024, 6, 17, 16, 0).to_i)
result = query.call
result_array = result.to_a
# Should only include hexagons with the specified user's points
total_points = result_array.sum { |row| row['point_count'].to_i }
expect(total_points).to eq(2) # Only the 2 points from our user
end
end
context 'with date filtering' do
let(:query_with_dates) do
described_class.new(
min_lon: min_lon,
min_lat: min_lat,
max_lon: max_lon,
max_lat: max_lat,
hex_size: hex_size,
user_id: user.id,
start_date: '2024-06-15T00:00:00Z',
end_date: '2024-06-16T23:59:59Z'
)
end
before do
# Create points within and outside the date range
create(:point,
user:,
latitude: 40.7,
longitude: -74.0,
timestamp: Time.new(2024, 6, 15, 12, 0).to_i) # Within range
create(:point,
user:,
latitude: 40.71,
longitude: -74.01,
timestamp: Time.new(2024, 6, 20, 12, 0).to_i) # Outside range
end
it 'filters points by date range' do
result = query_with_dates.call
result_array = result.to_a
expect(result_array).not_to be_empty
# Should only include the point within the date range
total_points = result_array.sum { |row| row['point_count'].to_i }
expect(total_points).to eq(1)
end
end
context 'without user_id filter' do
let(:query_no_user) do
described_class.new(
min_lon: min_lon,
min_lat: min_lat,
max_lon: max_lon,
max_lat: max_lat,
hex_size: hex_size
)
end
before do
user1 = create(:user)
user2 = create(:user)
create(:point, user: user1, latitude: 40.7, longitude: -74.0, timestamp: Time.current.to_i)
create(:point, user: user2, latitude: 40.75, longitude: -73.95, timestamp: Time.current.to_i)
end
it 'includes points from all users' do
result = query_no_user.call
result_array = result.to_a
expect(result_array).not_to be_empty
# Should include points from both users
total_points = result_array.sum { |row| row['point_count'].to_i }
expect(total_points).to eq(2)
end
end
end
describe '#build_date_filter (private method behavior)' do
context 'when testing date filter behavior through query execution' do
it 'works correctly with start_date only' do
query = described_class.new(
min_lon: min_lon,
min_lat: min_lat,
max_lon: max_lon,
max_lat: max_lat,
hex_size: hex_size,
user_id: user.id,
start_date: '2024-06-15T00:00:00Z'
)
# Should execute without SQL syntax errors
expect { query.call }.not_to raise_error
end
it 'works correctly with end_date only' do
query = described_class.new(
min_lon: min_lon,
min_lat: min_lat,
max_lon: max_lon,
max_lat: max_lat,
hex_size: hex_size,
user_id: user.id,
end_date: '2024-06-30T23:59:59Z'
)
# Should execute without SQL syntax errors
expect { query.call }.not_to raise_error
end
it 'works correctly with both start_date and end_date' do
query = described_class.new(
min_lon: min_lon,
min_lat: min_lat,
max_lon: max_lon,
max_lat: max_lat,
hex_size: hex_size,
user_id: user.id,
start_date: '2024-06-01T00:00:00Z',
end_date: '2024-06-30T23:59:59Z'
)
# Should execute without SQL syntax errors
expect { query.call }.not_to raise_error
end
end
end
end