app->bind(MalwareScanner::class, fn () => new class implements MalwareScanner { public function scan(string $path, int $fileSizeBytes, string $storageRoot): array { return ['result' => 'clean', 'reason_code' => null, 'engine' => 'ClamAV-Test-Double', 'engine_version' => 'fixture', 'signatures_at' => new \DateTimeImmutable('2026-10-06T00:00:00Z'), 'duration_ms' => 1, 'detail' => null]; } public function health(): array { return ['available' => true, 'engine' => 'ClamAV-Test-Double', 'engine_version' => 'fixture', 'signatures_at' => new \DateTimeImmutable('2026-10-06T00:00:00Z'), 'signature_age_hours' => 0.0, 'reason_code' => null]; } }); } public function test_preview_has_no_storage_or_database_side_effects(): void { Storage::fake('local'); $this->artisan('documents:import-legal-source-archive')->assertSuccessful(); $this->assertDatabaseCount('documents', 0); $this->assertDatabaseCount('portal_resources', 0); $this->assertDatabaseCount('portal_resource_links', 0); $this->assertSame([], Storage::disk('local')->allFiles('portal-documents')); } public function test_import_creates_private_unapproved_records_and_reimport_does_not_duplicate(): void { Storage::fake('local'); $this->artisan('documents:import-legal-source-archive', ['--apply' => true])->assertSuccessful(); $expectedResources = file_exists(storage_path('app/private/geo-ine-source-20260928/original.pdf')) ? 4 : 3; $this->assertDatabaseCount('documents', $expectedResources); $this->assertDatabaseCount('portal_resources', $expectedResources); $this->assertDatabaseCount('portal_resource_links', 19); $this->assertSame(8, DB::table('portal_resource_links')->where('target_type', 'requirement')->count()); $this->assertDatabaseCount('portal_resource_revisions', $expectedResources); $this->assertCount($expectedResources, Storage::disk('local')->allFiles('portal-documents')); $this->assertSame($expectedResources, DB::table('documents')->where('source_system', 'legal-source-archive') ->where('status', 'active')->where('data_classification', 'internal')->where('rights_status', 'unconfirmed') ->where('malware_scan_status', 'clean')->whereColumn('sha256', 'malware_scanned_sha256')->count()); $this->assertDatabaseHas('portal_resources', ['published' => false, 'approved_by' => null, 'rights_status' => 'unconfirmed']); $this->assertDatabaseHas('portal_resource_links', [ 'target_type' => 'module', 'target_key' => 'simulator', 'applicability' => 'evidence', ]); $this->assertDatabaseHas('portal_resources', [ 'document_number' => 'Lei n.º 22/2022', 'source_confirmation' => 'official_confirmed', 'legal_status' => 'amended', ]); $this->assertDatabaseHas('portal_resources', [ 'document_number' => 'BR n.º 89/2017', 'source_confirmation' => 'identified', 'legal_status' => 'unknown', ]); $this->assertDatabaseHas('portal_resource_links', [ 'target_type' => 'requirement', 'target_key' => 'fiscal.iva.lei_22_2022', 'review_status' => 'confirmed', ]); $this->assertDatabaseHas('portal_resource_links', [ 'target_type' => 'theme', 'target_key' => 'iva', 'review_status' => 'pending', ]); $this->assertDatabaseHas('portal_resource_links', [ 'target_type' => 'requirement', 'target_key' => 'fiscal.iva.lei_13_2016_rectification_2017', 'review_status' => 'pending', ]); if ($expectedResources === 4) { $this->assertDatabaseHas('portal_resources', [ 'document_number' => 'Codificador DPA 2012', 'document_type' => 'reference_data', 'legislation' => false, 'source_confirmation' => 'official_confirmed', 'rights_status' => 'unconfirmed', 'published' => false, ]); } $this->get('/documentos')->assertInertia(fn (Assert $page) => $page->has('resources.data', 0)); $this->get('/documentos/'.DB::table('portal_resources')->value('id').'/download')->assertNotFound(); $this->artisan('documents:import-legal-source-archive', ['--apply' => true])->assertSuccessful(); $this->assertDatabaseCount('documents', $expectedResources); $this->assertDatabaseCount('portal_resources', $expectedResources); $this->assertDatabaseCount('portal_resource_links', 19); $this->assertSame(8, DB::table('portal_resource_links')->where('target_type', 'requirement')->count()); $this->assertDatabaseCount('portal_resource_revisions', $expectedResources); $this->assertCount($expectedResources, Storage::disk('local')->allFiles('portal-documents')); $br248 = DB::table('portal_resources')->where('document_number', 'BR n.º 248/2025, Suplemento n.º 1')->firstOrFail(); DB::table('portal_resource_links')->where('resource_id', $br248->id)->where('target_type', 'requirement') ->where('target_key', 'fiscal.irpc.lei_12_2025')->delete(); $this->artisan('documents:import-legal-source-archive', ['--apply' => true])->assertSuccessful(); $this->assertDatabaseHas('portal_resource_links', ['resource_id' => $br248->id, 'target_type' => 'requirement', 'target_key' => 'fiscal.irpc.lei_12_2025', 'review_status' => 'confirmed']); $this->assertDatabaseCount('portal_resource_links', 19); $this->assertDatabaseCount('portal_resource_revisions', $expectedResources + 1); } }