OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

MaintenanceSpanTest.php

6 KB
<?php

declare(strict_types=1);

/**
 * Deckt die Darstellung mehrtägiger Wartungstermine ab.
 *
 * Ein Termin über mehrere Tage gehört an jeden Tag seines Zeitraums, nicht nur
 * an seinen Beginn. Das betrifft zwei Stellen: die Abfrage muss ihn finden,
 * sobald er den angezeigten Monat berührt, und das Raster muss ihn auf alle
 * Tage verteilen.
 */
return static function (): void {

    /**
     * Bildet die Zuordnung des Kalenders nach: Termin auf Tage verteilen,
     * begrenzt auf den angezeigten Monat.
     *
     * @param array<string,?string> $termin
     * @return array<string,string> Tag => Lage im Zeitraum
     */
    $verteilen = static function (array $termin, int $jahr, int $monat): array {
        $von = (string)$termin['date'];
        $bis = !empty($termin['end_date']) ? (string)$termin['end_date'] : $von;
        if ($bis < $von) {
            $bis = $von;
        }

        $tag  = max($von, sprintf('%04d-%02d-01', $jahr, $monat));
        $ende = min($bis, date('Y-m-t', mktime(0, 0, 0, $monat, 1, $jahr)));

        $karte = [];
        while ($tag <= $ende) {
            $karte[$tag] = $von === $bis
                ? 'single'
                : ($tag === $von ? 'start' : ($tag === $bis ? 'end' : 'middle'));
            $tag = date('Y-m-d', strtotime($tag . ' +1 day'));
        }
        return $karte;
    };

    // ----------------------------------------------------------------
    // Verteilung auf die Tage
    // ----------------------------------------------------------------

    test('Ein eintägiger Termin belegt genau seinen Tag', function () use ($verteilen) {
        $karte = $verteilen(['date' => '2026-09-10', 'end_date' => null], 2026, 9);

        assertSame(['2026-09-10' => 'single'], $karte);
    });

    test('Ein Enddatum gleich dem Startdatum bleibt eintägig', function () use ($verteilen) {
        $karte = $verteilen(['date' => '2026-09-10', 'end_date' => '2026-09-10'], 2026, 9);

        assertSame(['2026-09-10' => 'single'], $karte);
    });

    test('Ein mehrtägiger Termin belegt jeden Tag dazwischen', function () use ($verteilen) {
        $karte = $verteilen(['date' => '2026-09-08', 'end_date' => '2026-09-11'], 2026, 9);

        assertSame(
            ['2026-09-08', '2026-09-09', '2026-09-10', '2026-09-11'],
            array_keys($karte)
        );
        assertSame(['start', 'middle', 'middle', 'end'], array_values($karte));
    });

    test('Ein Termin über den Monatswechsel wird auf den Monat beschnitten', function () use ($verteilen) {
        // Beginn im August, Ende im September: Der September zeigt seinen Teil.
        $karte = $verteilen(['date' => '2026-08-30', 'end_date' => '2026-09-02'], 2026, 9);

        assertSame(['2026-09-01', '2026-09-02'], array_keys($karte));
        // Der Beginn liegt außerhalb – der letzte Tag bleibt trotzdem das Ende.
        assertSame('middle', $karte['2026-09-01']);
        assertSame('end', $karte['2026-09-02']);
    });

    test('Derselbe Termin erscheint auch im Vormonat', function () use ($verteilen) {
        $karte = $verteilen(['date' => '2026-08-30', 'end_date' => '2026-09-02'], 2026, 8);

        assertSame(['2026-08-30', '2026-08-31'], array_keys($karte));
        assertSame('start', $karte['2026-08-30']);
    });

    test('Ein verdrehtes Enddatum erzeugt keinen leeren oder endlosen Zeitraum', function () use ($verteilen) {
        $karte = $verteilen(['date' => '2026-09-10', 'end_date' => '2026-09-01'], 2026, 9);

        assertSame(['2026-09-10' => 'single'], $karte);
    });

    test('Ein Termin außerhalb des Monats belegt keinen Tag', function () use ($verteilen) {
        assertSame([], $verteilen(['date' => '2026-07-01', 'end_date' => '2026-07-05'], 2026, 9));
    });

    // ----------------------------------------------------------------
    // Abfrage
    // ----------------------------------------------------------------

    test('Die Abfrage findet Termine, die den Zeitraum nur berühren', function () {
        // Ein im Vormonat begonnener Termin fällt sonst ganz aus der Ansicht.
        $src = (string)file_get_contents(dirname(__DIR__) . '/src/Controllers/MaintenanceController.php');

        assertTrue(
            str_contains($src, 'AND event_date <= ?')
            && str_contains($src, 'AND COALESCE(end_date, event_date) >= ?'),
            'Die Abfrage prüft keine Überschneidung mit dem Zeitraum'
        );
        assertFalse(
            str_contains($src, 'source = ? AND event_date BETWEEN ? AND ?'),
            'Die alte, auf den Starttag begrenzte Bedingung ist noch vorhanden'
        );
    });

    // ----------------------------------------------------------------
    // Darstellung
    // ----------------------------------------------------------------

    test('Das Raster zeichnet den Zeitraum als durchgehenden Balken', function () {
        $tpl = (string)file_get_contents(dirname(__DIR__) . '/templates/maintenance/index.php');

        foreach (['mc-event-pill--start', 'mc-event-pill--middle', 'mc-event-pill--end'] as $klasse) {
            assertTrue(str_contains($tpl, '.' . $klasse), 'Kein Stil für ' . $klasse);
        }
        assertTrue(str_contains($tpl, "\$ev['span']"), 'Die Lage im Zeitraum wird nicht ausgewertet');
    });

    test('Ein bereits laufender Termin wird nicht mit negativen Tagen ausgewiesen', function () {
        $tpl = (string)file_get_contents(dirname(__DIR__) . '/templates/maintenance/index.php');

        assertTrue(str_contains($tpl, "\$dl < 0"), 'Der laufende Fall wird nicht unterschieden');
        assertTrue(str_contains($tpl, "'läuft'"), 'Für laufende Termine fehlt die Beschriftung');
    });
};