122 lines
7.0 KiB
PHP
122 lines
7.0 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\InvestmentZone;
|
|
use App\Services\InvestmentGeography;
|
|
use App\Services\InvestmentMapIndicators;
|
|
use App\Services\InvestmentZones;
|
|
use App\Support\IsolatedQaDatabase;
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
use Tests\TestCase;
|
|
|
|
class InvestmentMapIndicatorsTest extends TestCase
|
|
{
|
|
use DatabaseTransactions;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->assertTrue(IsolatedQaDatabase::allowsSchemaChanges());
|
|
}
|
|
|
|
private function observation(string $indicator = 'employment', ?string $value = '0'): array
|
|
{
|
|
return ['id' => (string) Str::uuid(), 'label' => 'SYNTHETIC QA source observation', 'indicator' => $indicator,
|
|
'value' => $value, 'unit' => $indicator === 'employment' ? 'pessoas' : 'toneladas', 'period_start' => '2025-01-01', 'period_end' => '2025-12-31',
|
|
'scope' => 'Synthetic park only', 'population' => 'Synthetic declared establishments', 'methodology' => 'Synthetic documentary register',
|
|
'source_reference' => 'SYNTHETIC QA only, not official statistics', 'source_date' => '2026-01-15', 'knowledge' => 'documented'];
|
|
}
|
|
|
|
private function zone(string $prefix, array $rows, ?string $territory = null): InvestmentZone
|
|
{
|
|
$base = app(InvestmentZones::class)->visible()->where('category', 'industrial_park')->firstOrFail();
|
|
$zone = $base->replicate();
|
|
$zone->forceFill(['code' => 'QA-'.Str::uuid(), 'name' => $prefix.' synthetic park '.Str::uuid(), 'primary_territory_id' => $territory,
|
|
'editorial_draft' => 'PRIVATE-DRAFT-NOT-TO-BE-DECRYPTED',
|
|
'operational_details' => ['schema_version' => 1, 'public' => ['integral' => ['observations' => $rows]], 'private_ciphertext' => 'PRIVATE-QUANTITATIVE-SOURCE']])->save();
|
|
|
|
return $zone;
|
|
}
|
|
|
|
public function test_public_values_keep_zero_decimal_precision_units_sources_and_incomplete_metadata_without_private_fields(): void
|
|
{
|
|
$prefix = 'QUANT-'.Str::uuid();
|
|
$rows = [$this->observation(), $this->observation('production', '12.3400'),
|
|
[...$this->observation('investment', '100'), 'unit' => null], [...$this->observation(), 'knowledge' => 'unknown', 'value' => '999'],
|
|
[...$this->observation('exports', '25.50'), 'knowledge' => 'disputed', 'private_note' => 'PRIVATE-NOTE']];
|
|
$zone = $this->zone($prefix, $rows);
|
|
$before = $zone->fresh()->getRawOriginal('operational_details');
|
|
$r = $this->getJson('/api/v1/investment/map?q='.$prefix)->assertOk()->assertJsonPath('quantitative_context.state', 'available')
|
|
->assertJsonCount(5, 'quantitative_context.records')->assertJsonPath('quantitative_context.records.0.value', '0')
|
|
->assertJsonPath('quantitative_context.records.1.value', '12.3400')->assertJsonPath('quantitative_context.records.0.unit', 'pessoas')
|
|
->assertJsonPath('quantitative_context.records.2.missing_metadata', ['unit'])->assertJsonPath('quantitative_context.records.3.value', null)
|
|
->assertJsonPath('quantitative_context.records.4.knowledge', 'disputed')->assertJsonPath('quantitative_context.records.0.source_date', '2026-01-15');
|
|
$this->assertStringNotContainsString('PRIVATE-', $r->getContent());
|
|
$this->assertSame($before, $zone->fresh()->getRawOriginal('operational_details'));
|
|
$this->assertArrayNotHasKey('total', $r->json('quantitative_context'));
|
|
}
|
|
|
|
public function test_numeric_json_decimals_are_read_exactly_from_the_same_public_snapshot(): void
|
|
{
|
|
$prefix = 'QUANT-'.Str::uuid();
|
|
$zone = $this->zone($prefix, [$this->observation('production', '1')]);
|
|
DB::update("UPDATE investment_zones SET operational_details=jsonb_set(operational_details, '{public,integral,observations,0,value}', '1234567890123.456789'::jsonb) WHERE id=?", [$zone->id]);
|
|
$this->getJson('/api/v1/investment/map?q='.$prefix)->assertOk()
|
|
->assertJsonPath('quantitative_context.records.0.value', '1234567890123.456789');
|
|
}
|
|
|
|
public function test_draft_and_unselected_private_observations_remain_unavailable_and_specific_opportunity_filters_are_explicit(): void
|
|
{
|
|
$prefix = 'QUANT-'.Str::uuid();
|
|
$draft = $this->zone($prefix, [$this->observation()]);
|
|
$draft->forceFill(['publication_status' => 'draft'])->save();
|
|
$private = $this->zone($prefix, []);
|
|
$private->forceFill(['operational_details' => ['private_ciphertext' => 'PRIVATE-SOURCE-WITH-QUANTITY']])->save();
|
|
$this->getJson('/api/v1/investment/map?q='.$prefix)->assertOk()->assertJsonCount(0, 'quantitative_context.records');
|
|
$this->getJson('/api/v1/investment/map?q='.$prefix.'§or=agronegocio')->assertOk()
|
|
->assertJsonPath('quantitative_context.state', 'not_included')->assertJsonCount(0, 'quantitative_context.records');
|
|
}
|
|
|
|
public function test_quantitative_context_uses_existing_province_and_district_scope_without_moving_any_source(): void
|
|
{
|
|
$prefix = 'QUANT-'.Str::uuid();
|
|
$districts = app(InvestmentGeography::class)->publicReferences()->where('location_type', 'district')->get(['id', 'parent_id']);
|
|
$district = $districts->first();
|
|
$other = $districts->first(fn ($row) => $row->parent_id !== $district->parent_id);
|
|
$zone = $this->zone($prefix, [$this->observation()], $district->id);
|
|
$this->zone($prefix, [$this->observation('production', '9')], $other->id);
|
|
foreach ([['province_id' => $district->parent_id], ['province_id' => $district->parent_id, 'district_id' => $district->id]] as $filters) {
|
|
$this->getJson('/api/v1/investment/map?'.http_build_query(['q' => $prefix, ...$filters]))->assertOk()
|
|
->assertJsonCount(1, 'quantitative_context.records')->assertJsonPath('quantitative_context.records.0.zone_id', $zone->id);
|
|
}
|
|
$this->assertSame($district->id, $zone->fresh()->primary_territory_id);
|
|
}
|
|
|
|
public function test_observation_limit_is_explicit_and_values_from_other_indicators_are_not_reinterpreted(): void
|
|
{
|
|
$rows = [];
|
|
for ($i = 0; $i < 201; $i++) {
|
|
$rows[] = $this->observation('production', (string) $i);
|
|
}
|
|
$rows[] = $this->observation('emissions', '42');
|
|
$zone = $this->zone('QUANT-'.Str::uuid(), $rows);
|
|
$result = app(InvestmentMapIndicators::class)->forZones(collect([$zone]));
|
|
$this->assertCount(200, $result['records']);
|
|
$this->assertTrue($result['truncated']);
|
|
$this->assertSame('economic_potential', $result['records'][0]['theme']);
|
|
}
|
|
|
|
public function test_zone_limit_does_not_claim_complete_territorial_coverage(): void
|
|
{
|
|
$prefix = 'QUANT-'.Str::uuid();
|
|
for ($i = 0; $i < 31; $i++) {
|
|
$this->zone($prefix, []);
|
|
}
|
|
$this->getJson('/api/v1/investment/map?q='.$prefix)->assertOk()->assertJsonPath('quantitative_context.zones_consulted', 30)
|
|
->assertJsonPath('quantitative_context.truncated', true)->assertJsonCount(30, 'territorial_context');
|
|
}
|
|
}
|