$map */
public function __construct(private array $map) {}
public function html(string $url): string
{
return $this->map[$url] ?? '';
}
};
}
it('по одному личному номеру находит карточку проекта: её сайт и телефон', function () {
$search = 'https://2gis.ru/krasnoyarsk/search/73912273531';
$firm = 'https://2gis.ru/krasnoyarsk/firm/111';
$fetch = fakeFetcher([
$search => 'Звезда, жилой комплекс',
$firm => '{"url":"https://zvezda-dsk.ru","text":"сайт","type":"website"}'
.'{"type":"phone","value":"+73912002288"}',
]);
$exp = new PhoneReverseExpander($fetch);
$res = $exp->expand('krasnoyarsk', ['73912273531'], []);
$domains = array_column($res->sites, 'domain');
$phones = array_column($res->phones, 'digits');
expect($domains)->toContain('zvezda-dsk.ru')
->and($phones)->toContain('73912002288');
});
it('общий номер (фирм больше порога) пропускается — находок нет', function () {
$search = 'https://2gis.ru/krasnoyarsk/search/78001234567';
$links = '';
foreach (range(201, 205) as $id) {
$links .= 'Фирма '.$id.'';
}
$fetch = fakeFetcher([$search => $links]);
$exp = new PhoneReverseExpander($fetch, crowdedCap: 4);
$res = $exp->expand('krasnoyarsk', ['78001234567'], []);
expect($res->sites)->toBe([])
->and($res->phones)->toBe([]);
});
it('пустой слаг города — разворот невозможен, пустой результат', function () {
$exp = new PhoneReverseExpander(fakeFetcher([]));
$res = $exp->expand('', ['73912273531'], []);
expect($res->sites)->toBe([])->and($res->phones)->toBe([]);
});
it('копает до талого: телефон A → карточка с телефоном B → карточка B даёт сайт проекта', function () {
$searchA = 'https://2gis.ru/krasnoyarsk/search/73912273531';
$firm1 = 'https://2gis.ru/krasnoyarsk/firm/111';
$searchB = 'https://2gis.ru/krasnoyarsk/search/73912002288';
$firm2 = 'https://2gis.ru/krasnoyarsk/firm/222';
$fetch = fakeFetcher([
$searchA => 'Управляющая компания',
$firm1 => '{"type":"phone","value":"+73912002288"}',
$searchB => 'Аллея парк, жилой комплекс',
$firm2 => '{"url":"https://alleya-park.ru","type":"website"}{"type":"phone","value":"+73912002288"}',
]);
$exp = new PhoneReverseExpander($fetch);
$res = $exp->expand('krasnoyarsk', ['73912273531'], []);
expect(array_column($res->sites, 'domain'))->toContain('alleya-park.ru');
});
it('одну и ту же карточку не открывает дважды (visited-set)', function () {
$searchA = 'https://2gis.ru/krasnoyarsk/search/73912273531';
$firm1 = 'https://2gis.ru/krasnoyarsk/firm/111';
$searchB = 'https://2gis.ru/krasnoyarsk/search/73912002288';
$fetch = new class($searchA, $firm1, $searchB) implements PageFetcher
{
public int $opens = 0;
public function __construct(private string $sA, private string $f1, private string $sB) {}
public function html(string $url): string
{
if ($url === $this->sA || $url === $this->sB) {
return 'Фирма';
}
if ($url === $this->f1) {
$this->opens++;
return '{"type":"phone","value":"+73912002288"}';
}
return '';
}
};
$exp = new PhoneReverseExpander($fetch);
$exp->expand('krasnoyarsk', ['73912273531'], []);
expect($fetch->opens)->toBe(1);
});
it('потолок карточек не превышается', function () {
$searchA = 'https://2gis.ru/krasnoyarsk/search/73912273531';
$fetch = new class($searchA) implements PageFetcher
{
public array $opens = [];
public function __construct(private string $sA) {}
public function html(string $url): string
{
if ($url === $this->sA) {
return 'AB';
}
$this->opens[] = $url;
return '{"type":"phone","value":"+7391200'.substr($url, -4).'"}';
}
};
$exp = new PhoneReverseExpander($fetch, maxFirms: 1);
$exp->expand('krasnoyarsk', ['73912273531'], []);
expect(count($fetch->opens))->toBe(1);
});
it('уже известный домен фирмы в находки не повторяет (не дублирует главную карточку)', function () {
$searchA = 'https://2gis.ru/krasnoyarsk/search/73912273531';
$firm1 = 'https://2gis.ru/krasnoyarsk/firm/111';
$fetch = fakeFetcher([
$searchA => 'ДСК',
$firm1 => '{"url":"https://gk-dsk.ru","type":"website"}',
]);
$exp = new PhoneReverseExpander($fetch);
$res = $exp->expand('krasnoyarsk', ['73912273531'], ['gk-dsk.ru']);
expect(array_column($res->sites, 'domain'))->not->toContain('gk-dsk.ru');
});
it('сайт без схемы в карточке — добавляем https://', function () {
$search = 'https://2gis.ru/krasnoyarsk/search/73912273531';
$firm = 'https://2gis.ru/krasnoyarsk/firm/111';
$fetch = fakeFetcher([
$search => 'Проект',
$firm => '{"url":"zvezda-dsk.ru","type":"website"}',
]);
$exp = new PhoneReverseExpander($fetch);
$res = $exp->expand('krasnoyarsk', ['73912273531'], []);
$site = array_values(array_filter($res->sites, fn ($s) => $s['domain'] === 'zvezda-dsk.ru'))[0] ?? null;
expect($site)->not->toBeNull()
->and($site['site_url'])->toBe('https://zvezda-dsk.ru');
});
it('ровно порог фирм — НЕ общая линия, находки берём', function () {
$search = 'https://2gis.ru/krasnoyarsk/search/73912273531';
$links = '';
foreach (range(301, 304) as $id) { // ровно 4 = crowdedCap → не общая линия
$links .= 'Фирма '.$id.'';
}
$map = [
$search => $links,
'https://2gis.ru/krasnoyarsk/firm/301' => '{"url":"https://proekt-301.ru","type":"website"}',
'https://2gis.ru/krasnoyarsk/firm/302' => '',
'https://2gis.ru/krasnoyarsk/firm/303' => '',
'https://2gis.ru/krasnoyarsk/firm/304' => '',
];
$exp = new PhoneReverseExpander(fakeFetcher($map), crowdedCap: 4);
$res = $exp->expand('krasnoyarsk', ['73912273531'], []);
expect(array_column($res->sites, 'domain'))->toContain('proekt-301.ru');
});