'amministratore', 'guard_name' => 'web']); Role::create(['name' => 'assistente', 'guard_name' => 'web']); $this->admin = User::create([ 'name' => 'Amministratore', 'email' => 'admin@example.test', 'password' => 'password-attuale', ]); $this->admin->assignRole('amministratore'); $this->actingAs($this->admin); } // ─── Round-trip ───────────────────────────────────────────── /** * Il difetto che spostava ogni data indietro di un giorno a ogni giro di * backup e ripristino: toArray() le serializzava in UTC. */ public function test_export_e_reimport_conservano_le_date_esatte(): void { $anno = AnnoTeocratico::create(['label' => '2025-2026', 'start_date' => '2025-09-01', 'end_date' => '2026-08-31']); Campagna::create(['descrizione' => 'Commemorazione', 'start_date' => '2026-03-01', 'end_date' => '2026-03-31']); $territorio = Territorio::create(['numero' => '7', 'attivo' => true]); $proclamatore = Proclamatore::create(['nome' => 'Mario', 'cognome' => 'Rossi', 'attivo' => true]); Assegnazione::create([ 'territorio_id' => $territorio->id, 'proclamatore_id' => $proclamatore->id, 'anno_teocratico_id' => $anno->id, 'assigned_at' => '2026-03-15', 'returned_at' => '2026-04-01', 'created_by' => $this->admin->id, ]); $this->reimporta(); $assegnazione = Assegnazione::sole(); $this->assertSame('2026-03-15', $assegnazione->assigned_at->toDateString()); $this->assertSame('2026-04-01', $assegnazione->returned_at->toDateString()); $anno = AnnoTeocratico::sole(); $this->assertSame('2025-09-01', $anno->start_date->toDateString()); $this->assertSame('2026-08-31', $anno->end_date->toDateString()); $campagna = Campagna::sole(); $this->assertSame('2026-03-01', $campagna->start_date->toDateString()); $this->assertSame('2026-03-31', $campagna->end_date->toDateString()); } /** I backup fatti prima della correzione hanno le date in UTC: tornano giuste. */ public function test_un_backup_vecchio_con_date_in_utc_viene_riportato_al_giorno_giusto(): void { $xml = $this->xmlMinimo( anni: '2025-08-31T22:00:00.000000Z2026-08-30T22:00:00.000000Z', assegnazioni: '1112026-03-14T23:00:00.000000Z', ); $this->assertArrayNotHasKey('error', $this->importa($xml)); $this->assertSame('2026-03-15', Assegnazione::sole()->assigned_at->toDateString()); $this->assertSame('2025-09-01', AnnoTeocratico::sole()->start_date->toDateString()); $this->assertSame('2026-08-31', AnnoTeocratico::sole()->end_date->toDateString()); } /** Un carattere di controllo in una nota rendeva l'intero file illeggibile. */ public function test_un_carattere_di_controllo_in_una_nota_non_rompe_il_file(): void { Territorio::create(['numero' => '1', 'attivo' => true, 'note' => "Citofono\x0Brotto\x01"]); $xml = (new XmlExchange())->currentXmlBackup(); $this->assertNotFalse(simplexml_load_string($xml)); $this->reimporta($xml); $this->assertSame('Citofonorotto', Territorio::sole()->note); } /** * Un territorio resta senza zona quando la sua zona viene eliminata: al * reimport veniva scartato insieme a tutte le sue assegnazioni. */ public function test_un_territorio_senza_zona_viene_importato_con_il_suo_storico(): void { $anno = AnnoTeocratico::create(['label' => '2025-2026', 'start_date' => '2025-09-01', 'end_date' => '2026-08-31']); $territorio = Territorio::create(['numero' => '3', 'attivo' => true, 'zona_id' => null]); $proclamatore = Proclamatore::create(['nome' => 'Anna', 'cognome' => 'Bianchi', 'attivo' => true]); Assegnazione::create([ 'territorio_id' => $territorio->id, 'proclamatore_id' => $proclamatore->id, 'anno_teocratico_id' => $anno->id, 'assigned_at' => '2025-10-01', 'created_by' => $this->admin->id, ]); $this->reimporta(); $this->assertNull(Territorio::sole()->zona_id); $this->assertSame(1, Assegnazione::count()); } // ─── File da rifiutare ────────────────────────────────────── public function test_un_xml_estraneo_viene_rifiutato_senza_toccare_i_dati(): void { Territorio::create(['numero' => '1', 'attivo' => true]); $esito = $this->importa('https://example.org'); $this->assertStringContainsString('non è un export di TerManager2', $esito['error']); $this->assertSame(1, Territorio::count()); } public function test_un_export_senza_le_sezioni_principali_viene_rifiutato(): void { Territorio::create(['numero' => '1', 'attivo' => true]); $esito = $this->importa(''); $this->assertStringContainsString('mancano le sezioni', $esito['error']); $this->assertSame(1, Territorio::count()); } public function test_un_file_malformato_indica_riga_e_motivo(): void { $esito = $this->importa("\n\n\n"); $this->assertStringContainsString('riga', $esito['error']); } // ─── Chi importa non resta fuori ──────────────────────────── /** * Il file può contenere l'account di chi importa con una password vecchia * e senza ruoli: l'amministratore che lo carica non deve perdere né l'una * né gli altri. */ public function test_chi_importa_conserva_password_e_ruolo_di_amministratore(): void { $hashVecchio = Hash::make('password-di-un-anno-fa'); $xml = $this->xmlMinimo( utenti: 'Amministratoreadmin@example.test' . $hashVecchio . '' . 'Altroaltro@example.test' . $hashVecchio . 'assistente', ); $this->assertArrayNotHasKey('error', $this->importa($xml)); $admin = $this->admin->fresh(); $this->assertTrue(Hash::check('password-attuale', $admin->password)); $this->assertTrue($admin->hasRole('amministratore')); // Gli altri account invece prendono i dati del file. $altro = User::where('email', 'altro@example.test')->sole(); $this->assertTrue(Hash::check('password-di-un-anno-fa', $altro->password)); $this->assertTrue($altro->hasRole('assistente')); } // ─── helper ───────────────────────────────────────────────── private function reimporta(?string $xml = null): void { $xml ??= (new XmlExchange())->currentXmlBackup(); $esito = $this->importa($xml); $this->assertArrayNotHasKey('error', $esito, $esito['error'] ?? ''); $this->assertSame([], $esito['issues'], json_encode($esito['issues'])); } private function importa(string $xml): array { return (new XmlExchange())->importXmlFromContent($xml); } private function xmlMinimo(string $utenti = '', string $anni = '', string $assegnazioni = ''): string { return '' . '' . $utenti . '' . 'MarioRossi1' . '11' . '' . $anni . '' . '' . $assegnazioni . '' . ''; } }