minotor 1.0.7 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/README.md +3 -2
  3. package/dist/cli.mjs +604 -531
  4. package/dist/cli.mjs.map +1 -1
  5. package/dist/gtfs/stops.d.ts +19 -5
  6. package/dist/gtfs/transfers.d.ts +5 -4
  7. package/dist/gtfs/trips.d.ts +7 -5
  8. package/dist/gtfs/utils.d.ts +7 -8
  9. package/dist/parser.cjs.js +569 -501
  10. package/dist/parser.cjs.js.map +1 -1
  11. package/dist/parser.esm.js +569 -501
  12. package/dist/parser.esm.js.map +1 -1
  13. package/dist/router.cjs.js +1 -1
  14. package/dist/router.cjs.js.map +1 -1
  15. package/dist/router.d.ts +3 -3
  16. package/dist/router.esm.js +1 -1
  17. package/dist/router.esm.js.map +1 -1
  18. package/dist/router.umd.js +1 -1
  19. package/dist/router.umd.js.map +1 -1
  20. package/dist/routing/__tests__/route.test.d.ts +1 -0
  21. package/dist/routing/query.d.ts +7 -7
  22. package/dist/routing/result.d.ts +3 -3
  23. package/dist/routing/route.d.ts +1 -0
  24. package/dist/stops/proto/stops.d.ts +5 -4
  25. package/dist/stops/stops.d.ts +10 -1
  26. package/dist/stops/stopsIndex.d.ts +21 -4
  27. package/dist/timetable/proto/timetable.d.ts +21 -18
  28. package/dist/timetable/timetable.d.ts +38 -14
  29. package/package.json +4 -3
  30. package/src/cli/repl.ts +13 -10
  31. package/src/gtfs/__tests__/parser.test.ts +50 -579
  32. package/src/gtfs/__tests__/stops.test.ts +181 -112
  33. package/src/gtfs/__tests__/transfers.test.ts +170 -12
  34. package/src/gtfs/__tests__/trips.test.ts +212 -141
  35. package/src/gtfs/__tests__/utils.test.ts +4 -4
  36. package/src/gtfs/parser.ts +22 -13
  37. package/src/gtfs/stops.ts +63 -28
  38. package/src/gtfs/transfers.ts +14 -6
  39. package/src/gtfs/trips.ts +110 -47
  40. package/src/gtfs/utils.ts +11 -11
  41. package/src/router.ts +2 -3
  42. package/src/routing/__tests__/route.test.ts +112 -0
  43. package/src/routing/__tests__/router.test.ts +234 -244
  44. package/src/routing/query.ts +7 -7
  45. package/src/routing/result.ts +9 -6
  46. package/src/routing/route.ts +11 -0
  47. package/src/routing/router.ts +26 -24
  48. package/src/stops/__tests__/io.test.ts +9 -8
  49. package/src/stops/__tests__/stopFinder.test.ts +45 -36
  50. package/src/stops/io.ts +8 -5
  51. package/src/stops/proto/stops.proto +8 -7
  52. package/src/stops/proto/stops.ts +68 -38
  53. package/src/stops/stops.ts +13 -1
  54. package/src/stops/stopsIndex.ts +50 -7
  55. package/src/timetable/__tests__/io.test.ts +40 -49
  56. package/src/timetable/__tests__/timetable.test.ts +50 -58
  57. package/src/timetable/io.ts +69 -56
  58. package/src/timetable/proto/timetable.proto +22 -17
  59. package/src/timetable/proto/timetable.ts +94 -184
  60. package/src/timetable/timetable.ts +62 -29
@@ -1,591 +1,62 @@
1
- import * as assert from 'node:assert/strict';
1
+ import assert from 'node:assert';
2
2
  import { beforeEach, describe, it } from 'node:test';
3
3
 
4
- import { StopsMap } from '../../stops/stops.js';
5
- import { StopsIndex } from '../../stops/stopsIndex.js';
6
4
  import { Time } from '../../timetable/time.js';
7
- import {
8
- RoutesAdjacency,
9
- ServiceRoutesMap,
10
- StopsAdjacency,
11
- Timetable,
12
- } from '../../timetable/timetable.js';
13
5
  import { GtfsParser } from '../parser.js';
