diff --git a/app/services/google_maps/semantic_history_parser.rb b/app/services/google_maps/semantic_history_parser.rb index 4231c965..b7c16236 100644 --- a/app/services/google_maps/semantic_history_parser.rb +++ b/app/services/google_maps/semantic_history_parser.rb @@ -57,15 +57,15 @@ class GoogleMaps::SemanticHistoryParser } end elsif timeline_object['placeVisit'].present? - if timeline_object['placeVisit']['location']['latitudeE7'].present? && - timeline_object['placeVisit']['location']['longitudeE7'].present? + if timeline_object.dig('placeVisit', 'location', 'latitudeE7').present? && + timeline_object.dig('placeVisit', 'location', 'longitudeE7').present? { latitude: timeline_object['placeVisit']['location']['latitudeE7'].to_f / 10**7, longitude: timeline_object['placeVisit']['location']['longitudeE7'].to_f / 10**7, timestamp: DateTime.parse(timeline_object['placeVisit']['duration']['startTimestamp']), raw_data: timeline_object } - elsif timeline_object['placeVisit']['otherCandidateLocations'].any? + elsif timeline_object.dig('placeVisit', 'otherCandidateLocations')&.any? point = timeline_object['placeVisit']['otherCandidateLocations'][0] next unless point['latitudeE7'].present? && point['longitudeE7'].present? diff --git a/spec/services/google_maps/semantic_history_parser_spec.rb b/spec/services/google_maps/semantic_history_parser_spec.rb index f52acaa1..800b0a35 100644 --- a/spec/services/google_maps/semantic_history_parser_spec.rb +++ b/spec/services/google_maps/semantic_history_parser_spec.rb @@ -4,5 +4,109 @@ require 'rails_helper' RSpec.describe GoogleMaps::SemanticHistoryParser do describe '#call' do + subject(:parser) { described_class.new(import, user.id).call } + + let(:user) { create(:user) } + + context 'when activitySegment is present' do + context 'when startLocation is blank' do + let(:import) { create(:import, raw_data: { 'timelineObjects' => [activity_segment] }) } + let(:activity_segment) do + { + 'activitySegment' => { + 'waypointPath' => { + 'waypoints' => [ + { 'latE7' => 123_456_789, 'lngE7' => 123_456_789 } + ] + }, + 'duration' => { 'startTimestamp' => Time.zone.now.to_s } + } + } + end + + it 'creates a point' do + expect { parser }.to change(Point, :count).by(1) + end + + context 'when waypointPath is blank' do + let(:activity_segment) do + { + 'activitySegment' => { + 'duration' => { 'startTimestamp' => Time.zone.now.to_s } + } + } + end + + it 'does not create a point' do + expect { parser }.not_to change(Point, :count) + end + end + end + + context 'when startLocation is present' do + let(:import) { create(:import, raw_data: { 'timelineObjects' => [activity_segment] }) } + let(:activity_segment) do + { + 'activitySegment' => { + 'startLocation' => { 'latitudeE7' => 123_456_789, 'longitudeE7' => 123_456_789 }, + 'duration' => { 'startTimestamp' => Time.zone.now.to_s } + } + } + end + + it 'creates a point' do + expect { parser }.to change(Point, :count).by(1) + end + end + end + + context 'when placeVisit is present' do + context 'when location with coordinates is present' do + let(:import) { create(:import, raw_data: { 'timelineObjects' => [place_visit] }) } + let(:place_visit) do + { + 'placeVisit' => { + 'location' => { 'latitudeE7' => 123_456_789, 'longitudeE7' => 123_456_789 }, + 'duration' => { 'startTimestamp' => Time.zone.now.to_s } + } + } + end + + it 'creates a point' do + expect { parser }.to change(Point, :count).by(1) + end + end + + context 'when location with coordinates is blank' do + let(:import) { create(:import, raw_data: { 'timelineObjects' => [place_visit] }) } + let(:place_visit) do + { + 'placeVisit' => { + 'location' => {}, + 'duration' => { 'startTimestamp' => Time.zone.now.to_s } + } + } + end + + it 'does not create a point' do + expect { parser }.not_to change(Point, :count) + end + + context 'when otherCandidateLocations is present' do + let(:place_visit) do + { + 'placeVisit' => { + 'otherCandidateLocations' => [{ 'latitudeE7' => 123_456_789, 'longitudeE7' => 123_456_789 }], + 'duration' => { 'startTimestamp' => Time.zone.now.to_s } + } + } + end + + it 'creates a point' do + expect { parser }.to change(Point, :count).by(1) + end + end + end + end end end