OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

TicketScopeConsistencyTest.php

5 KB
<?php

declare(strict_types=1);

/**
 * Der Sichtbereich gilt überall gleich – auch in den Zahlen.
 *
 * Wer nur Tickets bestimmter Standorte sehen darf, bekommt die Liste
 * eingeschränkt. Die Zahlen daneben müssen denselben Bereich meinen: Der
 * Einstieg in „Mein Bereich", die Zahl am Reiter und die Meldung über neu
 * eingegangene Tickets. Weichen sie ab, führt der Einstieg auf eine leere
 * Ansicht oder es wird etwas gemeldet, das sich nicht öffnen lässt.
 */

use OpenNIT\Tickets\TicketManager;

return static function (): void {

    $wurzel = dirname(__DIR__);
    $quelle = static fn (string $pfad): string => (string)file_get_contents($wurzel . '/' . $pfad);

    // ----------------------------------------------------------------
    // Die Zählung selbst
    // ----------------------------------------------------------------

    /** Ein Manager, der die abgesetzte Abfrage festhält. */
    $manager = static function (array $zeile): array {
        $db = new class ($zeile) extends OpenNIT\Core\Database {
            public string $sql = '';
            /** @var list<mixed> */
            public array $params = [];

            public function __construct(private array $zeile)
            {
            }

            public function fetchOne(string $sql, array $params = []): ?array
            {
                $this->sql    = $sql;
                $this->params = $params;
                return $this->zeile;
            }
        };

        $klasse = new ReflectionClass(TicketManager::class);
        $tm     = $klasse->newInstanceWithoutConstructor();
        $feld   = $klasse->getProperty('db');
        $feld->setAccessible(true);
        $feld->setValue($tm, $db);

        return [$tm, $db];
    };

    test('Ohne Einschränkung zählt die Abfrage alles', function () use ($manager) {
        [$tm, $db] = $manager(['c' => 3, 'm' => '2026-09-16 10:00:00']);

        [$anzahl, $marke] = $tm->countNewSince('2026-09-16 09:00:00', null);

        assertSame(3, $anzahl);
        assertSame('2026-09-16 10:00:00', $marke);
        assertFalse(str_contains($db->sql, 'IN ('), 'Ohne Einschränkung wurde dennoch eingeschränkt');
        assertSame(['2026-09-16 09:00:00'], $db->params);
    });

    test('Mit Einschränkung zählt sie nur die erlaubten Standorte', function () use ($manager) {
        [$tm, $db] = $manager(['c' => 1, 'm' => '2026-09-16 10:00:00']);

        $tm->countNewSince('2026-09-16 09:00:00', [4, 7]);

        assertTrue(str_contains($db->sql, 't.location_id IN (?,?)'), 'Der Sichtbereich fehlt in der Abfrage');
        assertSame(['2026-09-16 09:00:00', 4, 7], $db->params);
    });

    test('Ein leerer Sichtbereich zählt nichts', function () use ($manager) {
        // Nicht „alles": Wer keinen Standort sehen darf, sieht keine Tickets.
        [$tm, $db] = $manager(['c' => 0, 'm' => null]);

        [$anzahl, $marke] = $tm->countNewSince('2026-09-16 09:00:00', []);

        assertTrue(str_contains($db->sql, '1=0'), 'Ein leerer Sichtbereich wurde als uneingeschränkt gelesen');
        assertSame(0, $anzahl);
        assertSame('2026-09-16 09:00:00', $marke, 'Ohne Treffer bleibt die bisherige Marke stehen');
    });

    test('Zahl und Marke stammen aus einer Abfrage', function () use ($manager) {
        // Zwei Abfragen ließen zwischen beiden ein Ticket entstehen, das dann
        // zweimal gemeldet würde.
        [$tm, $db] = $manager(['c' => 2, 'm' => '2026-09-16 11:30:00']);

        $tm->countNewSince('2026-09-16 09:00:00', null);

        assertTrue(str_contains($db->sql, 'COUNT(*)'), 'Die Zählung fehlt');
        assertTrue(str_contains($db->sql, 'MAX(t.created_at)'), 'Die Marke kommt nicht aus derselben Abfrage');
    });

    // ----------------------------------------------------------------
    // Die Stellen, die zählen
    // ----------------------------------------------------------------

    test('Jede Zählstelle der Ticketliste kennt den Sichtbereich', function () use ($quelle) {
        $ctrl = $quelle('src/Controllers/TicketController.php');

        foreach (['public function index(', 'public function apiPoll('] as $stelle) {
            $von = strpos($ctrl, $stelle);
            assertTrue($von !== false, 'Die Stelle ' . $stelle . ' fehlt');
            $rumpf = substr($ctrl, $von, 4000);

            assertTrue(
                str_contains($rumpf, "\$this->accessibleLocations('view_tickets')"),
                $stelle . ' ermittelt den Sichtbereich nicht'
            );
            assertFalse(
                (bool)preg_match('/getMineCount\(\$userId\)/', $rumpf),
                $stelle . ' zählt „Mein Bereich" ohne Sichtbereich'
            );
        }
    });

    test('Die Meldung über neue Tickets zählt nicht an der Liste vorbei', function () use ($quelle) {
        $ctrl = $quelle('src/Controllers/TicketController.php');
        $von  = strpos($ctrl, 'public function apiPoll(');
        $rumpf = substr($ctrl, (int)$von, 4000);

        assertTrue(
            str_contains($rumpf, '$this->tickets->countNewSince('),
            'Die Zählung läuft nicht über die gemeinsame Stelle'
        );
        assertFalse(
            str_contains($rumpf, 'FROM tickets WHERE created_at > ?'),
            'Die Zählung geht wieder eigene Wege an der Berechtigung vorbei'
        );
    });
};