seedReferences(); $ids = DB::table('economic_activities')->orderBy('code')->pluck('id', 'code')->all(); $this->seedReferences(); $this->assertCount(6, $ids); $this->assertSame($ids, DB::table('economic_activities')->orderBy('code')->pluck('id', 'code')->all()); $this->assertSame(6, DB::table('economic_activities')->count()); $this->assertSame(3, DB::table('reference_catalog_versions')->count()); $this->assertDatabaseHas('reference_catalog_versions', [ 'catalog_code' => 'economic-activities', 'version_no' => 1, 'locale' => 'pt-MZ', 'status' => 'published', ]); } public function test_catalog_search_pagination_and_explicit_version(): void { $this->seedReferences(); $this->getJson('/api/v1/catalogs/economic-activities?q=turismo&per_page=1') ->assertOk()->assertJsonPath('meta.version', 1)->assertJsonPath('meta.locale', 'pt-MZ') ->assertJsonPath('meta.total', 1)->assertJsonPath('data.0.code', 'turismo') ->assertJsonPath('data.0.label', DB::table('sectors')->where('slug', 'turismo')->value('name')); $this->getJson('/api/v1/catalogs/economic-activities?version=1&per_page=2&page=2') ->assertOk()->assertJsonPath('meta.current_page', 2)->assertJsonPath('meta.total', 6) ->assertJsonCount(2, 'data')->assertJsonStructure(['links' => ['next', 'previous']]); $this->getJson('/api/v1/catalogs/economic-activities?version=999')->assertNotFound(); } public function test_jurisdiction_dropdown_requires_the_immediate_parent_and_filters_children(): void { $this->seedReferences(); $country = DB::table('geo_locations')->where('location_type', 'country')->where('source_system', 'cartografia-workbook')->value('id'); $province = DB::table('geo_locations')->where('location_type', 'province')->where('source_system', 'cartografia-workbook')->orderBy('name')->first(); $this->getJson('/api/v1/catalogs/jurisdictions?type=province&parent_id='.$country.'&per_page=100') ->assertOk()->assertJsonPath('meta.version', 3)->assertJsonPath('meta.locale', 'pt-MZ')->assertJsonPath('meta.total', 11); $district = DB::table('geo_locations')->where('parent_id', $province->id)->where('location_type', 'district')->first(); $this->getJson('/api/v1/catalogs/jurisdictions?type=district&parent_id='.$province->id.'&q='.$district->name) ->assertOk()->assertJsonPath('data.0.parent_id', $province->id)->assertJsonPath('data.0.name', $district->name)->assertJsonPath('meta.total', 1); $this->getJson('/api/v1/catalogs/jurisdictions?type=district')->assertUnprocessable()->assertJsonValidationErrors('parent_id'); $this->getJson('/api/v1/catalogs/jurisdictions?type=district&parent_id='.$country)->assertUnprocessable()->assertJsonValidationErrors('parent_id'); } public function test_economic_activity_dropdown_can_be_filtered_by_sector(): void { $this->seedReferences(); $sectorId = DB::table('sectors')->where('slug', 'turismo')->value('id'); $this->getJson('/api/v1/catalogs/economic-activities?sector_id='.$sectorId) ->assertOk()->assertJsonPath('meta.total', 1)->assertJsonPath('data.0.code', 'turismo'); $this->getJson('/api/v1/catalogs/economic-activities?sector_id=999999999') ->assertUnprocessable()->assertJsonValidationErrors('sector_id'); } public function test_authorities_are_not_fabricated_before_a_source_is_approved(): void { $this->seedReferences(); $this->getJson('/api/v1/catalogs/authorities')->assertOk()->assertJsonPath('data', []) ->assertJsonPath('meta.status', 'not_published')->assertJsonPath('meta.version', null); } public function test_published_authority_catalog_only_returns_public_organizations(): void { $this->seedReferences(); $versionId = DB::table('reference_catalog_versions')->where('catalog_code', 'authorities')->value('id'); DB::table('reference_catalog_versions')->where('id', $versionId)->update(['status' => 'published']); foreach ([['Public authority', 'public'], ['Internal authority', 'internal']] as [$name, $classification]) { $organizationId = (string) Str::uuid(); DB::table('organizations')->insert(['id' => $organizationId, 'name' => $name, 'organization_type' => 'public', 'data_classification' => $classification, 'created_at' => now(), 'updated_at' => now()]); DB::table('authorities')->insert(['id' => (string) Str::uuid(), 'catalog_version_id' => $versionId, 'organization_id' => $organizationId, 'code' => strtolower(str_replace(' ', '-', $name)), 'authority_type' => 'registry', 'label_pt_mz' => $name, 'source_reference' => 'Synthetic approved source', 'version_no' => 1, 'valid_from' => today()->toDateString(), 'status' => 'published', 'created_at' => now(), 'updated_at' => now()]); } $this->getJson('/api/v1/catalogs/authorities')->assertOk()->assertJsonPath('meta.version', 1) ->assertJsonPath('meta.total', 1)->assertJsonPath('data.0.name', 'Public authority'); } public function test_foreign_keys_and_catalog_migration_rollback_guard(): void { $this->seedReferences(); $migration = require database_path('migrations/2026_10_01_000100_create_reference_catalogs.php'); try { $migration->down(); $this->fail('Rollback must preserve seeded economic activity references.'); } catch (RuntimeException $exception) { $this->assertStringContainsString('Economic activities exist', $exception->getMessage()); } $activity = DB::table('economic_activities')->first(); try { DB::table('economic_activities')->insert([ 'id' => (string) Str::uuid(), 'catalog_version_id' => $activity->catalog_version_id, 'sector_id' => 999999999, 'code' => 'invalid-fk', 'label_pt_mz' => 'Inválido', 'version_no' => 1, 'valid_from' => '2026-10-01', 'status' => 'published', 'created_at' => now(), 'updated_at' => now(), ]); $this->fail('The database accepted an unknown sector reference.'); } catch (QueryException $exception) { $this->assertSame('23503', $exception->errorInfo[0]); } } public function test_published_catalog_values_are_immutable(): void { $this->seedReferences(); $activity = DB::table('economic_activities')->where('code', 'energia')->first(); try { DB::table('economic_activities')->where('id', $activity->id)->update(['label_pt_mz' => 'Rótulo adulterado']); $this->fail('Published catalog values must be immutable.'); } catch (QueryException $exception) { $this->assertSame('42501', $exception->errorInfo[0]); } } public function test_empty_catalog_migration_rolls_back_and_reapplies(): void { $migration = require database_path('migrations/2026_10_01_000100_create_reference_catalogs.php'); $migration->down(); $this->assertFalse(Schema::hasTable('economic_activities')); $this->assertFalse(Schema::hasTable('authorities')); $this->assertFalse(Schema::hasTable('reference_catalog_versions')); $migration->up(); $this->assertTrue(Schema::hasTable('economic_activities')); $this->assertTrue(Schema::hasTable('authorities')); $this->assertTrue(Schema::hasTable('reference_catalog_versions')); } private function seedReferences(): void { $this->seed(SectorSeeder::class); $this->seed(TerritoryReferenceSeeder::class); $this->seed(ReferenceCatalogSeeder::class); } }