2025-05-13 13:43:02 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
|
|
require 'rails_helper'
|
|
|
|
|
|
|
|
|
|
RSpec.describe Trips::Countries do
|
|
|
|
|
let(:trip) { instance_double('Trip') }
|
|
|
|
|
let(:point1) { instance_double('Point', lonlat: factory.point(10.0, 50.0)) }
|
|
|
|
|
let(:point2) { instance_double('Point', lonlat: factory.point(20.0, 60.0)) }
|
|
|
|
|
let(:point3) { instance_double('Point', lonlat: factory.point(30.0, 70.0)) }
|
|
|
|
|
let(:point4) { instance_double('Point', lonlat: nil) }
|
|
|
|
|
let(:factory) { RGeo::Geographic.spherical_factory }
|
|
|
|
|
let(:points) { [point1, point2, point3, point4] }
|
|
|
|
|
|
|
|
|
|
let(:geo_json_content) do
|
|
|
|
|
{
|
|
|
|
|
type: 'FeatureCollection',
|
|
|
|
|
features: [
|
|
|
|
|
{
|
|
|
|
|
type: 'Feature',
|
|
|
|
|
properties: { ADMIN: 'Germany', ISO_A3: 'DEU', ISO_A2: 'DE' },
|
|
|
|
|
geometry: { type: 'MultiPolygon', coordinates: [] }
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}.to_json
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
allow(trip).to receive(:points).and_return(points)
|
|
|
|
|
allow(File).to receive(:read).with(Trips::Countries::FILE_PATH).and_return(geo_json_content)
|
|
|
|
|
|
|
|
|
|
# Explicitly stub all Geocoder calls with specific coordinates
|
2025-05-13 14:21:18 -04:00
|
|
|
allow(Geocoder).to receive(:search).and_return(
|
|
|
|
|
[double(data: { 'properties' => { 'countrycode' => 'DE' } })]
|
|
|
|
|
)
|
|
|
|
|
allow(Geocoder).to receive(:search).with([50.0, 10.0], limit: 1).and_return(
|
|
|
|
|
[double(data: { 'properties' => { 'countrycode' => 'DE' } })]
|
|
|
|
|
)
|
|
|
|
|
allow(Geocoder).to receive(:search).with([60.0, 20.0], limit: 1).and_return(
|
|
|
|
|
[double(data: { 'properties' => { 'countrycode' => 'SE' } })]
|
|
|
|
|
)
|
|
|
|
|
allow(Geocoder).to receive(:search).with([70.0, 30.0], limit: 1).and_return(
|
|
|
|
|
[double(data: { 'properties' => { 'countrycode' => 'FI' } })]
|
|
|
|
|
)
|
2025-05-13 13:43:02 -04:00
|
|
|
|
|
|
|
|
allow(Rails.logger).to receive(:info)
|
|
|
|
|
allow(Rails.logger).to receive(:error)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe '#call' do
|
|
|
|
|
it 'returns a hash with country counts' do
|
|
|
|
|
allow(Thread).to receive(:new).and_yield
|
|
|
|
|
|
|
|
|
|
result = described_class.new(trip).call
|
|
|
|
|
|
2025-05-15 12:36:05 -04:00
|
|
|
expect(result).to match_array(%w[DE SE FI])
|
2025-05-13 13:43:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'handles points without coordinates' do
|
|
|
|
|
allow(Thread).to receive(:new).and_yield
|
|
|
|
|
|
|
|
|
|
result = described_class.new(trip).call
|
|
|
|
|
|
2025-05-15 12:36:05 -04:00
|
|
|
expect(result.size).to eq(3) # Should only count the 3 valid points
|
2025-05-13 13:43:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'processes batches in multiple threads' do
|
|
|
|
|
expect(Thread).to receive(:new).at_least(:twice).and_yield
|
|
|
|
|
|
|
|
|
|
described_class.new(trip).call
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'sorts countries by count in descending order' do
|
|
|
|
|
allow(Thread).to receive(:new).and_yield
|
|
|
|
|
allow(points).to receive(:to_a).and_return([point1, point1, point2, point3, point4])
|
|
|
|
|
|
|
|
|
|
result = described_class.new(trip).call
|
|
|
|
|
|
2025-05-15 12:36:05 -04:00
|
|
|
expect(result.first).to eq('DE')
|
2025-05-13 13:43:02 -04:00
|
|
|
end
|
2025-05-13 14:33:04 -04:00
|
|
|
|
|
|
|
|
context 'when an error occurs' do
|
|
|
|
|
before do
|
|
|
|
|
allow(Geocoder).to receive(:search).and_raise(Geocoder::Error, 'Error')
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'calls the exception reporter' do
|
|
|
|
|
expect(ExceptionReporter).to receive(:call).with(Geocoder::Error).at_least(3).times
|
|
|
|
|
|
|
|
|
|
described_class.new(trip).call
|
|
|
|
|
end
|
|
|
|
|
end
|
2025-05-13 13:43:02 -04:00
|
|
|
end
|
|
|
|
|
end
|