tmpFiles as $file) { if (is_file($file)) { @unlink($file); } } } public function testAnalyzeDetectsSemicolonAndBom(): void { $file = $this->newTmpFile("\xEF\xBB\xBFfirst_name;email\nMax;max@example.com\n"); $service = new CsvReaderService(); $result = $service->analyze($file, 20000); $this->assertTrue($result['ok']); $this->assertSame(';', $result['delimiter']); $this->assertSame(['first_name', 'email'], $result['headers']); $this->assertSame(1, $result['rows_total']); } public function testAnalyzeReturnsInvalidHeaderForDuplicateColumns(): void { $file = $this->newTmpFile("email,email\nfoo@example.com,bar@example.com\n"); $service = new CsvReaderService(); $result = $service->analyze($file, 20000); $this->assertFalse($result['ok']); $this->assertSame('invalid_csv_header', $result['code']); } public function testAnalyzeReturnsEmptyCsvWhenNoDataRows(): void { $file = $this->newTmpFile("email\n"); $service = new CsvReaderService(); $result = $service->analyze($file, 20000); $this->assertFalse($result['ok']); $this->assertSame('empty_csv', $result['code']); } private function newTmpFile(string $content): string { $file = tempnam(sys_get_temp_dir(), 'im_csv_'); $this->assertNotFalse($file); file_put_contents($file, $content); $this->tmpFiles[] = $file; return $file; } }