diff --git a/src/rt/gtfsrt_update.cc b/src/rt/gtfsrt_update.cc index 86a4f899..a745b242 100644 --- a/src/rt/gtfsrt_update.cc +++ b/src/rt/gtfsrt_update.cc @@ -123,6 +123,21 @@ void cancel_run(timetable const&, rt_timetable& rtt, run& r) { } } +unixtime_t fallback_pred(rt_timetable const& rtt, + run const& r, + std::optional const pred, + stop_idx_t const stop_idx, + event_type const ev_type) { + if (pred.has_value()) { + return pred->pred_time_; + } + if (stop_idx == 0U) { + return unixtime_t{0_minutes}; + } + return rtt.unix_event_time( + r.rt_, ev_type == event_type::kDep ? stop_idx - 1U : stop_idx, ev_type); +} + void update_run( source_idx_t const src, timetable const& tt, @@ -223,7 +238,7 @@ void update_run( (upd_it->arrival().has_delay() || upd_it->arrival().has_time())) { pred = update_event( tt, rtt, r, stop_idx, event_type::kArr, upd_it->arrival(), - pred.has_value() ? pred->pred_time_ : unixtime_t{0_minutes}); + fallback_pred(rtt, r, pred, stop_idx, event_type::kDep)); } else if (pred.has_value()) { pred = update_delay(tt, rtt, r, stop_idx, event_type::kArr, pred->pred_delay_, pred->pred_time_); @@ -245,7 +260,7 @@ void update_run( (upd_it->departure().has_time() || upd_it->departure().has_delay())) { pred = update_event( tt, rtt, r, stop_idx, event_type::kDep, upd_it->departure(), - pred.has_value() ? pred->pred_time_ : unixtime_t{0_minutes}); + fallback_pred(rtt, r, pred, stop_idx, event_type::kArr)); } else if (pred.has_value()) { pred = update_delay(tt, rtt, r, stop_idx, event_type::kDep, pred->pred_delay_, pred->pred_time_); diff --git a/test/rt/gtfsrt_relative_test.cc b/test/rt/gtfsrt_relative_test.cc new file mode 100644 index 00000000..b8bca1ec --- /dev/null +++ b/test/rt/gtfsrt_relative_test.cc @@ -0,0 +1,143 @@ +#include "gtest/gtest.h" + +#include "google/protobuf/util/json_util.h" + +#include "nigiri/loader/gtfs/files.h" +#include "nigiri/loader/gtfs/load_timetable.h" +#include "nigiri/loader/init_finish.h" +#include "nigiri/rt/create_rt_timetable.h" +#include "nigiri/rt/frun.h" +#include "nigiri/rt/gtfsrt_resolve_run.h" +#include "nigiri/rt/gtfsrt_update.h" +#include "nigiri/rt/util.h" +#include "nigiri/timetable.h" + +#include "./util.h" + +using namespace nigiri; +using namespace nigiri::loader; +using namespace nigiri::loader::gtfs; +using namespace nigiri::rt; +using namespace date; +using namespace std::chrono_literals; +using namespace std::string_literals; +using namespace std::string_view_literals; + +namespace { + +mem_dir test_files() { + return mem_dir::read(R"( + "( +# agency.txt +agency_name,agency_url,agency_timezone,agency_lang,agency_phone,agency_id +test,https://test.com,Europe/Berlin,DE,0800123456,AGENCY_1 + +# stops.txt +stop_id,stop_name,stop_lat,stop_lon +A,A,1.0,1.0 +B,B,2.0,2.0 +C,C,3.0,3.0 +D,D,4.0,4.0 +E,E,5.0,5.0 +F,F,6.0,6.0 + +# calendar_dates.txt +service_id,date,exception_type +SERVICE_1,20231126,1 + +# routes.txt +route_id,agency_id,route_short_name,route_long_name,route_type +ROUTE_1,AGENCY_1,Route 1,,3 + +# trips.txt +route_id,service_id,trip_id,trip_headsign,block_id, +ROUTE_1,SERVICE_1,TRIP_1,E,, + +# stop_times.txt +trip_id,arrival_time,departure_time,stop_id,stop_sequence,pickup_type,drop_off_type +TRIP_1,10:00:00,10:00:00,A,1,0,0 +TRIP_1,11:00:00,11:00:00,B,2,0,0 +TRIP_1,12:00:00,12:00:00,C,3,0,0 +TRIP_1,13:00:00,13:00:00,D,4,0,0 +TRIP_1,14:00:00,14:00:00,E,5,0,0 +TRIP_1,15:00:00,15:00:00,F,6,0,0 +)"); +} + +auto const kTripUpdate = + R"({ + "header": { + "gtfsRealtimeVersion": "2.0", + "incrementality": "FULL_DATASET", + "timestamp": "1691660324" + }, + "entity": [ + { + "id": "3248651", + "isDeleted": false, + "tripUpdate": { + "trip": { + "tripId": "TRIP_1", + "startTime": "10:00:00", + "startDate": "20231126" + }, + "stopTimeUpdate": [ + { + "stop_sequence":3, + "arrival":{"delay":-5400}, + "departure":{"delay":-5400}, + "schedule_relationship":"SCHEDULED" + }, + { + "stop_sequence":5, + "arrival":{"delay":-5460}, + "departure":{"delay":-5520}, + "schedule_relationship":"SCHEDULED" + } + ] + } + } + ] +})"s; + +constexpr auto const expected = R"( + 0: A A............................................... d: 26.11 09:00 [26.11 10:00] RT 26.11 09:00 [26.11 10:00] [{name=Bus Route 1, day=2023-11-26, id=TRIP_1, src=0}] + 1: B B............................................... a: 26.11 10:00 [26.11 11:00] RT 26.11 10:00 [26.11 11:00] d: 26.11 10:00 [26.11 11:00] RT 26.11 10:00 [26.11 11:00] [{name=Bus Route 1, day=2023-11-26, id=TRIP_1, src=0}] + 2: C C............................................... a: 26.11 11:00 [26.11 12:00] RT 26.11 10:00 [26.11 11:00] d: 26.11 11:00 [26.11 12:00] RT 26.11 10:00 [26.11 11:00] [{name=Bus Route 1, day=2023-11-26, id=TRIP_1, src=0}] + 3: D D............................................... a: 26.11 12:00 [26.11 13:00] RT 26.11 10:30 [26.11 11:30] d: 26.11 12:00 [26.11 13:00] RT 26.11 10:30 [26.11 11:30] [{name=Bus Route 1, day=2023-11-26, id=TRIP_1, src=0}] + 4: E E............................................... a: 26.11 13:00 [26.11 14:00] RT 26.11 11:29 [26.11 12:29] d: 26.11 13:00 [26.11 14:00] RT 26.11 11:29 [26.11 12:29] [{name=Bus Route 1, day=2023-11-26, id=TRIP_1, src=0}] + 5: F F............................................... a: 26.11 14:00 [26.11 15:00] RT 26.11 12:28 [26.11 13:28] +)"sv; + +} // namespace + +TEST(rt, gtfs_rt_relative) { + // Load static timetable. + timetable tt; + register_special_stations(tt); + tt.date_range_ = {date::sys_days{2023_y / November / 25}, + date::sys_days{2023_y / November / 27}}; + load_timetable({}, source_idx_t{0}, test_files(), tt); + finalize(tt); + + // Create empty RT timetable. + auto rtt = + rt::create_rt_timetable(tt, date::sys_days{2023_y / November / 26}); + + // Update. + auto const msg = rt::json_to_protobuf(kTripUpdate); + gtfsrt_update_buf(tt, rtt, source_idx_t{0}, "", msg); + + // Print trip. + transit_realtime::TripDescriptor td; + td.set_start_date("20231126"); + td.set_trip_id("TRIP_1"); + td.set_start_time("10:00:00"); + auto const [r, t] = rt::gtfsrt_resolve_run( + date::sys_days{2023_y / November / 26}, tt, &rtt, source_idx_t{0}, td); + ASSERT_TRUE(r.valid()); + + auto ss = std::stringstream{}; + ss << "\n" << rt::frun{tt, &rtt, r}; + EXPECT_EQ(expected, ss.str()); +} \ No newline at end of file diff --git a/test/rt/gtfsrt_rt_test.cc b/test/rt/gtfsrt_rt_test.cc index 405f5d02..01ffa4ef 100644 --- a/test/rt/gtfsrt_rt_test.cc +++ b/test/rt/gtfsrt_rt_test.cc @@ -273,7 +273,7 @@ auto const kTripUpdate = "time": "1691661152" }, "departure": { - "time": "1691661152" + "time": "0" }, "stopId": "2524", "scheduleRelationship": "SCHEDULED"