50d6da5931
Глубокое изучение строит отпечаток на КАЖДЫЙ элемент холдинга - имя элемента плюс его первый сайт - и сводит телефоны со всех. Без элементов - как раньше. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
85 lines
3.1 KiB
PHP
85 lines
3.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Services\Autopodbor\Agent\Dto\StudyCompetitorRequest;
|
|
use App\Services\Autopodbor\Agent\Fetch\FetchedSite;
|
|
use App\Services\Autopodbor\Agent\Fetch\Fetcher;
|
|
use App\Services\Autopodbor\Agent\FakeCompetitorAgent;
|
|
use App\Services\Autopodbor\Agent\RealCompetitorAgent;
|
|
use App\Services\Autopodbor\Agent\Study\Fingerprint;
|
|
use App\Services\Autopodbor\Agent\Study\SourceCollector;
|
|
|
|
/** Фейк-собиратель: запоминает отпечатки и отдаёт по строке-телефону на каждый. */
|
|
class FakeStudyCollector implements SourceCollector
|
|
{
|
|
/** @var list<Fingerprint> */
|
|
public array $seen = [];
|
|
|
|
public function collect(Fingerprint $fp): array
|
|
{
|
|
$this->seen[] = $fp;
|
|
|
|
return [[
|
|
'signal_type' => 'call', 'identifier' => 'phone-'.$fp->name,
|
|
'phone_kind' => 'real', 'phone_type' => 'city',
|
|
'provenance_url' => null, 'provenance_label' => $fp->name,
|
|
'where_found' => [], 'office' => null, 'confirmations' => 1,
|
|
]];
|
|
}
|
|
}
|
|
|
|
/** Фетчер-заглушка: в глубоком пути не вызывается. */
|
|
class NullStudyFetcher implements Fetcher
|
|
{
|
|
public function site(string $url): FetchedSite
|
|
{
|
|
throw new \LogicException('not used in deep path');
|
|
}
|
|
|
|
public function directory(string $url): array
|
|
{
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function studyAgent(FakeStudyCollector $c): RealCompetitorAgent
|
|
{
|
|
return new RealCompetitorAgent(new NullStudyFetcher, new FakeCompetitorAgent, deep: $c);
|
|
}
|
|
|
|
it('глубокое изучение строит отпечаток на КАЖДЫЙ элемент и сводит строки', function () {
|
|
config(['autopodbor.deep_study' => true]);
|
|
$c = new FakeStudyCollector;
|
|
|
|
$res = studyAgent($c)->studyCompetitor(new StudyCompetitorRequest(
|
|
competitor: [
|
|
'name' => 'Сибиряк',
|
|
'is_federal' => false,
|
|
'elements' => [
|
|
['name' => 'Нанжуль', 'sites' => ['nanzhul.ru'], 'cards' => []],
|
|
['name' => 'Плодово', 'sites' => ['plodovo.ru'], 'cards' => []],
|
|
],
|
|
],
|
|
regionCode: 24,
|
|
));
|
|
|
|
expect(array_map(fn (Fingerprint $fp) => $fp->name, $c->seen))->toBe(['Нанжуль', 'Плодово'])
|
|
->and(array_map(fn (Fingerprint $fp) => $fp->seedDomain, $c->seen))->toBe(['nanzhul.ru', 'plodovo.ru'])
|
|
->and(collect($res->sources)->pluck('identifier')->all())->toBe(['phone-Нанжуль', 'phone-Плодово']);
|
|
});
|
|
|
|
it('без элементов — один отпечаток из имени+сайта (обратная совместимость)', function () {
|
|
config(['autopodbor.deep_study' => true]);
|
|
$c = new FakeStudyCollector;
|
|
|
|
studyAgent($c)->studyCompetitor(new StudyCompetitorRequest(
|
|
competitor: ['name' => 'Одиночка', 'site_url' => 'one.ru', 'is_federal' => false],
|
|
regionCode: 24,
|
|
));
|
|
|
|
expect($c->seen)->toHaveCount(1)
|
|
->and($c->seen[0]->name)->toBe('Одиночка')
|
|
->and($c->seen[0]->seedDomain)->toBe('one.ru');
|
|
});
|