diff --git a/spec/services/maps/bounds_calculator_spec.rb b/spec/services/maps/bounds_calculator_spec.rb index c2265b5f..0f508550 100644 --- a/spec/services/maps/bounds_calculator_spec.rb +++ b/spec/services/maps/bounds_calculator_spec.rb @@ -95,14 +95,11 @@ RSpec.describe Maps::BoundsCalculator do end end - context 'with lenient date parsing' do + context 'with invalid date parsing' do let(:start_date) { 'invalid-date' } - it 'handles invalid dates gracefully via Time.zone.parse' do - # Time.zone.parse is very lenient and rarely raises errors - # It will parse 'invalid-date' as a valid time - result = calculate_bounds - expect(result[:success]).to be false # No points in weird date range + it 'raises ArgumentError for invalid dates' do + expect { calculate_bounds }.to raise_error(ArgumentError, 'Invalid date format: invalid-date') end end diff --git a/spec/services/maps/hexagon_center_manager_spec.rb b/spec/services/maps/hexagon_center_manager_spec.rb index e1b3f1fa..47d7f8c9 100644 --- a/spec/services/maps/hexagon_center_manager_spec.rb +++ b/spec/services/maps/hexagon_center_manager_spec.rb @@ -49,52 +49,6 @@ RSpec.describe Maps::HexagonCenterManager do end end - context 'with legacy area_too_large flag' do - let(:stat) do - create(:stat, user:, year: 2024, month: 6, h3_hex_ids: { 'area_too_large' => true }) - end - - before do - # Mock the Stats::CalculateMonth service - allow_any_instance_of(Stats::CalculateMonth).to receive(:calculate_hexagon_centers) - .and_return(new_centers) - end - - context 'when recalculation succeeds' do - let(:new_centers) do - [ - [-74.0, 40.7, 1_717_200_000, 1_717_203_600], - [-74.01, 40.71, 1_717_210_000, 1_717_213_600] - ] - end - - it 'recalculates and updates the stat' do - expect(stat).to receive(:update).with(h3_hex_ids: new_centers) - - result = manage_centers - - expect(result[:success]).to be true - expect(result[:pre_calculated]).to be true - expect(result[:data]['features'].length).to eq(2) - end - end - - context 'when recalculation fails' do - let(:new_centers) { nil } - - it 'returns nil' do - expect(manage_centers).to be_nil - end - end - - context 'when recalculation returns area_too_large again' do - let(:new_centers) { { area_too_large: true } } - - it 'returns nil' do - expect(manage_centers).to be_nil - end - end - end context 'with no stat' do let(:stat) { nil } @@ -113,7 +67,7 @@ RSpec.describe Maps::HexagonCenterManager do end context 'with empty hexagon_centers' do - let(:stat) { create(:stat, user:, year: 2024, month: 6, h3_hex_ids: []) } + let(:stat) { create(:stat, user:, year: 2024, month: 6, h3_hex_ids: {}) } it 'returns nil' do expect(manage_centers).to be_nil diff --git a/spec/services/maps/hexagon_polygon_generator_spec.rb b/spec/services/maps/hexagon_polygon_generator_spec.rb index 662d42c2..5d8466d5 100644 --- a/spec/services/maps/hexagon_polygon_generator_spec.rb +++ b/spec/services/maps/hexagon_polygon_generator_spec.rb @@ -5,17 +5,14 @@ require 'rails_helper' RSpec.describe Maps::HexagonPolygonGenerator do describe '.call' do subject(:generate_polygon) do - described_class.new( - center_lng: center_lng, - center_lat: center_lat - ).call + described_class.new(h3_index: h3_index).call end - let(:center_lng) { -74.0 } - let(:center_lat) { 40.7 } + # Valid H3 index for NYC area (resolution 6) + let(:h3_index) { '8a1fb46622dffff' } - it 'returns a polygon geometry using H3' do - result = generate_h3_polygon + it 'returns a polygon geometry' do + result = generate_polygon expect(result['type']).to eq('Polygon') expect(result['coordinates']).to be_an(Array) @@ -23,7 +20,7 @@ RSpec.describe Maps::HexagonPolygonGenerator do end it 'generates a hexagon with 7 coordinate pairs (6 vertices + closing)' do - result = generate_h3_polygon + result = generate_polygon coordinates = result['coordinates'].first expect(coordinates.length).to eq(7) # 6 vertices + closing vertex @@ -31,7 +28,7 @@ RSpec.describe Maps::HexagonPolygonGenerator do end it 'generates unique vertices' do - result = generate_h3_polygon + result = generate_polygon coordinates = result['coordinates'].first # Remove the closing vertex for uniqueness check @@ -39,44 +36,55 @@ RSpec.describe Maps::HexagonPolygonGenerator do expect(unique_vertices.uniq.length).to eq(6) # All vertices should be unique end - it 'generates vertices around the center point' do - result = generate_h3_polygon + it 'generates vertices in proper [lng, lat] format' do + result = generate_polygon coordinates = result['coordinates'].first - # Check that vertices have some variation in coordinates - longitudes = coordinates[0..5].map { |vertex| vertex[0] } - latitudes = coordinates[0..5].map { |vertex| vertex[1] } + coordinates.each do |vertex| + lng, lat = vertex + expect(lng).to be_a(Float) + expect(lat).to be_a(Float) + expect(lng).to be_between(-180, 180) + expect(lat).to be_between(-90, 90) + end + end - expect(longitudes.uniq.size).to be > 1 # Should have different longitudes - expect(latitudes.uniq.size).to be > 1 # Should have different latitudes + context 'with hex string index' do + let(:h3_index) { '8a1fb46622dffff' } + + it 'handles hex string format' do + result = generate_polygon + expect(result['type']).to eq('Polygon') + expect(result['coordinates'].first.length).to eq(7) + end + end + + context 'with integer index' do + let(:h3_index) { 0x8a1fb46622dffff } + + it 'handles integer format' do + result = generate_polygon + expect(result['type']).to eq('Polygon') + expect(result['coordinates'].first.length).to eq(7) + end end context 'when H3 operations fail' do before do - allow(H3).to receive(:from_geo_coordinates).and_raise(StandardError, 'H3 error') + allow(H3).to receive(:to_boundary).and_raise(StandardError, 'H3 error') end it 'raises the H3 error' do - expect { generate_h3_polygon }.to raise_error(StandardError, 'H3 error') + expect { generate_polygon }.to raise_error(StandardError, 'H3 error') end end - private + context 'with invalid H3 index' do + let(:h3_index) { nil } - def calculate_hexagon_size(coordinates) - # Calculate distance between first two vertices as size approximation - vertex1 = coordinates[0] - vertex2 = coordinates[1] - - lng_diff = vertex2[0] - vertex1[0] - lat_diff = vertex2[1] - vertex1[1] - - Math.sqrt(lng_diff**2 + lat_diff**2) - end - - def calculate_distance_from_center(vertex) - lng, lat = vertex - Math.sqrt((lng - center_lng)**2 + (lat - center_lat)**2) + it 'raises an error for invalid index' do + expect { generate_polygon }.to raise_error(TypeError) + end end end -end +end \ No newline at end of file diff --git a/spec/services/maps/hexagon_request_handler_spec.rb b/spec/services/maps/hexagon_request_handler_spec.rb index abe9a089..45b9f84b 100644 --- a/spec/services/maps/hexagon_request_handler_spec.rb +++ b/spec/services/maps/hexagon_request_handler_spec.rb @@ -8,15 +8,18 @@ RSpec.describe Maps::HexagonRequestHandler do described_class.new( params: params, user: user, - stat: nil, - start_date: params[:start_date], - end_date: params[:end_date] + stat: stat, + start_date: start_date, + end_date: end_date ).call end let(:user) { create(:user) } context 'with authenticated user but no pre-calculated data' do + let(:stat) { nil } + let(:start_date) { '2024-06-01T00:00:00Z' } + let(:end_date) { '2024-06-30T23:59:59Z' } let(:params) do ActionController::Parameters.new( { @@ -24,8 +27,8 @@ RSpec.describe Maps::HexagonRequestHandler do min_lat: 40.6, max_lon: -73.9, max_lat: 40.8, - start_date: '2024-06-01T00:00:00Z', - end_date: '2024-06-30T23:59:59Z' + start_date: start_date, + end_date: end_date } ) end @@ -52,6 +55,8 @@ RSpec.describe Maps::HexagonRequestHandler do create(:stat, :with_sharing_enabled, user:, year: 2024, month: 6, h3_hex_ids: pre_calculated_centers) end + let(:start_date) { Date.new(2024, 6, 1).beginning_of_day.iso8601 } + let(:end_date) { Date.new(2024, 6, 1).end_of_month.end_of_day.iso8601 } let(:params) do ActionController::Parameters.new( { @@ -76,6 +81,8 @@ RSpec.describe Maps::HexagonRequestHandler do context 'with public sharing UUID but no pre-calculated centers' do let(:stat) { create(:stat, :with_sharing_enabled, user:, year: 2024, month: 6) } + let(:start_date) { Date.new(2024, 6, 1).beginning_of_day.iso8601 } + let(:end_date) { Date.new(2024, 6, 1).end_of_month.end_of_day.iso8601 } let(:params) do ActionController::Parameters.new( { @@ -98,11 +105,13 @@ RSpec.describe Maps::HexagonRequestHandler do end end - context 'with legacy area_too_large that can be recalculated' do + context 'with stat containing empty h3_hex_ids data' do let(:stat) do create(:stat, :with_sharing_enabled, user:, year: 2024, month: 6, - h3_hex_ids: { 'area_too_large' => true }) + h3_hex_ids: {}) end + let(:start_date) { Date.new(2024, 6, 1).beginning_of_day.iso8601 } + let(:end_date) { Date.new(2024, 6, 1).end_of_month.end_of_day.iso8601 } let(:params) do ActionController::Parameters.new( { @@ -115,21 +124,13 @@ RSpec.describe Maps::HexagonRequestHandler do ) end - before do - # Mock successful recalculation - allow_any_instance_of(Stats::CalculateMonth).to receive(:calculate_hexagon_centers) - .and_return([[-74.0, 40.7, 1_717_200_000, 1_717_203_600]]) - end - - it 'recalculates and returns pre-calculated data' do + it 'returns empty feature collection for empty data' do result = handle_request expect(result['type']).to eq('FeatureCollection') - expect(result['features'].length).to eq(1) - expect(result['metadata']['pre_calculated']).to be true - - # Verify that the stat was updated with new centers (reload to check persistence) - expect(stat.reload.h3_hex_ids).to eq([[-74.0, 40.7, 1_717_200_000, 1_717_203_600]]) + expect(result['features']).to eq([]) + expect(result['metadata']['hexagon_count']).to eq(0) + expect(result['metadata']['source']).to eq('pre_calculated') end end end