62 lines
3.6 KiB
PHP
62 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit;
|
|
|
|
use App\Services\Ai\InvestorGuidanceRules;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
class InvestorGuidanceRulesTest extends TestCase
|
|
{
|
|
public function test_declared_quantities_require_common_scope_and_never_invent_missing_values(): void
|
|
{
|
|
$rules = new InvestorGuidanceRules;
|
|
$missing = $rules->evaluate(['demand_quantity' => '100', 'capacity_quantity' => '50']);
|
|
$this->assertContains('demand_quantity_comparison_incomplete', array_column($missing[1]['risks'], 'code'));
|
|
$facts = ['demand_quantity' => '100', 'capacity_quantity' => '50', 'quantity_unit' => 'toneladas', 'quantity_period' => 'ano',
|
|
'resources_required' => '12', 'resources_available' => '0', 'resource_unit' => 'pessoas',
|
|
'funding_required' => '100.50', 'funding_committed' => '100.49', 'funding_currency' => 'MZN',
|
|
'expected_start_date' => '2026-12-01', 'funding_ready_date' => '2027-01-01', 'completion_date' => '2026-11-01'];
|
|
$phases = $rules->evaluate($facts);
|
|
foreach ([1 => 'demand_quantity_declared_gap', 3 => 'resources_required_declared_gap', 4 => 'funding_required_declared_gap'] as $i => $code) {
|
|
$this->assertContains($code, array_column($phases[$i]['risks'], 'code'));
|
|
foreach ($phases[$i]['risks'] as $risk) {
|
|
$this->assertFalse($risk['restriction']);
|
|
}
|
|
}
|
|
$this->assertCount(2, $phases[5]['risks']);
|
|
$facts['funding_committed'] = '100.50';
|
|
$this->assertNotContains('funding_required_declared_gap', array_column($rules->evaluate($facts)[4]['risks'], 'code'));
|
|
}
|
|
|
|
public function test_missing_declared_and_attached_information_are_not_verified(): void
|
|
{
|
|
$rules = new InvestorGuidanceRules;
|
|
$this->assertSame('absent', $rules->evaluate([])[2]['evidence'][0]['state']);
|
|
$declared = $rules->evaluate(['location_evidence' => 'Declaração QA']);
|
|
$this->assertSame('investor_declared_not_verified', $declared[2]['evidence'][0]['state']);
|
|
$attached = $rules->evaluate([], ['location_evidence' => ['state' => 'attached_unchecked', 'documents' => []]]);
|
|
$this->assertSame('attached_unchecked', $attached[2]['evidence'][0]['state']);
|
|
$this->assertNotEmpty($attached[2]['risks']);
|
|
}
|
|
|
|
public function test_scoped_internal_verification_removes_only_the_corresponding_pending_alert(): void
|
|
{
|
|
$evidence = ['location_evidence' => ['state' => 'internally_verified', 'documents' => [['review' => ['author' => 'Verificador QA', 'date' => '2026-10-08', 'scope' => 'Acesso descrito no documento QA']]]]];
|
|
$phases = (new InvestorGuidanceRules)->evaluate([], $evidence);
|
|
$this->assertSame([], $phases[2]['risks']);
|
|
$this->assertNotEmpty($phases[3]['risks']);
|
|
$this->assertSame($evidence['location_evidence']['documents'], $phases[2]['evidence'][0]['documents']);
|
|
$this->assertStringContainsString('não aprova', $phases[2]['recommendations'][0]['limitations'][0]);
|
|
}
|
|
|
|
public function test_contradictions_expiration_and_replacement_are_specific_non_blocking_alerts(): void
|
|
{
|
|
foreach (['contradiction', 'expired', 'superseded'] as $state) {
|
|
$phase = (new InvestorGuidanceRules)->evaluate([], ['market_evidence' => ['state' => $state, 'documents' => []]])[1];
|
|
$this->assertSame('market_evidence_'.$state, $phase['risks'][0]['code']);
|
|
$this->assertFalse($phase['risks'][0]['restriction']);
|
|
$this->assertSame($state === 'contradiction' ? 'documented_contradiction' : 'insufficient_information', $phase['risks'][0]['classification']);
|
|
}
|
|
}
|
|
}
|