14
-
15
- describe('parse gtfs', () => {
16
- let gtfsParser: GtfsParser;
6
+ describe('GTFS parser', () => {
7
+ let parser: GtfsParser;
17
8
 
18
9
  beforeEach(() => {
19
10
  const gtfsPath = './src/gtfs/__tests__/resources/sample-feed.zip';
20
- gtfsParser = new GtfsParser(gtfsPath);
21
- });
22
-
23
- describe('given a gtfs feed', () => {
24
- const date = new Date('2007-01-10T12:00:00+00:00');
25
- it('should parse the timetable', async () => {
26
- const expectedRoutesAdjacency: RoutesAdjacency = new Map([
27
- [
28
- 'STBA_1kdg12n',
29
- {
30
- serviceRouteId: 'STBA',
31
- stops: ['STAGECOACH', 'BEATTY_AIRPORT'],
32
- stopTimes: [
33
- {
34
- departure: Time.fromHMS(6, 0, 0),
35
- arrival: Time.fromHMS(6, 0, 0),
36
- pickUpType: 'REGULAR',
37
- dropOffType: 'REGULAR',
38
- },
39
- {
40
- departure: Time.fromHMS(6, 20, 0),
41
- arrival: Time.fromHMS(6, 20, 0),
42
- pickUpType: 'REGULAR',
43
- dropOffType: 'REGULAR',
44
- },
45
- ],
46
- stopIndices: new Map([
47
- ['STAGECOACH', 0],
48
- ['BEATTY_AIRPORT', 1],
49
- ]),
50
- },
51
- ],
52
- [
53
- 'CITY_asdcjh',
54
- {
55
- serviceRouteId: 'CITY',
56
- stops: ['STAGECOACH', 'NANAA', 'NADAV', 'DADAN', 'EMSI'],
57
- stopTimes: [
58
- {
59
- departure: Time.fromHMS(6, 0, 0),
60
- arrival: Time.fromHMS(7, 0, 0),
61
- pickUpType: 'REGULAR',
62
- dropOffType: 'REGULAR',
63
- },
64
- {
65
- departure: Time.fromHMS(6, 7, 0),
66
- arrival: Time.fromHMS(7, 5, 0),
67
- pickUpType: 'REGULAR',
68
- dropOffType: 'REGULAR',
69
- },
70
- {
71
- departure: Time.fromHMS(6, 14, 0),
72
- arrival: Time.fromHMS(7, 12, 0),
73
- pickUpType: 'REGULAR',
74
- dropOffType: 'REGULAR',
75
- },
76
- {
77
- departure: Time.fromHMS(6, 21, 0),
78
- arrival: Time.fromHMS(7, 19, 0),
79
- pickUpType: 'REGULAR',
80
- dropOffType: 'REGULAR',
81
- },
82
- {
83
- departure: Time.fromHMS(6, 28, 0),
84
- arrival: Time.fromHMS(7, 26, 0),
85
- pickUpType: 'REGULAR',
86
- dropOffType: 'REGULAR',
87
- },
88
- {
89
- departure: Time.fromHMS(6, 0, 0),
90
- arrival: Time.fromHMS(6, 0, 0),
91
- pickUpType: 'REGULAR',
92
- dropOffType: 'REGULAR',
93
- },
94
- {
95
- departure: Time.fromHMS(6, 7, 0),
96
- arrival: Time.fromHMS(6, 5, 0),
97
- pickUpType: 'REGULAR',
98
- dropOffType: 'REGULAR',
99
- },
100
- {
101
- departure: Time.fromHMS(6, 14, 0),
102
- arrival: Time.fromHMS(6, 12, 0),
103
- pickUpType: 'REGULAR',
104
- dropOffType: 'REGULAR',
105
- },
106
- {
107
- departure: Time.fromHMS(6, 21, 0),
108
- arrival: Time.fromHMS(6, 19, 0),
109
- pickUpType: 'REGULAR',
110
- dropOffType: 'REGULAR',
111
- },
112
- {
113
- departure: Time.fromHMS(6, 28, 0),
114
- arrival: Time.fromHMS(6, 26, 0),
115
- pickUpType: 'REGULAR',
116
- dropOffType: 'REGULAR',
117
- },
118
- ],
119
- stopIndices: new Map([
120
- ['STAGECOACH', 0],
121
- ['NANAA', 1],
122
- ['NADAV', 2],
123
- ['DADAN', 3],
124
- ['EMSI', 4],
125
- ]),
126
- },
127
- ],
128
- [
129
- 'CITY_1vpda0p',
130
- {
131
- serviceRouteId: 'CITY',
132
- stops: ['EMSI', 'DADAN', 'NADAV', 'NANAA', 'STAGECOACH'],
133
- stopTimes: [
134
- {
135
- departure: Time.fromHMS(6, 30, 0),
136
- arrival: Time.fromHMS(6, 28, 0),
137
- pickUpType: 'REGULAR',
138
- dropOffType: 'REGULAR',
139
- },
140
- {
141
- departure: Time.fromHMS(6, 37, 0),
142
- arrival: Time.fromHMS(6, 35, 0),
143
- pickUpType: 'REGULAR',
144
- dropOffType: 'REGULAR',
145
- },
146
- {
147
- departure: Time.fromHMS(6, 44, 0),
148
- arrival: Time.fromHMS(6, 42, 0),
149
- pickUpType: 'REGULAR',
150
- dropOffType: 'REGULAR',
151
- },
152
- {
153
- departure: Time.fromHMS(6, 51, 0),
154
- arrival: Time.fromHMS(6, 49, 0),
155
- pickUpType: 'REGULAR',
156
- dropOffType: 'REGULAR',
157
- },
158
- {
159
- departure: Time.fromHMS(6, 58, 0),
160
- arrival: Time.fromHMS(6, 56, 0),
161
- pickUpType: 'REGULAR',
162
- dropOffType: 'REGULAR',
163
- },
164
- ],
165
- stopIndices: new Map([
166
- ['EMSI', 0],
167
- ['DADAN', 1],
168
- ['NADAV', 2],
169
- ['NANAA', 3],
170
- ['STAGECOACH', 4],
171
- ]),
172
- },
173
- ],
174
- [
175
- 'AB_4szggk',
176
- {
177
- serviceRouteId: 'AB',
178
- stops: ['BEATTY_AIRPORT', 'BULLFROG'],
179
- stopTimes: [
180
- {
181
- departure: Time.fromHMS(8, 0, 0),
182
- arrival: Time.fromHMS(8, 0, 0),
183
- pickUpType: 'REGULAR',
184
- dropOffType: 'REGULAR',
185
- },
186
- {
187
- departure: Time.fromHMS(8, 15, 0),
188
- arrival: Time.fromHMS(8, 10, 0),
189
- pickUpType: 'REGULAR',
190
- dropOffType: 'REGULAR',
191
- },
192
- ],
193
- stopIndices: new Map([
194
- ['BEATTY_AIRPORT', 0],
195
- ['BULLFROG', 1],
196
- ]),
197
- },
198
- ],
199
- [
200
- 'AB_7cf41g',
201
- {
202
- serviceRouteId: 'AB',
203
- stops: ['BULLFROG', 'BEATTY_AIRPORT'],
204
- stopTimes: [
205
- {
206
- departure: Time.fromHMS(12, 5, 0),
207
- arrival: Time.fromHMS(12, 5, 0),
208
- pickUpType: 'REGULAR',
209
- dropOffType: 'REGULAR',
210
- },
211
- {
212
- departure: Time.fromHMS(12, 15, 0),
213
- arrival: Time.fromHMS(12, 15, 0),
214
- pickUpType: 'REGULAR',
215
- dropOffType: 'REGULAR',
216
- },
217
- ],
218
- stopIndices: new Map([
219
- ['BULLFROG', 0],
220
- ['BEATTY_AIRPORT', 1],
221
- ]),
222
- },
223
- ],
224
- [
225
- 'BFC_zfm0pg',
226
- {
227
- serviceRouteId: 'BFC',
228
- stops: ['BULLFROG', 'FUR_CREEK_RES'],
229
- stopTimes: [
230
- {
231
- departure: Time.fromHMS(8, 20, 0),
232
- arrival: Time.fromHMS(8, 20, 0),
233
- pickUpType: 'REGULAR',
234
- dropOffType: 'REGULAR',
235
- },
236
- {
237
- departure: Time.fromHMS(9, 20, 0),
238
- arrival: Time.fromHMS(9, 20, 0),
239
- pickUpType: 'REGULAR',
240
- dropOffType: 'REGULAR',
241
- },
242
- ],
243
- stopIndices: new Map([
244
- ['BULLFROG', 0],
245
- ['FUR_CREEK_RES', 1],
246
- ]),
247
- },
248
- ],
249
- [
250
- 'BFC_1xsky4a',
251
- {
252
- serviceRouteId: 'BFC',
253
- stops: ['FUR_CREEK_RES', 'BULLFROG'],
254
- stopTimes: [
255
- {
256
- departure: Time.fromHMS(11, 0, 0),
257
- arrival: Time.fromHMS(11, 0, 0),
258
- pickUpType: 'REGULAR',
259
- dropOffType: 'REGULAR',
260
- },
261
- {
262
- departure: Time.fromHMS(12, 0, 0),
263
- arrival: Time.fromHMS(12, 0, 0),
264
- pickUpType: 'REGULAR',
265
- dropOffType: 'REGULAR',
266
- },
267
- ],
268
- stopIndices: new Map([
269
- ['FUR_CREEK_RES', 0],
270
- ['BULLFROG', 1],
271
- ]),
272
- },
273
- ],
274
- ]);
275
- const expectedStopsAdjacency: StopsAdjacency = new Map([
276
- [
277
- 'STAGECOACH',
278
- {
279
- routes: ['STBA_1kdg12n', 'CITY_asdcjh', 'CITY_1vpda0p'],
280
- transfers: [],
281
- },
282
- ],
283
- [
284
- 'BEATTY_AIRPORT',
285
- {
286
- routes: ['STBA_1kdg12n', 'AB_4szggk', 'AB_7cf41g'],
287
- transfers: [],
288
- },
289
- ],
290
- [
291
- 'NANAA',
292
- {
293
- routes: ['CITY_asdcjh', 'CITY_1vpda0p'],
294
- transfers: [],
295
- },
296
- ],
297
- [
298
- 'NADAV',
299
- {
300
- routes: ['CITY_asdcjh', 'CITY_1vpda0p'],
301
- transfers: [],
302
- },
303
- ],
304
- [
305
- 'DADAN',
306
- {
307
- routes: ['CITY_asdcjh', 'CITY_1vpda0p'],
308
- transfers: [],
309
- },
310
- ],
311
- [
312
- 'EMSI',
313
- {
314
- routes: ['CITY_asdcjh', 'CITY_1vpda0p'],
315
- transfers: [],
316
- },
317
- ],
318
- [
319
- 'BULLFROG',
320
- {
321
- routes: ['AB_4szggk', 'AB_7cf41g', 'BFC_zfm0pg', 'BFC_1xsky4a'],
322
- transfers: [],
323
- },
324
- ],
325
- [
326
- 'FUR_CREEK_RES',
327
- {
328
- routes: ['BFC_zfm0pg', 'BFC_1xsky4a'],
329
- transfers: [],
330
- },
331
- ],
332
- ]);
333
- const expectedRoutes: ServiceRoutesMap = new Map([
334
- [
335
- 'AB',
336
- {
337
- name: '10',
338
- type: 'BUS',
339
- },
340
- ],
341
- [
342
- 'BFC',
343
- {
344
- name: '20',
345
- type: 'BUS',
346
- },
347
- ],
348
- [
349
- 'STBA',
350
- {
351
- name: '30',
352
- type: 'BUS',
353
- },
354
- ],
355
- [
356
- 'CITY',
357
- {
358
- name: '40',
359
- type: 'BUS',
360
- },
361
- ],
362
- [
363
- 'AAMV',
364
- {
365
- name: '50',
366
- type: 'BUS',
367
- },
368
- ],
369
- ]);
370
- const expectedTimetable = new Timetable(
371
- expectedStopsAdjacency,
372
- expectedRoutesAdjacency,
373
- expectedRoutes,
374
- );
375
- const { timetable } = await gtfsParser.parse(date);
376
-
377
- assert.deepEqual(timetable, expectedTimetable);
378
- });
379
- it('should parse stops', async () => {
380
- const expectedStops: StopsMap = new Map([
381
- [
382
- 'FUR_CREEK_RES',
383
- {
384
- id: 'FUR_CREEK_RES',
385
- name: 'Furnace Creek Resort (Demo)',
386
- lat: 36.425288,
387
- lon: -117.133162,
388
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
389
- children: [],
390
- },
391
- ],
392
- [
393
- 'BEATTY_AIRPORT',
394
- {
395
- id: 'BEATTY_AIRPORT',
396
- name: 'Nye County Airport (Demo)',
397
- lat: 36.868446,
398
- lon: -116.784582,
399
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
400
- children: [],
401
- },
402
- ],
403
- [
404
- 'BULLFROG',
405
- {
406
- id: 'BULLFROG',
407
- name: 'Bullfrog (Demo)',
408
- lat: 36.88108,
409
- lon: -116.81797,
410
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
411
- children: [],
412
- },
413
- ],
414
- [
415
- 'STAGECOACH',
416
- {
417
- id: 'STAGECOACH',
418
- name: 'Stagecoach Hotel & Casino (Demo)',
419
- lat: 36.915682,
420
- lon: -116.751677,
421
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
422
- children: [],
423
- },
424
- ],
425
- [
426
- 'NADAV',
427
- {
428
- id: 'NADAV',
429
- name: 'North Ave / D Ave N (Demo)',
430
- lat: 36.914893,
431
- lon: -116.76821,
432
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
433
- children: [],
434
- },
435
- ],
436
- [
437
- 'NANAA',
438
- {
439
- id: 'NANAA',
440
- name: 'North Ave / N A Ave (Demo)',
441
- lat: 36.914944,
442
- lon: -116.761472,
443
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
444
- children: [],
445
- },
446
- ],
447
- [
448
- 'DADAN',
449
- {
450
- id: 'DADAN',
451
- name: 'Doing Ave / D Ave N (Demo)',
452
- lat: 36.909489,
453
- lon: -116.768242,
454
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
455
- children: [],
456
- },
457
- ],
458
- [
459
- 'EMSI',
460
- {
461
- id: 'EMSI',
462
- name: 'E Main St / S Irving St (Demo)',
463
- lat: 36.905697,
464
- lon: -116.76218,
465
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
466
- children: [],
467
- },
468
- ],
469
- ]);
470
- const { stopsIndex } = await gtfsParser.parse(date);
471
-
472
- assert.deepEqual(stopsIndex, new StopsIndex(expectedStops));
473
- });
11
+ parser = new GtfsParser(gtfsPath);
474
12
  });
475
- });
476
-
477
- describe('parse gtfs stops', () => {
478
- let gtfsParser: GtfsParser;
479
- beforeEach(() => {
480
- const gtfsPath = './src/gtfs/__tests__/resources/sample-feed.zip';
481
- gtfsParser = new GtfsParser(gtfsPath);
13
+ it('should correctly parse stops from GTFS feed', async () => {
14
+ const stopsIndex = await parser.parseStops();
15
+ assert.strictEqual(stopsIndex.size(), 9);
16
+ const stop = stopsIndex.findStopBySourceStopId('FUR_CREEK_RES');
17
+ assert(stop);
18
+ assert.strictEqual(stop.name, 'Furnace Creek Resort (Demo)');
19
+ assert.strictEqual(stop.lat, 36.425288);
20
+ assert.strictEqual(stop.lon, -117.133162);
482
21
  });
483
- describe('given a gtfs feed', () => {
484
- it('should parse stops', async () => {
485
- const expectedStops: StopsMap = new Map([
486
- [
487
- 'FUR_CREEK_RES',
488
- {
489
- id: 'FUR_CREEK_RES',
490
- name: 'Furnace Creek Resort (Demo)',
491
- lat: 36.425288,
492
- lon: -117.133162,
493
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
494
- children: [],
495
- },
496
- ],
497
- [
498
- 'BEATTY_AIRPORT',
499
- {
500
- id: 'BEATTY_AIRPORT',
501
- name: 'Nye County Airport (Demo)',
502
- lat: 36.868446,
503
- lon: -116.784582,
504
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
505
- children: [],
506
- },
507
- ],
508
- [
509
- 'BULLFROG',
510
- {
511
- id: 'BULLFROG',
512
- name: 'Bullfrog (Demo)',
513
- lat: 36.88108,
514
- lon: -116.81797,
515
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
516
- children: [],
517
- },
518
- ],
519
- [
520
- 'STAGECOACH',
521
- {
522
- id: 'STAGECOACH',
523
- name: 'Stagecoach Hotel & Casino (Demo)',
524
- lat: 36.915682,
525
- lon: -116.751677,
526
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
527
- children: [],
528
- },
529
- ],
530
- [
531
- 'NADAV',
532
- {
533
- id: 'NADAV',
534
- name: 'North Ave / D Ave N (Demo)',
535
- lat: 36.914893,
536
- lon: -116.76821,
537
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
538
- children: [],
539
- },
540
- ],
541
- [
542
- 'NANAA',
543
- {
544
- id: 'NANAA',
545
- name: 'North Ave / N A Ave (Demo)',
546
- lat: 36.914944,
547
- lon: -116.761472,
548
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
549
- children: [],
550
- },
551
- ],
552
- [
553
- 'DADAN',
554
- {
555
- id: 'DADAN',
556
- name: 'Doing Ave / D Ave N (Demo)',
557
- lat: 36.909489,
558
- lon: -116.768242,
559
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
560
- children: [],
561
- },
562
- ],
563
- [
564
- 'EMSI',
565
- {
566
- id: 'EMSI',
567
- name: 'E Main St / S Irving St (Demo)',
568
- lat: 36.905697,
569
- lon: -116.76218,
570
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
571
- children: [],
572
- },
573
- ],
574
- [
575
- 'AMV',
576
- {
577
- id: 'AMV',
578
- name: 'Amargosa Valley (Demo)',
579
- lat: 36.641496,
580
- lon: -116.40094,
581
- locationType: 'SIMPLE_STOP_OR_PLATFORM',
582
- children: [],
583
- },
584
- ],
585
- ]);
586
- const stops = await gtfsParser.parseStops();
587
22
 
588
- assert.deepStrictEqual(stops, new StopsIndex(expectedStops));
589
- });
23
+ it('should correctly parse timetable from GTFS feed', async () => {
24
+ const { timetable, stopsIndex } = await parser.parse(
25
+ new Date('2007-01-10'),
26
+ );
27
+
28
+ const furCreekResId =
29
+ stopsIndex.findStopBySourceStopId('FUR_CREEK_RES')?.id;
30
+ assert(furCreekResId !== undefined);
31
+ const transfers = timetable.getTransfers(furCreekResId);
32
+ assert.strictEqual(transfers.length, 0);
33
+
34
+ const route = timetable.getRoute('AB_x');
35
+ assert(route);
36
+ assert.strictEqual(route.serviceRouteId, 'AB');
37
+ const beattyAirportId =
38
+ stopsIndex.findStopBySourceStopId('BEATTY_AIRPORT')?.id;
39
+ const bullfrogId = stopsIndex.findStopBySourceStopId('BULLFROG')?.id;
40
+ assert(beattyAirportId !== undefined && bullfrogId !== undefined);
41
+ assert.deepStrictEqual(Array.from(route.stops), [
42
+ beattyAirportId,
43
+ bullfrogId,
44
+ ]);
45
+ assert.strictEqual(route.stopTimes.length, 4);
46
+ assert.strictEqual(route.pickUpDropOffTypes.length, 4);
47
+ assert.strictEqual(route.stopTimes[0], Time.fromHMS(8, 0, 0).toSeconds());
48
+ assert.strictEqual(route.stopTimes[1], Time.fromHMS(8, 0, 0).toSeconds());
49
+ assert.strictEqual(route.stopTimes[2], Time.fromHMS(8, 10, 0).toSeconds());
50
+ assert.strictEqual(route.stopTimes[3], Time.fromHMS(8, 15, 0).toSeconds());
51
+
52
+ const routes = timetable.getRoutesThroughStop(furCreekResId);
53
+ assert.strictEqual(routes.length, 2);
54
+ assert.strictEqual(routes[0], 'BFC_1q');
55
+ assert.strictEqual(routes[1], 'BFC_2');
56
+
57
+ const serviceRoute = timetable.getServiceRoute('AB');
58
+ assert(serviceRoute);
59
+ assert.strictEqual(serviceRoute.name, '10');
60
+ assert.strictEqual(serviceRoute.type, 'BUS');
590
61
  });
591
62
  });