assertSame( ['Hannover', 'Göttingen', 'Mannheim', 'Kassel', 'Frankfurt', 'Karlsruhe', 'Basel'], array_column($sorted, 'city'), ); } public function testADatedDepartureAfterMidnightKeepsItsOwnDay(): void { // destination DKIWE/110425: 03:15 carries the next day's date itself, so it must not // be pulled back in front of the evening departures $sorted = PickupDepartureOrder::sort([ self::pickup(1, 'Kiel', '02:15'), self::pickup(2, 'Hamburg', '10.04.2025 23:59:00'), self::pickup(3, 'Flensburg', '10.04.2025 21:30:00'), self::pickup(4, 'Lübeck', '10.04.2025 23:00:00'), self::pickup(5, 'Bremen', '11.04.2025 03:15:00'), self::pickup(6, 'Rostock', '01:00'), self::pickup(7, 'Schwerin', '04:15'), ]); $this->assertSame( ['Flensburg', 'Lübeck', 'Hamburg', 'Rostock', 'Kiel', 'Bremen', 'Schwerin'], array_column($sorted, 'city'), ); } public function testWithoutAnyDatedEntryTheClockAloneOrders(): void { $sorted = PickupDepartureOrder::sort([ self::pickup(1, 'Ulm', '07:30'), self::pickup(2, 'Augsburg', '05:15'), self::pickup(3, 'München', '09:00'), ]); $this->assertSame(['Augsburg', 'Ulm', 'München'], array_column($sorted, 'city')); } public function testAResolvedDatetimeWinsOverTheStoredTime(): void { // what MyE&P's travel export delivers: time for display, datetime for ordering $sorted = PickupDepartureOrder::sort([ [...self::pickup(1, 'Kassel', '00:30'), 'datetime' => '2024-03-09T00:30:00+01:00'], [...self::pickup(2, 'Hannover', '20:45'), 'datetime' => '2024-03-08T20:45:00+01:00'], ]); $this->assertSame(['Hannover', 'Kassel'], array_column($sorted, 'city')); } public function testEntriesWithoutAReadableTimeGoLastInTheirStoredOrder(): void { $sorted = PickupDepartureOrder::sort([ self::pickup(1, 'Ohne Zeit', ''), self::pickup(2, 'Nur Datum', '16.02.2024'), self::pickup(3, 'Bremen', '22:00'), self::pickup(4, 'Gar nichts', null), ]); $this->assertSame( ['Bremen', 'Ohne Zeit', 'Nur Datum', 'Gar nichts'], array_column($sorted, 'city'), ); } public function testTheClockReadsBothStoredTimeShapes(): void { $this->assertSame('20:45', PickupDepartureOrder::clock(self::pickup(1, 'Hannover', '08.03.2024 20:45:00'))); $this->assertSame('02:15', PickupDepartureOrder::clock(self::pickup(2, 'Kassel', '02:15'))); } public function testTheClockIsNullWhenNoTimeCanBeRead(): void { $this->assertNull(PickupDepartureOrder::clock(self::pickup(1, 'Nur Datum', '16.02.2024'))); $this->assertNull(PickupDepartureOrder::clock(self::pickup(2, 'Ohne Zeit', ''))); $this->assertNull(PickupDepartureOrder::clock(self::pickup(3, 'Gar nichts', null))); } public function testTheClockPrefersAResolvedDatetime(): void { $pickup = [...self::pickup(1, 'Hannover', '08.03.2024 20:45:00'), 'datetime' => '2024-03-08T20:45:00+01:00']; $this->assertSame('20:45', PickupDepartureOrder::clock($pickup)); } public function testAnEmptyListStaysEmpty(): void { $this->assertSame([], PickupDepartureOrder::sort([])); } public function testTheStoredEntriesArePassedThroughUntouched(): void { $pickups = [self::pickup(7, 'Bremen', '22:00')]; $this->assertSame($pickups, PickupDepartureOrder::sort($pickups)); } /** * @return array */ private static function pickup(int $busProId, string $city, ?string $time): array { return [ 'busProId' => $busProId, 'city' => $city, 'street' => 'Irgendwo 1', 'time' => $time, ]; } }