withoutVite(); $db = DB::selectOne('select current_database() as name, inet_server_port() as port'); $this->assertSame('investor_intent_20261115_test', $db->name); $this->assertSame(55441, (int) $db->port); $this->editor = User::factory()->create(); config(['portal.managers' => [$this->editor->email]]); $parent = null; foreach (['country', 'province', 'district'] as $type) { $id = (string) Str::uuid(); DB::table('geo_locations')->insert(['id' => $id, 'parent_id' => $parent, 'name' => 'SYNTHETIC '.$type, 'code' => $id, 'location_type' => $type, 'source_system' => 'cartografia-workbook', 'data_classification' => 'public', 'external_id' => '964a187ad32ea553b9e112cd159caa90b900050c42b7329594a75bcd798a96ff:QA:'.$id]); $this->geo[$type] = $id; $parent = $id; } $this->sector = Sector::create(['slug' => 'synthetic-funding-qa', 'name' => 'SYNTHETIC sector', 'is_active' => true, 'published_at' => now()])->id; } private function publish(string $code, string $kind = 'institution', array $overrides = []): string { $source = ['source_url' => 'https://example.invalid/synthetic-qa', 'source_reference' => 'SYNTHETIC QA ONLY', 'checked_on' => today()->toDateString()]; $draft = ['title' => 'SYNTHETIC '.$code, 'kind' => $kind, 'manager_name' => 'SYNTHETIC manager', 'summary' => 'Synthetic isolated record, not real content.', 'source_url' => $source['source_url'], 'source_reference' => $source['source_reference'], 'source_checked_on' => $source['checked_on'], 'source_status' => 'identified', 'coverage' => 'national', 'sectors_scope' => 'all', 'funding_needs' => ['investment'], 'windows' => []]; if ($kind === 'institution') $draft += ['institution_key' => $code, 'institution_nature' => 'bank', 'institution_categories' => ['banking'], 'institution_types' => ['commercial_bank'], 'institution_status' => 'reported', 'locations' => [['role' => 'headquarters', 'label' => 'Synthetic headquarters', 'territory_id' => $this->geo['district'], 'evidence_status' => 'reported', ...$source]], 'products' => [['code' => 'investment', 'title' => 'Synthetic investment product', 'needs' => ['investment'], 'coverage' => 'national', 'availability' => 'documented', ...$source]]]; $service = app(FundingProgrammes::class); $id = $service->save($this->editor, null, ['version' => 0, 'code' => $code, 'reason' => 'Synthetic QA fixture', 'draft' => array_replace($draft, $overrides)]); $plan = $service->preview($this->editor, $id); $service->publish($this->editor, $id, ['version' => $plan['version'], 'hash' => $plan['hash'], 'confirm' => true, 'reason' => 'Synthetic QA only, rolled back']); return $id; } public function test_bank_filters_apply_to_the_shared_query_and_never_return_brokers_or_microinsurers(): void { $bank = $this->publish('qa-bank'); $this->publish('qa-broker', overrides: ['institution_categories' => ['intermediation'], 'institution_types' => ['broker']]); $this->publish('qa-microinsurance', overrides: ['institution_categories' => ['insurance'], 'institution_types' => ['microinsurer']]); $fund = $this->publish('qa-fund', 'fund'); $service = app(FundingProgrammes::class); $filters = ['category' => 'banking', 'institution_type' => 'commercial_bank', 'kind' => 'institution', 'certainty' => 'documented', 'location_mode' => 'physical', 'territory' => $this->geo['district'], 'sector' => $this->sector, 'need' => 'investment']; $this->assertSame([$bank], $service->catalogueQuery($filters)->pluck('p.id')->all()); $this->assertSame([$fund], $service->catalogueQuery(['kind' => 'fund'])->pluck('p.id')->all()); $this->assertSame(0, $service->catalogueQuery(['q' => 'no-such-record'])->count()); $this->assertSame(0, $service->catalogueQuery(['category' => 'banking', 'institution_type' => 'investment_bank'])->count(), 'A valid combination without records is an empty result, not an invalid combination.'); $this->get('/fundos?'.http_build_query($filters))->assertOk()->assertInertia(fn ($page) => $page->has('items.data', 1)->where('items.data.0.id', $bank)->where('territorySelection.0.id', $this->geo['province'])->where('territorySelection.1.id', $this->geo['district'])); $returnFilters = [...$filters, 'q' => 'qa', 'state' => 'closed', 'kind' => 'institution', 'include_historical' => '0', 'province_id' => $this->geo['province'], 'district_id' => $this->geo['district'], 'page' => '2']; $this->get('/fundos/'.$bank.'?'.http_build_query($returnFilters))->assertOk()->assertInertia(function ($page) use ($returnFilters) { foreach ($returnFilters as $key => $value) $page->where('selection.'.$key, (string) $value); }); $this->getJson('/api/v1/investment/territory-options?type=district')->assertOk()->assertJsonCount(0, 'data'); $this->getJson('/api/v1/investment/territory-options?type=district&parent_id='.$this->geo['province'])->assertOk()->assertJsonCount(1, 'data'); } public function test_physical_search_defaults_to_documented_presence_but_preserves_explicit_unknown_choice(): void { $local = $this->publish('qa-local'); $this->publish('qa-unlocated', overrides: ['locations' => []]); $filters = ['q' => 'SYNTHETIC qa-', 'location_mode' => 'physical', 'territory' => $this->geo['province']]; $this->get('/fundos?'.http_build_query($filters))->assertOk()->assertInertia(fn ($page) => $page ->where('filters.certainty', 'documented')->has('items.data', 1)->where('items.data.0.id', $local)); $this->get('/fundos?'.http_build_query([...$filters, 'certainty' => 'include_unknown']))->assertOk()->assertInertia(fn ($page) => $page ->where('filters.certainty', 'include_unknown')->has('items.data', 2)); } public function test_contradictory_type_or_record_kind_and_incomplete_hierarchy_are_rejected(): void { foreach ([['category' => 'banking', 'institution_type' => 'broker'], ['category' => 'banking', 'institution_type' => 'commercial_bank', 'kind' => 'fund', 'location_mode' => 'physical'], ['district_id' => $this->geo['district']]] as $filters) { try { app(FundingProgrammes::class)->catalogueQuery($filters)->count(); $this->fail('Contradictory criteria must not silently broaden a query.'); } catch (ValidationException $error) { $this->assertNotEmpty($error->errors()); } $this->getJson('/fundos?'.http_build_query($filters))->assertUnprocessable(); $this->get('/fundos?'.http_build_query($filters))->assertOk()->assertInertia(fn ($page) => $page->has('criteriaErrors')->has('items.data', 0)); } } public function test_unknown_scope_is_not_a_documented_match_and_physical_presence_does_not_prove_coverage(): void { $this->publish('qa-unknown', overrides: ['sectors_scope' => 'unknown', 'products' => []]); $service = app(FundingProgrammes::class); $this->assertSame(0, $service->catalogueQuery(['need' => 'investment', 'certainty' => 'documented'])->count()); $this->assertSame(0, $service->catalogueQuery(['sector' => $this->sector, 'certainty' => 'documented'])->count()); $this->assertSame(1, $service->catalogueQuery(['territory' => $this->geo['district'], 'location_mode' => 'physical', 'certainty' => 'documented'])->count()); $this->assertSame(0, $service->catalogueQuery(['territory' => $this->geo['district'], 'location_mode' => 'coverage', 'certainty' => 'documented'])->count()); $this->assertSame(1, $service->catalogueQuery(['need' => 'investment', 'certainty' => 'include_unknown'])->count()); $this->assertSame(0, $service->catalogueQuery(['state' => 'closed'])->count(), 'An institution without a window is not a closed funding window.'); } public function test_window_state_and_scope_are_matched_on_the_same_window_without_inventing_a_local_window(): void { $source = ['source_url' => 'https://example.invalid/synthetic-qa', 'source_reference' => 'Synthetic window', 'checked_on' => today()->toDateString()]; $id = $this->publish('qa-closed-window', overrides: ['windows' => [['code' => 'closed', 'title' => 'Synthetic closed window', 'mode' => 'closed', 'coverage' => 'unknown', ...$source]]]); $service = app(FundingProgrammes::class); $criteria = ['territory' => $this->geo['district'], 'certainty' => 'documented', 'state' => 'closed', 'location_mode' => 'coverage']; $this->assertSame(0, $service->catalogueQuery($criteria)->count()); $this->assertSame([$id], $service->catalogueQuery([...$criteria, 'certainty' => 'include_unknown'])->pluck('p.id')->all()); $this->assertSame([$id], $service->catalogueQuery([...$criteria, 'location_mode' => 'physical'])->pluck('p.id')->all()); $this->assertSame(0, $service->catalogueQuery([...$criteria, 'state' => 'open'])->count()); } }