164 lines
8.3 KiB
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=energia&per_page=1')
|
|
->assertOk()->assertJsonPath('meta.version', 1)->assertJsonPath('meta.locale', 'pt-MZ')
|
|
->assertJsonPath('meta.total', 1)->assertJsonPath('data.0.code', 'energia')
|
|
->assertJsonPath('data.0.label', DB::table('sectors')->where('slug', 'energia')->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', 'energia')->value('id');
|
|
|
|
$this->getJson('/api/v1/catalogs/economic-activities?sector_id='.$sectorId)
|
|
->assertOk()->assertJsonPath('meta.total', 1)->assertJsonPath('data.0.code', 'energia');
|
|
$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);
|
|
}
|
|
}
|