blade('', ['p' => [10, 20, null, 40, 50]]); // Zwei Züge: einer vor der Lücke, einer danach. Ein einziges `M` hieße, // die Linie läuft durch. expect(substr_count($view->__toString(), 'toBe(2); }); it('draws one unbroken line when nothing is missing', function () { // Die Gegenprobe: an sauberen Reihen — und das sind alle bisherigen // Aufrufer — darf sich nichts ändern. $view = $this->blade('', ['p' => [10, 20, 30, 40, 50]]); expect(substr_count($view->__toString(), 'toBe(1); }); it('keeps later points in place when an earlier one is missing', function () { // Der eigentliche Schaden am Filtern: der letzte Punkt einer Stunde muss // ganz rechts liegen, egal wie viele Messwerte dazwischen fehlen. $withGap = $this->blade('', ['p' => [10, null, 30, 40, 50]])->__toString(); $without = $this->blade('', ['p' => [10, 20, 30, 40, 50]])->__toString(); expect($withGap)->toContain('96 ') // rechter Rand erreicht ->and($without)->toContain('96 '); }); it('closes the filled area with a path a renderer can actually follow', function () { // Beim Zerlegen in Züge ist der Flächenpfad kurz `… L` direkt vor einem `M` // geworden — gültig sieht das aus, gezeichnet wird es nicht, und die // Füllung verschwand still. Ein Blick auf die Seite hat es gezeigt, keine // Meldung. $view = $this->blade('', ['p' => [10, 20, null, 40, 50]])->__toString(); preg_match_all('/class="area"[^>]*\sd="([^"]+)"/', $view, $m); expect($m[1])->toHaveCount(2); foreach ($m[1] as $d) { expect($d)->toStartWith('M') ->and($d)->not->toContain('LM') // ein Befehl direkt hinter einem anderen ->and($d)->toEndWith('Z'); } }); it('draws nothing at all when every sample is missing', function () { $view = $this->blade('', ['p' => [null, null]]); expect($view->__toString())->not->toContain(' $n) { if ($i % 2 === 1) { $ys[] = (float) $n; } } } return $ys; } it('keeps a nearly idle host near the baseline instead of filling the box', function () { $html = $this->blade('', ['p' => [0.1, 0.3, 0.2, 0.25]])->__toString(); // 30 ist die Grundlinie, 4 die Oberkante. Bei 0,2 % darf nichts hochspringen. expect(max(sparkY($html)))->toBeGreaterThan(29.0) ->and(min(sparkY($html)))->toBeGreaterThan(29.0); }); it('still uses the whole box when the load really does span it', function () { $html = $this->blade('', ['p' => [0, 100]])->__toString(); expect(min(sparkY($html)))->toBe(4.0) // 100 % ganz oben ->and(max(sparkY($html)))->toBe(30.0); // 0 % auf der Grundlinie }); it('draws a flat line at the bottom when nothing moved at all', function () { // Die Netz-Kacheln eines ruhigen Hosts: lauter Nullen. Ohne verankerte // Untergrenze wurde daraus eine Linie irgendwo in der Mitte. $html = $this->blade('', ['p' => [0, 0, 0, 0]])->__toString(); expect(array_unique(sparkY($html)))->toBe([30.0]); }); it('scales to the series itself when no bounds are given', function () { // Die Gegenprobe: alle bisherigen Aufrufer geben keine Grenzen mit und // dürfen sich nicht verändern. $html = $this->blade('', ['p' => [10, 20]])->__toString(); expect(min(sparkY($html)))->toBe(4.0) ->and(max(sparkY($html)))->toBe(30.0); });