Files
portal/app/tests/Unit/Supplier/SupplierCsvParserTest.php
T
Дмитрий cb86065588 feat(supplier): Plan 4 Task 7 — SupplierCsvParser (streaming) + SupplierPortalClient::downloadLeadsCsv
SupplierCsvParser — pure streaming-generator CSV parser:
- BOM (UTF-8 EF BB BF) + CRLF normalization
- Malformed rows (< 6 columns) skipped + Log::warning
- 5 unit tests: empty / 1 row / 1000 rows / malformed / BOM+CRLF

SupplierPortalClient::downloadLeadsCsv(CarbonInterface, CarbonInterface):
- GET /admin/report/index?type=49 через существующий request() helper
- Наследует auth/retry семантику (401 → RefreshSession, 5xx → Transient, 4xx → Client)
- 3 unit tests через Http::fake: 200 / 401 retry / 500

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 10:50:11 +03:00

79 lines
2.2 KiB
PHP

<?php
declare(strict_types=1);
use App\Services\Supplier\SupplierCsvParser;
use Illuminate\Support\Facades\Log;
use Tests\TestCase;
uses(TestCase::class);
beforeEach(function () {
$this->parser = new SupplierCsvParser;
});
it('parses empty CSV → yields nothing', function () {
$rows = iterator_to_array($this->parser->parse(''));
expect($rows)->toBeEmpty();
});
it('parses 1 row → yields 1 struct with vid/project/phone/time', function () {
$csv = "vid;project;tag;phone;phones;time\n"
."1234;B1_example.com;;79991234567;79991234567;1715432400\n";
$rows = iterator_to_array($this->parser->parse($csv));
expect($rows)->toHaveCount(1);
expect($rows[0])->toMatchArray([
'vid' => '1234',
'project' => 'B1_example.com',
'phone' => '79991234567',
'time' => 1715432400,
]);
});
it('parses 1000 rows without OOM (streaming generator)', function () {
$lines = ['vid;project;tag;phone;phones;time'];
for ($i = 1; $i <= 1000; $i++) {
$lines[] = "{$i};B1_test.com;;79991234567;79991234567;1715432400";
}
$csv = implode("\n", $lines)."\n";
$count = 0;
foreach ($this->parser->parse($csv) as $_) {
$count++;
}
expect($count)->toBe(1000);
});
it('skips malformed rows with missing columns + logs warning', function () {
Log::spy();
$csv = "vid;project;tag;phone;phones;time\n"
."1234;B1_example.com;;79991234567;79991234567;1715432400\n"
."broken-row-only-one-column\n"
."5678;B1_another.com;;79991234567;79991234567;1715432500\n";
$rows = iterator_to_array($this->parser->parse($csv));
expect($rows)->toHaveCount(2);
expect($rows[0]['vid'])->toBe('1234');
expect($rows[1]['vid'])->toBe('5678');
Log::shouldHaveReceived('warning')
->with('supplier_csv_parser.malformed_row', Mockery::any())
->once();
});
it('handles BOM + CRLF line endings', function () {
$bom = "\xEF\xBB\xBF";
$csv = $bom."vid;project;tag;phone;phones;time\r\n"
."1234;B1_example.com;;79991234567;79991234567;1715432400\r\n";
$rows = iterator_to_array($this->parser->parse($csv));
expect($rows)->toHaveCount(1);
expect($rows[0]['vid'])->toBe('1234');
});