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" d="([^"]+)"/', $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('