Files
Investidor-V2/tests/Feature/ReferenceCatalogTest.php

164 lines
8.3 KiB
PHP

<?php
namespace Tests\Feature;
use Database\Seeders\ReferenceCatalogSeeder;
use Database\Seeders\SectorSeeder;
use Database\Seeders\TerritoryReferenceSeeder;
use Illuminate\Database\QueryException;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;
use RuntimeException;
use Tests\TestCase;
class ReferenceCatalogTest extends TestCase
{
use RefreshDatabase;
public function test_reference_seeds_are_repeatable_and_activity_codes_are_stable(): void
{
$this->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);
}
}