diff --git a/include/just_gtfs/just_gtfs.h b/include/just_gtfs/just_gtfs.h index 4077c02..9fbb789 100644 --- a/include/just_gtfs/just_gtfs.h +++ b/include/just_gtfs/just_gtfs.h @@ -1840,7 +1840,7 @@ inline Result Feed::add_fare_attributes(const ParsedCsvRow & row) item.currency_type = row.at("currency_type"); set_field(item.payment_method, row, "payment_method", false); - set_field(item.transfers, row, "transfers", false); + set_field(item.transfers, row, "transfers"); // Conditionally optional: item.agency_id = get_value_or_default(row, "agency_id"); @@ -2779,7 +2779,11 @@ inline void Feed::write_fare_attributes(std::ofstream & out) const { std::vector fields{ wrap(attribute.fare_id), wrap(attribute.price), attribute.currency_type, - wrap(attribute.payment_method), wrap(attribute.transfers), wrap(attribute.agency_id), + wrap(attribute.payment_method), + // Here we handle GTFS specification corner case: "The fact that this field can be left + // empty is an exception to the requirement that a Required field must not be empty.": + attribute.transfers == FareTransfers::Unlimited? "" : wrap(attribute.transfers), + wrap(attribute.agency_id), wrap(attribute.transfer_duration)}; write_joined(out, std::move(fields)); } diff --git a/tests/data/sample_feed/fare_attributes.txt b/tests/data/sample_feed/fare_attributes.txt index 3ee7a99..22b7efb 100644 --- a/tests/data/sample_feed/fare_attributes.txt +++ b/tests/data/sample_feed/fare_attributes.txt @@ -1,3 +1,4 @@ fare_id,price,currency_type,payment_method,transfers,transfer_duration p,1.25,USD,0,0, -a,5.25,USD,0,0, \ No newline at end of file +a,5.25,USD,1,1, +x,20,USD,0,,60 \ No newline at end of file diff --git a/tests/unit_tests.cpp b/tests/unit_tests.cpp index 4fc646e..5eafc31 100644 --- a/tests/unit_tests.cpp +++ b/tests/unit_tests.cpp @@ -310,7 +310,7 @@ TEST_CASE("Read GTFS feed") CHECK_EQ(feed.get_attributions().size(), 1); CHECK_EQ(feed.get_calendar().size(), 2); CHECK_EQ(feed.get_calendar_dates().size(), 1); - CHECK_EQ(feed.get_fare_attributes().size(), 2); + CHECK_EQ(feed.get_fare_attributes().size(), 3); CHECK_EQ(feed.get_fare_rules().size(), 4); CHECK(!feed.get_feed_info().feed_publisher_name.empty()); CHECK_EQ(feed.get_levels().size(), 3); @@ -494,7 +494,7 @@ TEST_CASE("Fare attributes") REQUIRE_EQ(feed.read_fare_attributes(), ResultCode::OK); const auto & attributes = feed.get_fare_attributes(); - REQUIRE_EQ(attributes.size(), 2); + REQUIRE_EQ(attributes.size(), 3); CHECK_EQ(attributes[0].fare_id, "p"); CHECK_EQ(attributes[0].price, 1.25); CHECK_EQ(attributes[0].currency_type, "USD"); @@ -502,6 +502,20 @@ TEST_CASE("Fare attributes") CHECK_EQ(attributes[0].transfers, FareTransfers::No); CHECK_EQ(attributes[0].transfer_duration, 0); + CHECK_EQ(attributes[1].fare_id, "a"); + CHECK_EQ(attributes[1].price, 5.25); + CHECK_EQ(attributes[1].currency_type, "USD"); + CHECK_EQ(attributes[1].payment_method, FarePayment::BeforeBoarding); + CHECK_EQ(attributes[1].transfers, FareTransfers::Once); + CHECK_EQ(attributes[1].transfer_duration, 0); + + CHECK_EQ(attributes[2].fare_id, "x"); + CHECK_EQ(attributes[2].price, 20); + CHECK_EQ(attributes[2].currency_type, "USD"); + CHECK_EQ(attributes[2].payment_method, FarePayment::OnBoard); + CHECK_EQ(attributes[2].transfers, FareTransfers::Unlimited); + CHECK_EQ(attributes[2].transfer_duration, 60); + const auto & attributes_for_id = feed.get_fare_attributes("a"); REQUIRE_EQ(attributes_for_id.size(), 1); CHECK_EQ(attributes_for_id[0].price, 5.25);