Files
Investidor-V2/tests/Feature/TerritoryGeometrySubdivisionTest.php
T

128 lines
7.2 KiB
PHP

<?php
namespace Tests\Feature;
use App\Services\TerritoryGeometry;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Tests\TestCase;
class TerritoryGeometrySubdivisionTest extends TestCase
{
use DatabaseTransactions;
protected function setUp(): void
{
parent::setUp();
$target = DB::selectOne('SELECT current_database() AS name, inet_server_port() AS port');
$this->assertStringEndsWith('_test', $target->name);
$this->assertSame(55441, (int) $target->port);
$this->assertSame('127.0.0.1', config('database.connections.pgsql.host'));
$this->withoutMiddleware(ThrottleRequests::class);
}
private function location(string $type, ?string $parent = null, string $classification = 'public'): string
{
if ($type === 'province' && $parent === null) {
$parent = $this->location('country');
}
$id = (string) Str::uuid();
DB::table('geo_locations')->insert(['id' => $id, 'name' => 'Synthetic '.$type.' '.$id, 'code' => $id,
'location_type' => $type, 'parent_id' => $parent, 'data_classification' => $classification,
'source_system' => 'cartografia-workbook',
'external_id' => '964a187ad32ea553b9e112cd159caa90b900050c42b7329594a75bcd798a96ff:'.$id]);
return $id;
}
private function geometry(string $territory, string $classification = 'public'): string
{
$id = (string) Str::uuid();
DB::insert("INSERT INTO geo_geometries(id,geo_location_id,geometry_type,geom,properties,data_classification) VALUES (?,?,'polygon',ST_GeomFromText('POLYGON((32 -20,33 -20,33 -19,32 -19,32 -20))',4326),?::jsonb,?)",
[$id, $territory, json_encode(['purpose' => 'administrative_boundary', 'authority' => 'Synthetic QA only', 'source_version' => '2026-11-04']), $classification]);
return $id;
}
public function test_optional_children_preserve_default_and_sources_without_grandchildren_or_other_provinces(): void
{
$province = $this->location('province');
$district = $this->location('district', $province);
$post = $this->location('admin_post', $district);
$this->geometry($province);
$this->geometry($district);
$this->geometry($post);
$this->geometry($this->location('district', $this->location('province')));
$url = '/api/v1/investment/territory-geometries?territory_id='.$province;
$this->getJson($url)->assertOk()->assertJsonCount(1, 'areas')->assertJsonPath('child_coverage', null);
$result = $this->getJson($url.'&include_children=1')->assertOk()->assertJsonCount(2, 'areas')
->assertJsonPath('areas.0.territory_id', $province)->assertJsonPath('areas.0.selected_territory', true)
->assertJsonPath('areas.1.territory_id', $district)->assertJsonPath('areas.1.child_territory', true)
->assertJsonPath('areas.1.source_reference', 'Synthetic QA only')->assertJsonPath('areas.1.source_date', '2026-11-04')
->assertJsonPath('child_coverage.registered_count', 1)->assertJsonPath('child_coverage.represented_count', 1)
->assertJsonPath('investment_site', false)->assertJsonPath('truncated', false)->json();
$this->assertFalse($result['areas'][1]['selected_territory']);
$this->getJson('/api/v1/investment/territory-geometries?territory_id='.$district.'&include_children=1')
->assertOk()->assertJsonCount(3, 'areas')->assertJsonPath('child_coverage.location_type', 'admin_post');
}
public function test_coverage_counts_only_accessible_references_and_never_publishes_private_boundaries(): void
{
$province = $this->location('province');
$public = $this->location('district', $province);
$missing = $this->location('district', $province);
$hidden = $this->location('district', $province, 'internal');
$privateGeometry = $this->geometry($public, 'internal');
$this->geometry($hidden);
$before = DB::table('geo_geometries')->where('id', $privateGeometry)->value('data_classification');
$this->getJson('/api/v1/investment/territory-geometries?territory_id='.$province.'&include_children=1')
->assertOk()->assertJsonCount(0, 'areas')->assertJsonPath('selected_geometry_available', false)
->assertJsonPath('child_coverage.registered_count', 2)->assertJsonPath('child_coverage.represented_count', 0);
$internal = app(TerritoryGeometry::class)->context($province, true, true);
$this->assertSame(3, $internal['child_coverage']['registered_count']);
$this->assertSame(2, $internal['child_coverage']['represented_count']);
$this->assertSame($before, DB::table('geo_geometries')->where('id', $privateGeometry)->value('data_classification'));
DB::table('geo_locations')->where('id', $missing)->update(['deleted_at' => now()]);
$this->getJson('/api/v1/investment/territory-geometries?territory_id='.$province.'&include_children=1')
->assertOk()->assertJsonPath('child_coverage.registered_count', 1);
}
public function test_limits_are_explicit_and_selected_boundary_is_retained_ahead_of_children(): void
{
$province = $this->location('province');
$selected = $this->geometry($province);
for ($i = 0; $i < 101; $i++) {
$this->geometry($this->location('district', $province));
}
$this->getJson('/api/v1/investment/territory-geometries?territory_id='.$province.'&include_children=1')
->assertOk()->assertJsonCount(100, 'areas')->assertJsonPath('areas.0.id', $selected)
->assertJsonPath('selected_geometry_available', true)->assertJsonPath('truncated', true)
->assertJsonPath('child_coverage.registered_count', 101)->assertJsonPath('child_coverage.represented_count', 99);
}
public function test_reference_limit_reports_unrepresented_subdivisions_without_claiming_they_do_not_exist(): void
{
$province = $this->location('province');
for ($i = 0; $i < 501; $i++) {
$this->location('district', $province);
}
$this->getJson('/api/v1/investment/territory-geometries?territory_id='.$province.'&include_children=1')
->assertOk()->assertJsonCount(0, 'areas')->assertJsonPath('truncated', true)
->assertJsonPath('child_coverage.registered_count', 501)->assertJsonPath('child_coverage.represented_count', 0);
}
public function test_invalid_child_option_is_rejected_and_locality_has_no_lower_level(): void
{
$province = $this->location('province');
$district = $this->location('district', $province);
$post = $this->location('admin_post', $district);
$locality = $this->location('locality', $post);
$url = '/api/v1/investment/territory-geometries?territory_id='.$locality;
$this->getJson($url.'&include_children=all')->assertUnprocessable();
$this->getJson($url.'&include_children=1')->assertOk()->assertJsonPath('child_coverage.location_type', null)
->assertJsonPath('child_coverage.registered_count', 0)->assertJsonPath('truncated', false);
}
}