mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-11 01:31:39 -05:00
200 lines
No EOL
4.9 KiB
Ruby
200 lines
No EOL
4.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'rails_helper'
|
|
|
|
RSpec.describe LocationSearch::GeocodingService do
|
|
let(:query) { 'Kaufland Berlin' }
|
|
let(:service) { described_class.new(query) }
|
|
|
|
describe '#search' do
|
|
context 'with valid query' do
|
|
let(:mock_geocoder_result) do
|
|
double(
|
|
'Geocoder::Result',
|
|
latitude: 52.5200,
|
|
longitude: 13.4050,
|
|
address: 'Kaufland, Alexanderplatz 1, Berlin',
|
|
data: {
|
|
'type' => 'shop',
|
|
'osm_id' => '12345',
|
|
'place_rank' => 30,
|
|
'importance' => 0.8
|
|
}
|
|
)
|
|
end
|
|
|
|
before do
|
|
allow(Geocoder).to receive(:search).and_return([mock_geocoder_result])
|
|
allow(Geocoder.config).to receive(:lookup).and_return(:photon)
|
|
end
|
|
|
|
it 'returns normalized geocoding results' do
|
|
results = service.search
|
|
|
|
expect(results).to be_an(Array)
|
|
expect(results.first).to include(
|
|
lat: 52.5200,
|
|
lon: 13.4050,
|
|
name: 'Kaufland',
|
|
address: 'Kaufland, Alexanderplatz 1, Berlin',
|
|
type: 'shop'
|
|
)
|
|
end
|
|
|
|
it 'includes provider data' do
|
|
results = service.search
|
|
|
|
expect(results.first[:provider_data]).to include(
|
|
osm_id: '12345',
|
|
place_rank: 30,
|
|
importance: 0.8
|
|
)
|
|
end
|
|
|
|
it 'caches results' do
|
|
expect(Rails.cache).to receive(:fetch).and_call_original
|
|
|
|
service.search
|
|
end
|
|
|
|
it 'limits results to MAX_RESULTS' do
|
|
expect(Geocoder).to receive(:search).with(query, limit: 10)
|
|
|
|
service.search
|
|
end
|
|
|
|
context 'with cached results' do
|
|
let(:cached_results) { [{ lat: 1.0, lon: 2.0, name: 'Cached' }] }
|
|
|
|
before do
|
|
allow(Rails.cache).to receive(:fetch).and_return(cached_results)
|
|
end
|
|
|
|
it 'returns cached results without calling Geocoder' do
|
|
expect(Geocoder).not_to receive(:search)
|
|
|
|
results = service.search
|
|
expect(results).to eq(cached_results)
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'with blank query' do
|
|
let(:service) { described_class.new('') }
|
|
|
|
it 'returns empty array' do
|
|
expect(service.search).to eq([])
|
|
end
|
|
end
|
|
|
|
context 'when Geocoder returns no results' do
|
|
before do
|
|
allow(Geocoder).to receive(:search).and_return([])
|
|
end
|
|
|
|
it 'returns empty array' do
|
|
expect(service.search).to eq([])
|
|
end
|
|
end
|
|
|
|
context 'when Geocoder raises an error' do
|
|
before do
|
|
allow(Geocoder).to receive(:search).and_raise(StandardError.new('Geocoding error'))
|
|
end
|
|
|
|
it 'handles error gracefully and returns empty array' do
|
|
expect(service.search).to eq([])
|
|
end
|
|
end
|
|
|
|
context 'with invalid coordinates' do
|
|
let(:invalid_result) do
|
|
double(
|
|
'Geocoder::Result',
|
|
latitude: 91.0, # Invalid latitude
|
|
longitude: 13.4050,
|
|
address: 'Invalid location',
|
|
data: {}
|
|
)
|
|
end
|
|
|
|
let(:valid_result) do
|
|
double(
|
|
'Geocoder::Result',
|
|
latitude: 52.5200,
|
|
longitude: 13.4050,
|
|
address: 'Valid location',
|
|
data: {}
|
|
)
|
|
end
|
|
|
|
before do
|
|
allow(Geocoder).to receive(:search).and_return([invalid_result, valid_result])
|
|
end
|
|
|
|
it 'filters out results with invalid coordinates' do
|
|
results = service.search
|
|
|
|
expect(results.length).to eq(1)
|
|
expect(results.first[:lat]).to eq(52.5200)
|
|
end
|
|
end
|
|
|
|
describe '#deduplicate_results' do
|
|
let(:duplicate_results) do
|
|
[
|
|
{
|
|
lat: 52.5200,
|
|
lon: 13.4050,
|
|
name: 'Location 1',
|
|
address: 'Address 1',
|
|
type: 'shop',
|
|
provider_data: {}
|
|
},
|
|
{
|
|
lat: 52.5201, # Within 100m of first location
|
|
lon: 13.4051,
|
|
name: 'Location 2',
|
|
address: 'Address 2',
|
|
type: 'shop',
|
|
provider_data: {}
|
|
}
|
|
]
|
|
end
|
|
|
|
let(:mock_results) do
|
|
duplicate_results.map do |result|
|
|
double(
|
|
'Geocoder::Result',
|
|
latitude: result[:lat],
|
|
longitude: result[:lon],
|
|
address: result[:address],
|
|
data: { 'type' => result[:type] }
|
|
)
|
|
end
|
|
end
|
|
|
|
before do
|
|
allow(Geocoder).to receive(:search).and_return(mock_results)
|
|
end
|
|
|
|
it 'removes locations within 100m of each other' do
|
|
service = described_class.new('test')
|
|
results = service.search
|
|
|
|
expect(results.length).to eq(1)
|
|
expect(results.first[:name]).to eq('Address 1')
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#provider_name' do
|
|
before do
|
|
allow(Geocoder.config).to receive(:lookup).and_return(:nominatim)
|
|
end
|
|
|
|
it 'returns the current geocoding provider name' do
|
|
expect(service.provider_name).to eq('Nominatim')
|
|
end
|
|
end
|
|
end |