diff --git a/Cargo.toml b/Cargo.toml index e786972c7..13bc7e19d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Kisio Digital ", "Guillaume Pinot "] name = "transit_model" -version = "0.9.0" +version = "0.8.0" license = "AGPL-3.0" description = "Transit data management" repository = "https://github.com/CanalTP/transit_model" diff --git a/src/add_prefix.rs b/src/add_prefix.rs index bc0acc252..0a5e18e1f 100644 --- a/src/add_prefix.rs +++ b/src/add_prefix.rs @@ -60,6 +60,7 @@ impl AddPrefix for Collections { self.vehicle_journeys.add_prefix(&prefix); self.stop_areas.add_prefix(&prefix); self.stop_points.add_prefix(&prefix); + self.stop_locations.add_prefix(&prefix); self.calendars.add_prefix(&prefix); self.companies.add_prefix(&prefix); self.comments.add_prefix(&prefix); @@ -78,7 +79,6 @@ impl AddPrefix for Collections { self.ticket_use_restrictions.add_prefix(&prefix); self.pathways.add_prefix(&prefix); self.levels.add_prefix(&prefix); - self.stop_locations.add_prefix(&prefix); } } diff --git a/src/gtfs/mod.rs b/src/gtfs/mod.rs index b508a160c..162462eb5 100644 --- a/src/gtfs/mod.rs +++ b/src/gtfs/mod.rs @@ -91,28 +91,26 @@ enum StopLocationType { } impl Into for StopLocationType { - fn into(self) -> objects::StopType { - let stop_type = match self { - StopLocationType::StopPoint => objects::StopType::Point, - StopLocationType::StopArea => objects::StopType::Zone, - StopLocationType::StopEntrance => objects::StopType::StopEntrance, - StopLocationType::GenericNode => objects::StopType::GenericNode, - StopLocationType::BoardingArea => objects::StopType::BoardingArea, - }; - stop_type + fn into(self) -> StopType { + match self { + StopLocationType::StopPoint => StopType::Point, + StopLocationType::StopArea => StopType::Zone, + StopLocationType::StopEntrance => StopType::StopEntrance, + StopLocationType::GenericNode => StopType::GenericNode, + StopLocationType::BoardingArea => StopType::BoardingArea, + } } } impl From for StopLocationType { fn from(stop_type: StopType) -> StopLocationType { - let stop_location_type = match stop_type { - objects::StopType::Point => StopLocationType::StopPoint, - objects::StopType::Zone => StopLocationType::StopArea, - objects::StopType::StopEntrance => StopLocationType::StopEntrance, - objects::StopType::GenericNode => StopLocationType::GenericNode, - objects::StopType::BoardingArea => StopLocationType::BoardingArea, - }; - stop_location_type + match stop_type { + StopType::Point => StopLocationType::StopPoint, + StopType::Zone => StopLocationType::StopArea, + StopType::StopEntrance => StopLocationType::StopEntrance, + StopType::GenericNode => StopLocationType::GenericNode, + StopType::BoardingArea => StopLocationType::BoardingArea, + } } } @@ -122,7 +120,7 @@ struct Stop { id: String, #[serde(rename = "stop_code")] code: Option, - #[serde(rename = "stop_name")] //Conditionally Required + #[serde(rename = "stop_name")] name: String, #[serde( default, @@ -141,7 +139,7 @@ struct Stop { #[serde(default, deserialize_with = "de_with_empty_default")] location_type: StopLocationType, #[serde(default, deserialize_with = "de_option_without_slashes")] - parent_station: Option, //Conditionally Required + parent_station: Option, #[serde(rename = "stop_timezone")] timezone: Option, level_id: Option, @@ -285,7 +283,7 @@ where collections.networks = networks; collections.companies = companies; let (stop_areas, stop_points, stop_locations) = - read::manage_stops(file_handler, &mut comments, &mut equipments)?; + read::read_stops(file_handler, &mut comments, &mut equipments)?; collections.transfers = read::read_transfers(file_handler, &stop_points)?; collections.stop_areas = stop_areas; collections.stop_points = stop_points; @@ -298,7 +296,7 @@ where collections.comments = comments; read::manage_stop_times(&mut collections, file_handler)?; read::manage_frequencies(&mut collections, file_handler)?; - collections.pathways = read::read_pathways(file_handler)?; + collections.pathways = read::read_pathways(&mut collections, file_handler)?; collections.levels = read_utils::read_opt_collection(file_handler, "levels.txt")?; collections.sanitize()?; diff --git a/src/gtfs/read.rs b/src/gtfs/read.rs index cb036c50c..46d3ccff5 100644 --- a/src/gtfs/read.rs +++ b/src/gtfs/read.rs @@ -29,11 +29,12 @@ use crate::utils::*; use crate::Result; use csv; use derivative::Derivative; -use failure::{bail, format_err, ResultExt}; +use failure::{bail, format_err, Error, ResultExt}; use geo_types::{LineString, Point}; use log::{info, warn}; use serde::Deserialize; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; +use std::convert::TryFrom; use std::result::Result as StdResult; use transit_model_collection::{Collection, CollectionWithId, Id}; @@ -84,168 +85,119 @@ impl From for objects::Company { } } -impl From for objects::StopArea { - fn from(stop: Stop) -> objects::StopArea { +impl TryFrom for objects::StopArea { + type Error = Error; + fn try_from(stop: Stop) -> Result { let mut stop_codes: KeysValues = BTreeSet::new(); if let Some(c) = stop.code { stop_codes.insert(("gtfs_stop_code".to_string(), c)); } - let coord: Coord = Coord::from((stop.lon, stop.lat)); - objects::StopArea { - id: stop.id, - name: stop.name, - codes: stop_codes, - object_properties: KeysValues::default(), - comment_links: objects::CommentLinksT::default(), - coord: coord, - timezone: stop.timezone, - visible: true, - geometry_id: None, - level_id: stop.level_id, - equipment_id: None, + if stop.name.is_empty() { + warn!("stop_id: {}: for station stop_name is required", stop.id); } - } -} -impl Into> for Stop { - fn into(self) -> Result { - let mut stop_codes: KeysValues = BTreeSet::new(); - if let Some(c) = self.code { - stop_codes.insert(("gtfs_stop_code".to_string(), c)); - } - - if self.name.is_empty() { - warn!("stop_id: {}: for station stop_name is required", self.id); - } - - let coord: Coord = Coord::from((self.lon, self.lat)); + let coord = Coord::from((stop.lon, stop.lat)); if coord == Coord::default() { - warn!("stop_id: {}: for station coordinates are required", self.id); + warn!("stop_id: {}: for station coordinates are required", stop.id); } let stop_area = objects::StopArea { - id: self.id, - name: self.name, + id: stop.id, + name: stop.name, codes: stop_codes, object_properties: KeysValues::default(), comment_links: objects::CommentLinksT::default(), - coord: coord, - timezone: self.timezone, + coord, + timezone: stop.timezone, visible: true, geometry_id: None, - level_id: self.level_id, + level_id: stop.level_id, equipment_id: None, }; Ok(stop_area) } } -impl From for objects::StopPoint { - fn from(stop: Stop) -> objects::StopPoint { +impl TryFrom for objects::StopPoint { + type Error = Error; + fn try_from(stop: Stop) -> Result { let mut stop_codes: KeysValues = BTreeSet::new(); if let Some(c) = stop.code { stop_codes.insert(("gtfs_stop_code".to_string(), c)); } - let coord: Coord = Coord::from((stop.lon, stop.lat)); - objects::StopPoint { - id: stop.id, - name: stop.name, - codes: stop_codes, - coord: coord, - stop_area_id: stop.parent_station.unwrap(), - timezone: stop.timezone, - visible: true, - stop_type: StopType::Point, - platform_code: stop.platform_code, - level_id: stop.level_id, - ..Default::default() - } - } -} - -impl Into> for Stop { - fn into(self) -> Result { - let mut stop_codes: KeysValues = BTreeSet::new(); - if let Some(c) = self.code { - stop_codes.insert(("gtfs_stop_code".to_string(), c)); - } - if self.name.is_empty() { - warn!("stop_id: {}: for platform name is required", self.id); + if stop.name.is_empty() { + warn!("stop_id: {}: for platform name is required", stop.id); }; - let coord: Coord = Coord::from((self.lon, self.lat)); + let coord = Coord::from((stop.lon, stop.lat)); if coord == Coord::default() { warn!( "stop_id: {}: for platform coordinates are required", - self.id + stop.id ); } let stop_point = objects::StopPoint { - id: self.id, - name: self.name, + id: stop.id, + name: stop.name, codes: stop_codes, - coord: coord, - stop_area_id: self + coord, + stop_area_id: stop .parent_station .unwrap_or_else(|| String::from("default_id")), - timezone: self.timezone, + timezone: stop.timezone, visible: true, stop_type: StopType::Point, - platform_code: self.platform_code, - level_id: self.level_id, + platform_code: stop.platform_code, + level_id: stop.level_id, ..Default::default() }; Ok(stop_point) } } -impl StopLocation { - fn from_gtfs_stop(stop: Stop) -> Result { - let coord: Coord = Coord::from((stop.lon, stop.lat)); +impl TryFrom for objects::StopLocation { + type Error = Error; + fn try_from(stop: Stop) -> Result { + let coord = Coord::from((stop.lon, stop.lat)); if stop.location_type == StopLocationType::StopEntrance { if coord == Coord::default() { - return Err(format_err!( + bail!( "stop_id: {}: for entrances/exits coordinates is required", stop.id - )); + ); } if stop.parent_station.is_none() { - return Err(format_err!( + bail!( "stop_id: {}: for entrances/exits parent_station is required", stop.id - )); + ); } if stop.name.is_empty() { - return Err(format_err!( + bail!( "stop_id: {}: for entrances/exits stop_name is required", stop.id - )); + ); } } - if stop.location_type == StopLocationType::GenericNode { - if stop.parent_station.is_none() { - return Err(format_err!( - "stop_id: {}: for generic node parent_station is required", - stop.id - )); - } + if stop.location_type == StopLocationType::GenericNode && stop.parent_station.is_none() { + bail!( + "stop_id: {}: for generic node parent_station is required", + stop.id + ); } - if stop.location_type == StopLocationType::BoardingArea { - if stop.parent_station.is_none() { - return Err(format_err!( - "stop_id: {}: for boarding area parent_station is required", - stop.id - )); - } + if stop.location_type == StopLocationType::BoardingArea && stop.parent_station.is_none() { + bail!( + "stop_id: {}: for boarding area parent_station is required", + stop.id + ); } - let stop_location = StopLocation { id: stop.id, name: stop.name, comment_links: CommentLinksT::default(), visible: false, - coord: coord, + coord, parent_id: stop.parent_station, timezone: stop.timezone, geometry_id: None, @@ -595,13 +547,13 @@ fn manage_comment_from_stop( stop: &Stop, ) -> CommentLinksT { let mut comment_links: CommentLinksT = CommentLinksT::default(); - if stop.desc.is_some() { + if let Some(desc) = &stop.desc { let comment_id = "stop:".to_string() + &stop.id; let comment = objects::Comment { id: comment_id, comment_type: objects::CommentType::Information, label: None, - name: stop.desc.as_ref().unwrap().to_string(), + name: desc.to_string(), url: None, }; let idx = comments.push(comment).unwrap(); @@ -661,10 +613,19 @@ fn get_equipment_id_and_populate_equipments( } } -fn read_stops(file_handler: &mut H) -> Result> +pub fn read_stops( + file_handler: &mut H, + comments: &mut CollectionWithId, + equipments: &mut EquipmentList, +) -> Result<( + CollectionWithId, + CollectionWithId, + CollectionWithId, +)> where for<'a> &'a mut H: FileHandler, { + info!("Reading stops.txt"); let file = "stops.txt"; let (reader, path) = file_handler.get_file(file)?; @@ -675,23 +636,6 @@ where .deserialize() .collect::>() .with_context(ctx_from_path!(path))?; - Ok(gtfs_stops) -} - -pub fn manage_stops( - file_handler: &mut H, - comments: &mut CollectionWithId, - equipments: &mut EquipmentList, -) -> Result<( - CollectionWithId, - CollectionWithId, - CollectionWithId, -)> -where - for<'a> &'a mut H: FileHandler, -{ - info!("Reading stops.txt"); - let gtfs_stops = read_stops(file_handler)?; let mut stop_areas = vec![]; let mut stop_points = vec![]; @@ -701,27 +645,24 @@ where let equipment_id = get_equipment_id_and_populate_equipments(equipments, &stop); match stop.location_type { StopLocationType::StopPoint => { - let mut stop_point: objects::StopPoint = skip_fail!(stop.clone().into()); + let mut stop_point = skip_fail!(objects::StopPoint::try_from(stop.clone())); if stop.parent_station.is_none() { let stop_area = objects::StopArea::from(stop_point.clone()); stop_point.stop_area_id = stop_area.id.clone(); stop_areas.push(stop_area); - stop_point.clone() - } else { - skip_fail!(stop.into()) }; stop_point.comment_links = comment_links; stop_point.equipment_id = equipment_id; stop_points.push(stop_point); } StopLocationType::StopArea => { - let mut stop_area: objects::StopArea = skip_fail!(stop.into()); + let mut stop_area = skip_fail!(objects::StopArea::try_from(stop)); stop_area.comment_links = comment_links; stop_area.equipment_id = equipment_id; stop_areas.push(stop_area); } _ => { - let mut stop_location = skip_fail!(objects::StopLocation::from_gtfs_stop(stop)); + let mut stop_location = skip_fail!(objects::StopLocation::try_from(stop)); stop_location.comment_links = comment_links; stop_location.equipment_id = equipment_id; stop_locations.push(stop_location); @@ -734,18 +675,14 @@ where Ok((stopareas, stoppoints, stoplocations)) } -pub fn read_pathways(file_handler: &mut H) -> Result> +pub fn read_pathways( + collections: &mut Collections, + file_handler: &mut H, +) -> Result> where for<'a> &'a mut H: FileHandler, { let file = "pathways.txt"; - let gtfs_stops = read_stops(file_handler)?; - let mut stops: HashMap = HashMap::new(); - - for gtfs_stop in gtfs_stops { - stops.insert(gtfs_stop.id.clone(), gtfs_stop); - } - let (reader, _path) = file_handler.get_file_if_exists(file)?; match reader { None => { @@ -759,24 +696,38 @@ where for pathway in rdr.deserialize() { let mut pathway: Pathway = skip_fail!(pathway.map_err(|e| format_err!("{}", e))); - let from_stop_point = - skip_fail!(stops.get(&pathway.from_stop_id).ok_or_else(|| format_err!( - "Problem reading {:?}: from_stop_id={:?} not found", - file, - pathway.from_stop_id - ))); - - let to_stop_point = - skip_fail!(stops.get(&pathway.to_stop_id).ok_or_else(|| format_err!( - "Problem reading {:?}: from_stop_id={:?} not found", - file, - pathway.to_stop_id - ))); - - pathway.from_stop_type = from_stop_point.location_type.clone().into(); - pathway.to_stop_type = to_stop_point.location_type.clone().into(); - - pathways.push(pathway) + pathway.from_stop_type = skip_fail!(collections + .stop_points + .get(&pathway.from_stop_id) + .map(|st| st.stop_type.clone()) + .or(collections + .stop_locations + .get(&pathway.from_stop_id) + .map(|sl| sl.stop_type.clone())) + .ok_or_else(|| { + format_err!( + "Problem reading {:?}: from_stop_id={:?} not found", + file, + pathway.from_stop_id + ) + })); + + pathway.to_stop_type = skip_fail!(collections + .stop_points + .get(&pathway.to_stop_id) + .map(|st| st.stop_type.clone()) + .or(collections + .stop_locations + .get(&pathway.to_stop_id) + .map(|sl| sl.stop_type.clone())) + .ok_or_else(|| { + format_err!( + "Problem reading {:?}: to_stop_id={:?} not found", + file, + pathway.to_stop_id + ) + })); + pathways.push(pathway); } Ok(CollectionWithId::new(pathways)?) } @@ -1246,7 +1197,7 @@ mod tests { gtfs::read::EquipmentList, model::Collections, objects::*, - read_utils::{self, PathFileHandler, read_opt_collection}, + read_utils::{self, read_opt_collection, PathFileHandler}, test_utils::*, AddPrefix, }; @@ -1338,7 +1289,7 @@ mod tests { let mut comments: CollectionWithId = CollectionWithId::default(); let (stop_areas, stop_points, stop_locations) = - super::manage_stops(&mut handler, &mut comments, &mut equipments).unwrap(); + super::read_stops(&mut handler, &mut comments, &mut equipments).unwrap(); assert_eq!(1, stop_areas.len()); assert_eq!(1, stop_points.len()); assert_eq!(0, stop_locations.len()); @@ -1371,7 +1322,7 @@ mod tests { let mut comments: CollectionWithId = CollectionWithId::default(); // let stop_file = File::open(path.join("stops.txt")).unwrap(); let (stop_areas, stop_points, stop_locations) = - super::manage_stops(&mut handler, &mut comments, &mut equipments).unwrap(); + super::read_stops(&mut handler, &mut comments, &mut equipments).unwrap(); collections.stop_areas = stop_areas; collections.stop_points = stop_points; collections.stop_locations = stop_locations; @@ -1406,7 +1357,7 @@ mod tests { let mut equipments = EquipmentList::default(); let mut comments: CollectionWithId = CollectionWithId::default(); let (stop_areas, stop_points, stop_locations) = - super::manage_stops(&mut handler, &mut comments, &mut equipments).unwrap(); + super::read_stops(&mut handler, &mut comments, &mut equipments).unwrap(); //validate stop_point code assert_eq!(1, stop_points.len()); let stop_point = stop_points.iter().next().unwrap().1; @@ -1438,7 +1389,7 @@ mod tests { let mut equipments = EquipmentList::default(); let mut comments: CollectionWithId = CollectionWithId::default(); let (stop_areas, _, _) = - super::manage_stops(&mut handler, &mut comments, &mut equipments).unwrap(); + super::read_stops(&mut handler, &mut comments, &mut equipments).unwrap(); //validate stop_area code assert_eq!(1, stop_areas.len()); let stop_area = stop_areas.iter().next().unwrap().1; @@ -1888,7 +1839,7 @@ mod tests { collections.contributors = CollectionWithId::new(vec![contributor]).unwrap(); collections.datasets = CollectionWithId::new(vec![dataset]).unwrap(); let (stop_areas, stop_points, stop_locations) = - super::manage_stops(&mut handler, &mut comments, &mut equipments).unwrap(); + super::read_stops(&mut handler, &mut comments, &mut equipments).unwrap(); collections.equipments = CollectionWithId::new(equipments.into_equipments()).unwrap(); collections.transfers = super::read_transfers(&mut handler, &stop_points).unwrap(); collections.stop_areas = stop_areas; @@ -2224,7 +2175,7 @@ mod tests { let mut comments: CollectionWithId = CollectionWithId::default(); let mut equipments = EquipmentList::default(); let (stop_areas, stop_points, _) = - super::manage_stops(&mut handler, &mut comments, &mut equipments).unwrap(); + super::read_stops(&mut handler, &mut comments, &mut equipments).unwrap(); let equipments_collection = CollectionWithId::new(equipments.into_equipments()).unwrap(); assert_eq!(2, stop_areas.len()); @@ -2289,7 +2240,7 @@ mod tests { let mut comments: CollectionWithId = CollectionWithId::default(); let mut equipments = EquipmentList::default(); let (_, stop_points, _) = - super::manage_stops(&mut handler, &mut comments, &mut equipments).unwrap(); + super::read_stops(&mut handler, &mut comments, &mut equipments).unwrap(); let equipments_collection = CollectionWithId::new(equipments.into_equipments()).unwrap(); assert_eq!(2, stop_points.len()); @@ -2359,7 +2310,7 @@ mod tests { let mut comments: CollectionWithId = CollectionWithId::default(); let mut equipments = EquipmentList::default(); let (_, stop_points, _) = - super::manage_stops(&mut handler, &mut comments, &mut equipments).unwrap(); + super::read_stops(&mut handler, &mut comments, &mut equipments).unwrap(); collections.stop_points = stop_points; super::read_routes(&mut handler, &mut collections).unwrap(); @@ -2442,7 +2393,7 @@ mod tests { let mut comments: CollectionWithId = CollectionWithId::default(); let mut equipments = EquipmentList::default(); let (_, stop_points, _) = - super::manage_stops(&mut handler, &mut comments, &mut equipments).unwrap(); + super::read_stops(&mut handler, &mut comments, &mut equipments).unwrap(); collections.stop_points = stop_points; super::read_routes(&mut handler, &mut collections).unwrap(); @@ -2509,7 +2460,7 @@ mod tests { let mut comments: CollectionWithId = CollectionWithId::default(); let mut equipments = EquipmentList::default(); let (_, stop_points, _) = - super::manage_stops(&mut handler, &mut comments, &mut equipments).unwrap(); + super::read_stops(&mut handler, &mut comments, &mut equipments).unwrap(); let transfers = super::read_transfers(&mut handler, &stop_points).unwrap(); assert_eq!( @@ -2846,7 +2797,7 @@ mod tests { let mut equipments = EquipmentList::default(); let mut comments: CollectionWithId = CollectionWithId::default(); let (stop_areas, stop_points, _) = - super::manage_stops(&mut handler, &mut comments, &mut equipments).unwrap(); + super::read_stops(&mut handler, &mut comments, &mut equipments).unwrap(); assert_eq!(1, stop_points.len()); assert_eq!(1, stop_areas.len()); let stop_area = stop_areas.iter().next().unwrap().1; @@ -2869,7 +2820,7 @@ mod tests { let mut equipments = EquipmentList::default(); let mut comments: CollectionWithId = CollectionWithId::default(); let (_, stop_points, _) = - super::manage_stops(&mut handler, &mut comments, &mut equipments).unwrap(); + super::read_stops(&mut handler, &mut comments, &mut equipments).unwrap(); assert_eq!(3, stop_points.len()); let longitudes: Vec = stop_points .values() @@ -2932,7 +2883,7 @@ mod tests { let mut comments: CollectionWithId = CollectionWithId::default(); let mut equipments = EquipmentList::default(); let (_, stop_points, _) = - super::manage_stops(&mut handler, &mut comments, &mut equipments).unwrap(); + super::read_stops(&mut handler, &mut comments, &mut equipments).unwrap(); collections.stop_points = stop_points; super::read_routes(&mut handler, &mut collections).unwrap(); @@ -3004,7 +2955,7 @@ mod tests { let mut comments: CollectionWithId = CollectionWithId::default(); let mut equipments = EquipmentList::default(); let (_, stop_points, _) = - super::manage_stops(&mut handler, &mut comments, &mut equipments).unwrap(); + super::read_stops(&mut handler, &mut comments, &mut equipments).unwrap(); collections.stop_points = stop_points; super::read_routes(&mut handler, &mut collections).unwrap(); @@ -3029,25 +2980,20 @@ mod tests { create_file_with_content(path, "stops.txt", stops_content); let mut equipments = EquipmentList::default(); let mut comments: CollectionWithId = CollectionWithId::default(); - let (_, _, mut stop_locations) = - super::manage_stops(&mut handler, &mut comments, &mut equipments).unwrap(); + let (_, _, stop_locations) = + super::read_stops(&mut handler, &mut comments, &mut equipments).unwrap(); let stop_entrance = stop_locations - .clone() - .take() - .into_iter() + .values() .filter(|sl| sl.stop_type == StopType::StopEntrance) .collect::>(); assert_eq!(1, stop_entrance.len()); let stop_node = stop_locations - .clone() - .take() - .into_iter() + .values() .filter(|sl| sl.stop_type == StopType::GenericNode) .collect::>(); assert_eq!(1, stop_node.len()); let stop_boarding = stop_locations - .take() - .into_iter() + .values() .filter(|sl| sl.stop_type == StopType::GenericNode) .collect::>(); assert_eq!(1, stop_boarding.len()); @@ -3066,12 +3012,21 @@ mod tests { 1;stoppoint_id,stoparea_id,8,0\n\ 2,stoppoint_id,stoparea_id,1,3\n\ 3,stoppoint_id,stoparea_id_0,2,0\n\ - 4,stoppoint_id,stoparea_id,1,0"; + 4,stoppoint_id,stoparea_id,1,0 + 5,node_id,boarding_id,1,0"; test_in_tmp_dir(|path| { let mut handler = PathFileHandler::new(path.to_path_buf()); create_file_with_content(path, "stops.txt", stops_content); create_file_with_content(path, "pathways.txt", pathway_content); - let pathways = super::read_pathways(&mut handler).unwrap(); + let mut collections = Collections::default(); + let mut equipments = EquipmentList::default(); + let (_, stop_points, stop_locations) = + super::read_stops(&mut handler, &mut collections.comments, &mut equipments) + .unwrap(); + collections.stop_points = stop_points; + collections.stop_locations = stop_locations; + + let pathways = super::read_pathways(&mut collections, &mut handler).unwrap(); assert_eq!(1, pathways.len()); }) } @@ -3085,15 +3040,16 @@ mod tests { node_id,,node name,0.1,1.2,3,stop_area_id,2\n\ boarding_id,,boarding name,0.1,1.2,4,stoppoint_id,"; let level_content = "level_id,level_index\n\ - 1,0\n\ - 2,2\n\ - 3,1\n\ - 4,4"; + 1,0\n\ + 2,2\n\ + 3,1\n\ + 4,4"; test_in_tmp_dir(|path| { let mut handler = PathFileHandler::new(path.to_path_buf()); create_file_with_content(path, "stops.txt", stops_content); create_file_with_content(path, "levels.txt", level_content); - let levels : CollectionWithId = read_opt_collection(&mut handler, "levels.txt").unwrap(); + let levels: CollectionWithId = + read_opt_collection(&mut handler, "levels.txt").unwrap(); assert_eq!(4, levels.len()); }) } diff --git a/src/gtfs/write.rs b/src/gtfs/write.rs index 54da3483c..de396fa97 100644 --- a/src/gtfs/write.rs +++ b/src/gtfs/write.rs @@ -100,7 +100,7 @@ fn ntfs_stop_point_to_gtfs_stop( .clone() .and_then(|eq_id| equipments.get(&eq_id)) .map(|eq| eq.wheelchair_boarding) - .unwrap_or_else(Availability::default); + .unwrap_or_default(); Stop { id: sp.id.clone(), name: sp.name.clone(), @@ -129,7 +129,7 @@ fn ntfs_stop_area_to_gtfs_stop( .clone() .and_then(|eq_id| equipments.get(&eq_id)) .map(|eq| eq.wheelchair_boarding) - .unwrap_or_else(Availability::default); + .unwrap_or_default(); Stop { id: sa.id.clone(), name: sa.name.clone(), @@ -158,14 +158,14 @@ fn ntfs_stop_location_to_gtfs_stop( .clone() .and_then(|eq_id| equipments.get(&eq_id)) .map(|eq| eq.wheelchair_boarding) - .unwrap_or_else(Availability::default); + .unwrap_or_default(); let (lon, lat) = sl.coord.into(); Stop { id: sl.id.clone(), name: sl.name.clone(), - lat: lat, - lon: lon, + lat, + lon, fare_zone_id: None, location_type: StopLocationType::from(sl.stop_type.clone()), parent_station: sl.parent_id.clone(), diff --git a/src/model.rs b/src/model.rs index 963925783..61a409194 100644 --- a/src/model.rs +++ b/src/model.rs @@ -45,6 +45,7 @@ pub struct Collections { pub physical_modes: CollectionWithId, pub stop_areas: CollectionWithId, pub stop_points: CollectionWithId, + pub stop_locations: CollectionWithId, pub feed_infos: BTreeMap, pub calendars: CollectionWithId, pub companies: CollectionWithId, @@ -70,7 +71,6 @@ pub struct Collections { pub ticket_use_restrictions: Collection, pub pathways: CollectionWithId, pub levels: CollectionWithId, - pub stop_locations: CollectionWithId, } impl Collections { @@ -108,6 +108,8 @@ impl Collections { ticket_prices, ticket_use_perimeters, ticket_use_restrictions, + pathways, + levels, .. } = c; self.contributors.try_merge(contributors)?; @@ -127,6 +129,8 @@ impl Collections { self.ticket_prices.merge(ticket_prices); self.ticket_use_perimeters.merge(ticket_use_perimeters); self.ticket_use_restrictions.merge(ticket_use_restrictions); + self.pathways.merge(pathways); + self.levels.merge(levels); fn get_new_idx( old_idx: Idx, @@ -341,7 +345,7 @@ impl Collections { level_id_used.insert(level_id.clone()); } update_comments_used(&mut comments_used, &sl.comment_links, &self.comments); - return true; + true }) .collect::>(); @@ -350,28 +354,20 @@ impl Collections { .take() .into_iter() .filter(|pw| { - if pw.from_stop_type == StopType::BoardingArea - || pw.from_stop_type == StopType::Point - { - stop_points_used.insert(pw.from_stop_id.clone()); - if let Some(stop_area_id) = self - .stop_points - .get(&pw.from_stop_id) - .map(|sp| sp.stop_area_id.clone()) - { - stop_area_ids_used.insert(stop_area_id); - } - } - if pw.to_stop_type == StopType::BoardingArea || pw.to_stop_type == StopType::Point { - stop_points_used.insert(pw.to_stop_id.clone()); - if let Some(stop_area_id) = self - .stop_points - .get(&pw.to_stop_id) - .map(|sp| sp.stop_area_id.clone()) - { - stop_area_ids_used.insert(stop_area_id); + let mut insert_if_used = |stop_type: &StopType, stop_id: &String| { + if *stop_type == StopType::BoardingArea || *stop_type == StopType::Point { + stop_points_used.insert(stop_id.clone()); + if let Some(stop_area_id) = self + .stop_points + .get(&stop_id) + .map(|sp| sp.stop_area_id.clone()) + { + stop_area_ids_used.insert(stop_area_id); + } } - } + }; + insert_if_used(&pw.from_stop_type, &pw.from_stop_id); + insert_if_used(&pw.to_stop_type, &pw.to_stop_id); true }) .collect::>(); diff --git a/src/ntfs/mod.rs b/src/ntfs/mod.rs index b7ca51ce5..21cf88697 100644 --- a/src/ntfs/mod.rs +++ b/src/ntfs/mod.rs @@ -78,28 +78,26 @@ enum StopLocationType { impl Into for StopLocationType { fn into(self) -> StopType { - let stop_type = match self { + match self { StopLocationType::StopPoint => StopType::Point, StopLocationType::StopArea => StopType::Zone, StopLocationType::GeographicArea => StopType::Zone, StopLocationType::EntranceExit => StopType::StopEntrance, StopLocationType::PathwayInterconnectionNode => StopType::GenericNode, StopLocationType::BoardingArea => StopType::BoardingArea, - }; - stop_type + } } } impl From for StopLocationType { fn from(stop_type: StopType) -> StopLocationType { - let stop_location_type = match stop_type { + match stop_type { StopType::Point => StopLocationType::StopPoint, StopType::Zone => StopLocationType::StopArea, StopType::StopEntrance => StopLocationType::EntranceExit, StopType::GenericNode => StopLocationType::PathwayInterconnectionNode, StopType::BoardingArea => StopLocationType::BoardingArea, - }; - stop_location_type + } } } @@ -201,12 +199,12 @@ pub fn read>(path: P) -> Result { collections.ticket_prices = make_opt_collection(path, "ticket_prices.txt")?; collections.ticket_use_perimeters = make_opt_collection(path, "ticket_use_perimeters.txt")?; collections.ticket_use_restrictions = make_opt_collection(path, "ticket_use_restrictions.txt")?; - collections.pathways = read::read_pathways(path)?; collections.levels = make_opt_collection_with_id(path, "levels.txt")?; manage_calendars(&mut file_handle, &mut collections)?; read::manage_geometries(&mut collections, path)?; read::manage_feed_infos(&mut collections, path)?; read::manage_stops(&mut collections, path)?; + collections.pathways = read::read_pathways(&mut collections, path)?; read::manage_stop_times(&mut collections, path)?; read::manage_codes(&mut collections, path)?; read::manage_comments(&mut collections, path)?; diff --git a/src/ntfs/read.rs b/src/ntfs/read.rs index 74e653676..a72650a66 100644 --- a/src/ntfs/read.rs +++ b/src/ntfs/read.rs @@ -27,79 +27,62 @@ use failure::{bail, ensure, format_err, ResultExt}; use log::{error, info, warn}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use std::convert::TryFrom; use transit_model_collection::*; -impl From for StopArea { - fn from(stop: Stop) -> StopArea { +impl TryFrom for StopArea { + type Error = Error; + fn try_from(stop: Stop) -> Result { if stop.name.is_empty() { - warn!("stop_id: {}: for station stop_name is required", stop.id); + warn!("stop_id: {}: for platform stop_name is required", stop.id); } + let coord = Coord::from((stop.lon, stop.lat)); if coord == Coord::default() { - warn!("stop_id: {}: for station coordinates are required", stop.id); + warn!( + "stop_id: {}: for platform coordinates are required", + stop.id + ); } - StopArea { + let stop_area = StopArea { id: stop.id, name: stop.name, codes: KeysValues::default(), object_properties: KeysValues::default(), comment_links: CommentLinksT::default(), visible: stop.visible, - coord: coord, + coord, timezone: stop.timezone, geometry_id: stop.geometry_id, equipment_id: stop.equipment_id, level_id: stop.level_id, - } - } -} - -impl Into> for Stop { - fn into(self) -> Result { - if self.name.is_empty() { - warn!("stop_id: {}: for platform stop_name is required", self.id); - } - - let coord = Coord::from((self.lon, self.lat)); - if coord == Coord::default() { - warn!( - "stop_id: {}: for platform coordinates are required", - self.id - ); - } - let stop_area = StopArea { - id: self.id, - name: self.name, - codes: KeysValues::default(), - object_properties: KeysValues::default(), - comment_links: CommentLinksT::default(), - visible: self.visible, - coord: coord, - timezone: self.timezone, - geometry_id: self.geometry_id, - equipment_id: self.equipment_id, - level_id: self.level_id, }; Ok(stop_area) } } -impl From for StopPoint { - fn from(stop: Stop) -> StopPoint { - let id = stop.id; +impl TryFrom for StopPoint { + type Error = Error; + fn try_from(stop: Stop) -> Result { if stop.name.is_empty() { - warn!("stop_id: {}: for plateform stop_name is required", id); - } + warn!("stop_id: {}: for platform name is required", stop.id); + }; + let coord = Coord::from((stop.lon, stop.lat)); if coord == Coord::default() { - warn!("stop_id: {}: for plateform coordinates are required", id); + warn!( + "stop_id: {}: for platform coordinates are required", + stop.id + ); } - StopPoint { - id, + let stop_point = StopPoint { + id: stop.id, name: stop.name, visible: stop.visible, - coord: coord, - stop_area_id: stop.parent_station.unwrap(), + coord, + stop_area_id: stop + .parent_station + .unwrap_or_else(|| String::from("default_id")), timezone: stop.timezone, geometry_id: stop.geometry_id, equipment_id: stop.equipment_id, @@ -109,91 +92,56 @@ impl From for StopPoint { platform_code: stop.platform_code, level_id: stop.level_id, ..Default::default() - } - } -} - -impl Into> for Stop { - fn into(self) -> Result { - if self.name.is_empty() { - warn!("stop_id: {}: for platform name is required", self.id); - }; - - let coord: Coord = Coord::from((self.lon, self.lat)); - if coord == Coord::default() { - warn!( - "stop_id: {}: for platform coordinates are required", - self.id - ); - } - let stop_point = StopPoint { - id: self.id, - name: self.name, - visible: self.visible, - coord: coord, - stop_area_id: self - .parent_station - .unwrap_or_else(|| String::from("default_id")), - timezone: self.timezone, - geometry_id: self.geometry_id, - equipment_id: self.equipment_id, - fare_zone_id: self.fare_zone_id, - zone_id: self.zone_id, - stop_type: self.location_type.into(), - platform_code: self.platform_code, - level_id: self.level_id, - ..Default::default() }; Ok(stop_point) } } -impl StopLocation { - fn from_ntfs_stop(stop: Stop) -> Result { - let coord: Coord = Coord::from((stop.lon, stop.lat)); +impl TryFrom for StopLocation { + type Error = Error; + fn try_from(stop: Stop) -> Result { + let coord = Coord::from((stop.lon, stop.lat)); if stop.location_type == StopLocationType::EntranceExit { if coord == Coord::default() { - return Err(format_err!( + bail!( "stop_id: {}: for entrances/exits coordinates is required", stop.id - )); + ); } if stop.parent_station.is_none() { - return Err(format_err!( + bail!( "stop_id: {}: for entrances/exits parent_station is required", stop.id - )); + ); } if stop.name.is_empty() { - return Err(format_err!( + bail!( "stop_id: {}: for entrances/exits stop_name is required", stop.id - )); + ); } } - if stop.location_type == StopLocationType::PathwayInterconnectionNode { - if stop.parent_station.is_none() { - return Err(format_err!( - "stop_id: {}: for generic node parent_station is required", - stop.id - )); - } + if stop.location_type == StopLocationType::PathwayInterconnectionNode + && stop.parent_station.is_none() + { + bail!( + "stop_id: {}: for generic node parent_station is required", + stop.id + ); } - if stop.location_type == StopLocationType::BoardingArea { - if stop.parent_station.is_none() { - return Err(format_err!( - "stop_id: {}: for boarding area parent_station is required", - stop.id - )); - } + if stop.location_type == StopLocationType::BoardingArea && stop.parent_station.is_none() { + bail!( + "stop_id: {}: for boarding area parent_station is required", + stop.id + ); } let stop_location = StopLocation { id: stop.id, name: stop.name, comment_links: CommentLinksT::default(), visible: false, - coord: coord, + coord, parent_id: stop.parent_station, timezone: stop.timezone, geometry_id: stop.geometry_id, @@ -205,41 +153,30 @@ impl StopLocation { } } -fn read_stops(path: &path::Path) -> Result> { - let path = path.join("stops.txt"); - let mut rdr = csv::Reader::from_path(&path).with_context(ctx_from_path!(path))?; - let stops: Vec = rdr - .deserialize() - .collect::, _>>() - .with_context(ctx_from_path!(path))?; - Ok(stops) -} - pub fn manage_stops(collections: &mut Collections, path: &path::Path) -> Result<()> { info!("Reading stops.txt"); - let ntfs_stops = read_stops(&path)?; + let path = path.join("stops.txt"); + let mut rdr = csv::Reader::from_path(&path).with_context(ctx_from_path!(path))?; let mut stop_areas = vec![]; let mut stop_points = vec![]; let mut stop_locations = vec![]; - for stop in ntfs_stops { + for stop in rdr.deserialize() { + let stop: Stop = stop.with_context(ctx_from_path!(path))?; match stop.location_type { StopLocationType::StopPoint | StopLocationType::GeographicArea => { - let mut stop_point: StopPoint = skip_fail!(stop.clone().into()); + let mut stop_point = skip_fail!(StopPoint::try_from(stop.clone())); if stop.parent_station.is_none() { let mut stop_area = StopArea::from(stop_point.clone()); stop_point.stop_area_id = stop_area.id.clone(); - stop_area.visible = stop.location_type.clone() == StopLocationType::StopPoint; + stop_area.visible = stop.location_type == StopLocationType::StopPoint; stop_areas.push(stop_area); - stop_point.clone() - } else { - skip_fail!(stop.into()) }; stop_points.push(stop_point); } - StopLocationType::StopArea => stop_areas.push(StopArea::from(stop)), + StopLocationType::StopArea => stop_areas.push(skip_fail!(StopArea::try_from(stop))), _ => { - stop_locations.push(skip_fail!(StopLocation::from_ntfs_stop(stop))); + stop_locations.push(skip_fail!(StopLocation::try_from(stop))); } } } @@ -681,7 +618,10 @@ pub fn manage_companies_on_vj(collections: &mut Collections) -> Result<()> { Ok(()) } -pub fn read_pathways(path: &path::Path) -> Result> { +pub fn read_pathways( + collections: &mut Collections, + path: &path::Path, +) -> Result> { let file = "pathways.txt"; let pathway_path = path.join(file); if !pathway_path.exists() { @@ -690,36 +630,45 @@ pub fn read_pathways(path: &path::Path) -> Result> { } info!("Reading {}", file); - let ntfs_stops = read_stops(&path)?; - let mut stops: HashMap = HashMap::new(); - - for ntfs_stop in ntfs_stops { - stops.insert(ntfs_stop.id.clone(), ntfs_stop); - } - let mut pathways = vec![]; let mut rdr = csv::Reader::from_path(&pathway_path).with_context(ctx_from_path!(pathway_path))?; for pathway in rdr.deserialize() { - let mut pathway: Pathway = skip_fail!(pathway); - let from_stop_point = - skip_fail!(stops.get(&pathway.from_stop_id).ok_or_else(|| format_err!( - "Problem reading {:?}: from_stop_id={:?} not found", - file, - pathway.from_stop_id - ))); - - let to_stop_point = skip_fail!(stops.get(&pathway.to_stop_id).ok_or_else(|| format_err!( - "Problem reading {:?}: from_stop_id={:?} not found", - file, - pathway.to_stop_id - ))); - - pathway.from_stop_type = from_stop_point.location_type.clone().into(); - pathway.to_stop_type = to_stop_point.location_type.clone().into(); - - pathways.push(pathway) + let mut pathway: Pathway = skip_fail!(pathway.map_err(|e| format_err!("{}", e))); + + pathway.from_stop_type = skip_fail!(collections + .stop_points + .get(&pathway.from_stop_id) + .map(|st| st.stop_type.clone()) + .or(collections + .stop_locations + .get(&pathway.from_stop_id) + .map(|sl| sl.stop_type.clone())) + .ok_or_else(|| { + format_err!( + "Problem reading {:?}: from_stop_id={:?} not found", + file, + pathway.from_stop_id + ) + })); + + pathway.to_stop_type = skip_fail!(collections + .stop_points + .get(&pathway.to_stop_id) + .map(|st| st.stop_type.clone()) + .or(collections + .stop_locations + .get(&pathway.to_stop_id) + .map(|sl| sl.stop_type.clone())) + .ok_or_else(|| { + format_err!( + "Problem reading {:?}: to_stop_id={:?} not found", + file, + pathway.to_stop_id + ) + })); + pathways.push(pathway); } Ok(CollectionWithId::new(pathways)?) diff --git a/src/ntfs/write.rs b/src/ntfs/write.rs index 0d31e8238..65b4b39b8 100644 --- a/src/ntfs/write.rs +++ b/src/ntfs/write.rs @@ -433,12 +433,11 @@ pub fn write_stops( let path = path.join(file); let mut wtr = csv::Writer::from_path(&path).with_context(ctx_from_path!(path))?; for st in stop_points.values() { - let location_type: StopLocationType; - if st.stop_type == StopType::Zone { - location_type = StopLocationType::GeographicArea; + let location_type = if st.stop_type == StopType::Zone { + StopLocationType::GeographicArea } else { - location_type = StopLocationType::from(st.stop_type.clone()); - } + StopLocationType::from(st.stop_type.clone()) + }; wtr.serialize(Stop { id: st.id.clone(), visible: st.visible, @@ -447,7 +446,7 @@ pub fn write_stops( lon: st.coord.lon.to_string(), fare_zone_id: st.fare_zone_id.clone(), zone_id: st.zone_id.clone(), - location_type: location_type, + location_type, parent_station: stop_areas.get(&st.stop_area_id).map(|sa| sa.id.clone()), timezone: st.timezone.clone(), equipment_id: st.equipment_id.clone(), @@ -484,8 +483,8 @@ pub fn write_stops( id: sl.id.clone(), visible: sl.visible, name: sl.name.clone(), - lat: lat, - lon: lon, + lat, + lon, fare_zone_id: None, zone_id: None, location_type: StopLocationType::from(sl.stop_type.clone()), diff --git a/src/objects.rs b/src/objects.rs index 05eaea6b1..42cfca236 100644 --- a/src/objects.rs +++ b/src/objects.rs @@ -878,12 +878,12 @@ impl From<(String, String)> for Coord { impl Into<(String, String)> for Coord { fn into(self) -> (String, String) { ( - if self.lon == ::default() { + if (self.lon - ::default()).abs() < std::f64::EPSILON { "".to_string() } else { self.lon.to_string() }, - if self.lat == ::default() { + if (self.lat - ::default()).abs() < std::f64::EPSILON { "".to_string() } else { self.lat.to_string() diff --git a/tests/fixtures/gtfs2ntfs/no_traffic/input/levels.txt b/tests/fixtures/gtfs2ntfs/no_traffic/input/levels.txt new file mode 100644 index 000000000..36fa5db55 --- /dev/null +++ b/tests/fixtures/gtfs2ntfs/no_traffic/input/levels.txt @@ -0,0 +1,5 @@ +level_id,level_index,level_name +level1,-1,level 1 +level2,0,level 2 +level3,1,level 3 +level4,2,level 4 diff --git a/tests/fixtures/gtfs2ntfs/no_traffic/output/levels.txt b/tests/fixtures/gtfs2ntfs/no_traffic/output/levels.txt new file mode 100644 index 000000000..d6549d21f --- /dev/null +++ b/tests/fixtures/gtfs2ntfs/no_traffic/output/levels.txt @@ -0,0 +1,4 @@ +level_id,level_index,level_name +level1,-1.0,level 1 +level2,0.0,level 2 +level4,2.0,level 4 diff --git a/tests/fixtures/merge-ntfs/input/levels.txt b/tests/fixtures/merge-ntfs/input/levels.txt new file mode 100644 index 000000000..0aa19e69e --- /dev/null +++ b/tests/fixtures/merge-ntfs/input/levels.txt @@ -0,0 +1,7 @@ +level_id,level_index,level_name +OIF:1,1, +OIF:2,0, +OIF:3,-1, +OIF:4,-2, +OIF:5,2, + diff --git a/tests/fixtures/merge-ntfs/input/pathways.txt b/tests/fixtures/merge-ntfs/input/pathways.txt new file mode 100644 index 000000000..09d893b53 --- /dev/null +++ b/tests/fixtures/merge-ntfs/input/pathways.txt @@ -0,0 +1,10 @@ +pathway_id,from_stop_id,to_stop_id,pathway_mode,is_bidirectional +OIF:1,OIF:SP:10:10,OIF:SP:10:100,1,0 +OIF:2,OIF:SP:10:100,OIF:SP:10:200,2,1 +OIF:3,OIF:SP:10:200,OIF:SP:10:300,3,0 +OIF:4,OIF:SP:10:10,OIF:SP:10:100,1,3 +OIF:5,OIF:SP:10:200,OIF:SP:10:300,8,0 +OIF:6,OIF:SP:10:300,OIF:SP:10:400,4,1 +OIF:7,OIF:SP:10:400,OIF:SP:10:300,5,1 +OIF:8,OIF:SP:10:400,OIF:SP:10:400,6,1 + diff --git a/tests/fixtures/merge-ntfs/input/stops.txt b/tests/fixtures/merge-ntfs/input/stops.txt index 917c9d7e9..57a9f4693 100644 --- a/tests/fixtures/merge-ntfs/input/stops.txt +++ b/tests/fixtures/merge-ntfs/input/stops.txt @@ -1,6 +1,6 @@ -stop_id,visible,stop_name,stop_lat,stop_lon,zone_id,location_type,parent_station,stop_timezone,equipment_id,contributor_id,geometry_id -OIF:SP:10:10,1,"Avenue de l'Essonne",48.844747,2.372988,,0,OIF:SA:10:1002,Europe/Paris,,OIF, -OIF:SP:10:100,1,"Clinique",48.637689,2.426617,,0,OIF:SA:10:1002,Europe/Paris,,OIF, -OIF:SP:10:200,1,"Clinique 2",48.873966,2.295355,,0,OIF:SA:10:1002,Europe/Paris,,OIF, -OIF:SP:10:300,1,"Clinique paumée",48.873966,2.295355,,0,OIF:SA:10:1002,Europe/Paris,,OIF, -OIF:SA:10:1002,1,"Maison de l'Enfance",48.844745,2.372986,,1,,Europe/Paris,,OIF, \ No newline at end of file +stop_id,visible,stop_name,stop_lat,stop_lon,zone_id,location_type,parent_station,stop_timezone,equipment_id,contributor_id,geometry_id,level_id +OIF:SP:10:10,1,Avenue de l'Essonne,48.844747,2.372988,,0,OIF:SA:10:1002,Europe/Paris,,OIF,,OIF:1 +OIF:SP:10:100,1,Clinique,48.637689,2.426617,,0,OIF:SA:10:1002,Europe/Paris,,OIF,,OIF:2 +OIF:SP:10:200,1,Clinique 2,48.873966,2.295355,,0,OIF:SA:10:1002,Europe/Paris,,OIF,,OIF:3 +OIF:SP:10:300,1,Clinique paumée,48.873966,2.295355,,0,OIF:SA:10:1002,Europe/Paris,,OIF,,OIF:4 +OIF:SA:10:1002,1,Maison de l'Enfance,48.844745,2.372986,,1,,Europe/Paris,,OIF,,OIF:2 diff --git a/tests/gtfs2ntfs.rs b/tests/gtfs2ntfs.rs index 984b93efb..84e874869 100644 --- a/tests/gtfs2ntfs.rs +++ b/tests/gtfs2ntfs.rs @@ -100,6 +100,7 @@ fn test_gtfs_remove_vjs_with_no_traffic() { "stops.txt", "routes.txt", "stop_times.txt", + "levels.txt", ]), "./tests/fixtures/gtfs2ntfs/no_traffic/output", ); @@ -148,7 +149,7 @@ fn test_gtfs_with_levels() { transit_model::ntfs::write(&model, path, get_test_datetime()).unwrap(); compare_output_dir_with_expected( &path, - Some(vec!["stops.txt", "pathways.txt", "levels.txt",],), + Some(vec!["stops.txt", "pathways.txt", "levels.txt"]), "./tests/fixtures/gtfs2ntfs/levels_and_pathways/output", ); }); diff --git a/tests/merge_ntfs.rs b/tests/merge_ntfs.rs index 4315d0470..1b0f5400a 100644 --- a/tests/merge_ntfs.rs +++ b/tests/merge_ntfs.rs @@ -69,6 +69,8 @@ fn merge_collections_ok() { assert_eq!(2, collections.frequencies.len()); assert_eq!(1, collections.stop_time_headsigns.len()); assert_eq!(5, collections.stop_time_ids.len()); + assert_eq!(5, collections.levels.len()); + assert_eq!(3, collections.pathways.len()); let mut headsigns = HashMap::<(Idx, u32), String>::new(); headsigns.insert(