'7', 'attivo' => true, 'confini' => "Nord: via Roma\nSud: via Milano", ]); $mappa = TerritorioMappa::create([ 'territorio_id' => $territorio->id, 'geojson' => '{"type":"Polygon","coordinates":[[[1,1],[2,1],[2,2],[1,1]]]}', 'image_path' => 'territori-mappe/territorio-' . $territorio->id . '.png', 'rendered_at' => now(), ]); // Un PNG vero, piccolo: FPDF lo legge davvero, un finto no. $immagine = imagecreatetruecolor(80, 50); imagefilledrectangle($immagine, 0, 0, 79, 49, imagecolorallocate($immagine, 230, 230, 230)); ob_start(); imagepng($immagine); Storage::disk('public')->put($mappa->image_path, ob_get_clean()); imagedestroy($immagine); return [$territorio, $mappa]; } private function servizio(): PiantinaPdfService { return app(PiantinaPdfService::class); } public function test_genera_produce_un_pdf_di_due_pagine(): void { [$territorio, $mappa] = $this->territorioConImmagine(); $pdf = $this->servizio()->genera($territorio, $mappa); $this->assertStringStartsWith('%PDF', $pdf); // FPDF conta le pagine nel catalogo: /Count 2. $this->assertStringContainsString('/Count 2', $pdf); } /** * La "Località" del modulo è il nome della zona: un dato solo, in un posto * solo, che si aggiorna quando la congregazione riorganizza il lavoro. */ public function test_la_localita_stampata_e_il_nome_della_zona(): void { [$territorio, $mappa] = $this->territorioConImmagine(); $zona = \App\Models\Zona::create(['nome' => 'Palermo Montepellegrino', 'attivo' => true]); $territorio->update(['zona_id' => $zona->id]); $testo = $this->testoDel($this->servizio()->genera($territorio->fresh(), $mappa)); $this->assertStringContainsString('Palermo Montepellegrino', $testo); } public function test_senza_zona_l_intestazione_resta_vuota_senza_rompere_nulla(): void { [$territorio, $mappa] = $this->territorioConImmagine(); $pdf = $this->servizio()->genera($territorio, $mappa); $this->assertStringStartsWith('%PDF', $pdf); } /** I confini vanno sulla cartolina, non su una pagina a parte. */ public function test_i_confini_finiscono_nel_pdf(): void { [$territorio, $mappa] = $this->territorioConImmagine(); $testo = $this->testoDel($this->servizio()->genera($territorio, $mappa)); $this->assertStringContainsString('Nord: via Roma', $testo); $this->assertStringContainsString('Sud: via Milano', $testo); } public function test_senza_confini_il_pdf_lo_dichiara(): void { [$territorio, $mappa] = $this->territorioConImmagine(); $territorio->update(['confini' => null]); $testo = $this->testoDel($this->servizio()->genera($territorio->refresh(), $mappa)); $this->assertStringContainsString('Confini non ancora descritti', $testo); } /** * Il testo scritto da FPDF vive dentro i flussi compressi delle pagine: * per leggerlo vanno estratti e decompressi. */ private function testoDel(string $pdf): string { $testo = ''; if (preg_match_all('/stream\r?\n(.*?)\r?\nendstream/s', $pdf, $trovati)) { foreach ($trovati[1] as $flusso) { $decompresso = @gzuncompress($flusso); if ($decompresso !== false) { $testo .= $decompresso; } } } return $testo; } public function test_genera_senza_immagine_si_ferma_con_un_messaggio_chiaro(): void { [$territorio, $mappa] = $this->territorioConImmagine(); Storage::disk('public')->delete($mappa->image_path); $this->expectException(RuntimeException::class); $this->servizio()->genera($territorio, $mappa); } public function test_sostituisci_archivia_il_pdf_precedente_nello_storico(): void { [$territorio, $mappa] = $this->territorioConImmagine(); Storage::disk('public')->put('territori-pdf/vecchio.pdf', '%PDF-vecchio'); $territorio->update(['pdf_path' => 'territori-pdf/vecchio.pdf']); $this->servizio()->sostituisci($territorio, $mappa); $territorio->refresh(); $this->assertNotSame('territori-pdf/vecchio.pdf', $territorio->pdf_path); Storage::disk('public')->assertExists($territorio->pdf_path); Storage::disk('public')->assertMissing('territori-pdf/vecchio.pdf'); $versione = TerritorioPdfVersione::sole(); $this->assertSame($territorio->id, $versione->territorio_id); Storage::disk('public')->assertExists($versione->pdf_path); $this->assertSame('%PDF-vecchio', Storage::disk('public')->get($versione->pdf_path)); } public function test_sostituisci_senza_pdf_precedente_non_crea_versioni(): void { [$territorio, $mappa] = $this->territorioConImmagine(); $this->servizio()->sostituisci($territorio, $mappa); $this->assertNotNull($territorio->refresh()->pdf_path); $this->assertSame(0, TerritorioPdfVersione::count()); } public function test_ripristina_rimette_in_vigore_la_versione_e_archivia_l_attuale(): void { [$territorio, $mappa] = $this->territorioConImmagine(); Storage::disk('public')->put('territori-pdf/vecchio.pdf', '%PDF-vecchio'); $territorio->update(['pdf_path' => 'territori-pdf/vecchio.pdf']); $this->servizio()->sostituisci($territorio, $mappa); $versione = TerritorioPdfVersione::sole(); $this->servizio()->ripristina($versione); $territorio->refresh(); $this->assertSame('%PDF-vecchio', Storage::disk('public')->get($territorio->pdf_path)); // La versione usata e' sparita; al suo posto c'e' quella del PDF che // era in vigore, quindi il ripristino resta a sua volta reversibile. $this->assertSame(0, TerritorioPdfVersione::whereKey($versione->id)->count()); $this->assertSame(1, TerritorioPdfVersione::count()); $this->assertSame('ripristino', TerritorioPdfVersione::sole()->origine); } public function test_ripristina_con_file_sparito_si_ferma_con_un_messaggio_chiaro(): void { [$territorio] = $this->territorioConImmagine(); $versione = TerritorioPdfVersione::create([ 'territorio_id' => $territorio->id, 'pdf_path' => 'territori-pdf-versioni/inesistente.pdf', 'origine' => 'sostituzione', 'sostituito_il' => now(), ]); $this->expectException(RuntimeException::class); $this->servizio()->ripristina($versione); } }