use amtrak_api::{Client, TrainStatus};
use chrono::{FixedOffset, NaiveDate};
use mockito::Server;
#[tokio::test]
async fn test_single_train() -> Result<(), amtrak_api::Error> {
let mut server = Server::new_async().await;
let mock_server = server
.mock("GET", "/trains")
.with_body(
r#"
{
"657": [
{
"routeName": "Keystone",
"trainNum": "657",
"trainID": "657-30",
"lat": 40.14815944794739,
"lon": -76.61796031144218,
"trainTimely": "NaN Minutes Early",
"stations": [
{
"name": "New York Penn",
"code": "NYP",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T20:30:00-04:00",
"schDep": "2023-08-29T20:30:00-04:00",
"arr": "2023-08-29T20:30:00-04:00",
"dep": "2023-08-29T20:30:00-04:00",
"arrCmnt": "0 Minutes Early",
"depCmnt": "0 Minutes Early",
"status": "Departed"
},
{
"name": "Newark Penn",
"code": "NWK",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T20:45:00-04:00",
"schDep": "2023-08-29T20:47:00-04:00",
"arr": "2023-08-29T20:42:00-04:00",
"dep": "2023-08-29T20:47:00-04:00",
"arrCmnt": "3 Minutes Early",
"depCmnt": "0 Minutes Early",
"status": "Departed"
},
{
"name": "Trenton",
"code": "TRE",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T21:23:00-04:00",
"schDep": "2023-08-29T21:24:00-04:00",
"arr": "2023-08-29T21:17:00-04:00",
"dep": "2023-08-29T21:24:00-04:00",
"arrCmnt": "6 Minutes Early",
"depCmnt": "0 Minutes Early",
"status": "Departed"
},
{
"name": "Cornwells Heights",
"code": "CWH",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T21:35:00-04:00",
"schDep": "2023-08-29T21:36:00-04:00",
"arr": "2023-08-29T21:35:00-04:00",
"dep": "2023-08-29T21:36:00-04:00",
"arrCmnt": "0 Minutes Early",
"depCmnt": "0 Minutes Early",
"status": "Departed"
},
{
"name": "Philadelphia North",
"code": "PHN",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T21:47:00-04:00",
"schDep": "2023-08-29T21:47:00-04:00",
"arr": "2023-08-29T21:47:00-04:00",
"dep": "2023-08-29T21:48:00-04:00",
"arrCmnt": "0 Minutes Early",
"depCmnt": "On Time",
"status": "Departed"
},
{
"name": "Philadelphia 30th Street",
"code": "PHL",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T21:55:00-04:00",
"schDep": "2023-08-29T22:05:00-04:00",
"arr": "2023-08-29T21:56:00-04:00",
"dep": "2023-08-29T22:05:00-04:00",
"arrCmnt": "On Time",
"depCmnt": "0 Minutes Early",
"status": "Departed"
},
{
"name": "Ardmore",
"code": "ARD",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T22:17:00-04:00",
"schDep": "2023-08-29T22:18:00-04:00",
"arr": "2023-08-29T22:18:00-04:00",
"dep": "2023-08-29T22:18:00-04:00",
"arrCmnt": "On Time",
"depCmnt": "0 Minutes Early",
"status": "Departed"
},
{
"name": "Paoli",
"code": "PAO",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T22:29:00-04:00",
"schDep": "2023-08-29T22:30:00-04:00",
"arr": "2023-08-29T22:31:00-04:00",
"dep": "2023-08-29T22:32:00-04:00",
"arrCmnt": "On Time",
"depCmnt": "On Time",
"status": "Departed"
},
{
"name": "Exton",
"code": "EXT",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T22:37:00-04:00",
"schDep": "2023-08-29T22:38:00-04:00",
"arr": "2023-08-29T22:39:00-04:00",
"dep": "2023-08-29T22:40:00-04:00",
"arrCmnt": "On Time",
"depCmnt": "On Time",
"status": "Departed"
},
{
"name": "Downingtown",
"code": "DOW",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T22:42:00-04:00",
"schDep": "2023-08-29T22:42:00-04:00",
"arr": "2023-08-29T22:46:00-04:00",
"dep": "2023-08-29T22:47:00-04:00",
"arrCmnt": "On Time",
"depCmnt": "5 Minutes Late",
"status": "Departed"
},
{
"name": "Coatesville",
"code": "COT",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T22:49:00-04:00",
"schDep": "2023-08-29T22:49:00-04:00",
"arr": "2023-08-29T22:52:00-04:00",
"dep": "2023-08-29T22:52:00-04:00",
"arrCmnt": "On Time",
"depCmnt": "On Time",
"status": "Departed"
},
{
"name": "Parkesburg",
"code": "PAR",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T22:55:00-04:00",
"schDep": "2023-08-29T22:55:00-04:00",
"arr": "2023-08-29T22:57:00-04:00",
"dep": "2023-08-29T22:58:00-04:00",
"arrCmnt": "On Time",
"depCmnt": "On Time",
"status": "Departed"
},
{
"name": "Lancaster",
"code": "LNC",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T23:17:00-04:00",
"schDep": "2023-08-29T23:18:00-04:00",
"arr": "2023-08-29T23:16:00-04:00",
"dep": "2023-08-29T23:18:00-04:00",
"arrCmnt": "1 Minutes Early",
"depCmnt": "0 Minutes Early",
"status": "Departed"
},
{
"name": "Mount Joy",
"code": "MJY",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T23:28:00-04:00",
"schDep": "2023-08-29T23:28:00-04:00",
"arr": "2023-08-29T23:26:00-04:00",
"dep": "2023-08-29T23:28:00-04:00",
"arrCmnt": "2 Minutes Early",
"depCmnt": "0 Minutes Early",
"status": "Departed"
},
{
"name": "Elizabethtown",
"code": "ELT",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T23:35:00-04:00",
"schDep": "2023-08-29T23:35:00-04:00",
"arr": "2023-08-29T23:33:00-04:00",
"dep": "2023-08-29T23:35:00-04:00",
"arrCmnt": "2 Minutes Early",
"depCmnt": "0 Minutes Early",
"status": "Departed"
},
{
"name": "Middletown",
"code": "MID",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T23:42:00-04:00",
"schDep": "2023-08-29T23:42:00-04:00",
"arr": "2023-08-29T23:42:00-04:00",
"dep": "2023-08-29T23:42:00-04:00",
"arrCmnt": "NaN Minutes Early",
"depCmnt": "NaN Minutes Early",
"status": "Enroute"
},
{
"name": "Harrisburg",
"code": "HAR",
"tz": "America/New_York",
"bus": false,
"schArr": "2023-08-29T23:56:00-04:00",
"schDep": "2023-08-29T23:56:00-04:00",
"arr": null,
"arrCmnt": "NaN Minutes Early",
"depCmnt": "NaN Minutes Early",
"status": "Station"
}
],
"heading": "W",
"eventCode": "MID",
"eventTZ": "America/New_York",
"eventName": "Middletown",
"origCode": "NYP",
"originTZ": "America/New_York",
"origName": "New York Penn",
"destCode": "HAR",
"destTZ": "America/New_York",
"destName": "Harrisburg",
"trainState": "Active",
"velocity": 51.2444686889648,
"statusMsg": " ",
"createdAt": "2023-08-29T23:39:50-04:00",
"updatedAt": "2023-08-29T23:39:50-04:00",
"lastValTS": "2023-08-29T23:39:34-04:00",
"objectID": 847
}
]
}"#,
)
.create_async()
.await;
let client = Client::with_base_url(server.url().as_str());
let response = client.trains().await?;
let trains = response.get("657").unwrap();
assert_eq!(trains.len(), 1);
let train = trains.get(0).unwrap();
assert_eq!(train.route_name, "Keystone");
assert_eq!(train.train_num, "657");
assert_eq!(train.lat, 40.14815944794739);
assert_eq!(train.lon, -76.61796031144218);
assert_eq!(train.train_timely, "NaN Minutes Early");
assert_eq!(train.stations.len(), 17);
assert_eq!(train.stations[0].name, "New York Penn");
assert_eq!(train.stations[0].code, "NYP");
assert_eq!(train.stations[0].tz, "America/New_York");
assert!(!train.stations[0].bus);
assert_eq!(train.stations[0].schedule_arrival, {
let tz = FixedOffset::east_opt(-4 * 3600).unwrap();
NaiveDate::from_ymd_opt(2023, 8, 29)
.unwrap()
.and_hms_opt(20, 30, 0)
.unwrap()
.and_local_timezone(tz)
.unwrap()
});
assert_eq!(train.stations[0].schedule_departure, {
let tz = FixedOffset::east_opt(-4 * 3600).unwrap();
NaiveDate::from_ymd_opt(2023, 8, 29)
.unwrap()
.and_hms_opt(20, 30, 0)
.unwrap()
.and_local_timezone(tz)
.unwrap()
});
assert_eq!(train.stations[0].arrival.unwrap(), {
let tz = FixedOffset::east_opt(-4 * 3600).unwrap();
NaiveDate::from_ymd_opt(2023, 8, 29)
.unwrap()
.and_hms_opt(20, 30, 0)
.unwrap()
.and_local_timezone(tz)
.unwrap()
});
assert_eq!(train.stations[0].departure.unwrap(), {
let tz = FixedOffset::east_opt(-4 * 3600).unwrap();
NaiveDate::from_ymd_opt(2023, 8, 29)
.unwrap()
.and_hms_opt(20, 30, 0)
.unwrap()
.and_local_timezone(tz)
.unwrap()
});
assert_eq!(train.stations[0].arrival_comment, "0 Minutes Early");
assert_eq!(train.stations[0].departure_comment, "0 Minutes Early");
assert_eq!(train.stations[0].status, TrainStatus::Departed);
mock_server.assert_async().await;
Ok(())
}
#[tokio::test]
async fn test_empty_trains() -> Result<(), amtrak_api::Error> {
let mut server = Server::new_async().await;
let mock_server = server
.mock("GET", "/trains")
.with_body("[]")
.create_async()
.await;
let client = Client::with_base_url(server.url().as_str());
let response = client.trains().await?;
assert_eq!(response.len(), 0);
mock_server.assert_async().await;
Ok(())
}