instances added god may help
This commit is contained in:
65
tests/Service/Import/CsvReaderServiceTest.php
Normal file
65
tests/Service/Import/CsvReaderServiceTest.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Tests\Service\Import;
|
||||
|
||||
use MintyPHP\Service\Import\CsvReaderService;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class CsvReaderServiceTest extends TestCase
|
||||
{
|
||||
private array $tmpFiles = [];
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
foreach ($this->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;
|
||||
}
|
||||
}
|
||||
|
||||
213
tests/Service/Import/ImportServiceTest.php
Normal file
213
tests/Service/Import/ImportServiceTest.php
Normal file
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Tests\Service\Import;
|
||||
|
||||
use MintyPHP\Service\Audit\ImportAuditService;
|
||||
use MintyPHP\Service\Access\PermissionGateway;
|
||||
use MintyPHP\Service\Import\CsvReaderService;
|
||||
use MintyPHP\Service\Import\ImportService;
|
||||
use MintyPHP\Service\Import\ImportStateStoreService;
|
||||
use MintyPHP\Service\Import\ImportTempFileService;
|
||||
use MintyPHP\Service\Import\Profile\ImportProfileInterface;
|
||||
use MintyPHP\Service\Settings\SettingGateway;
|
||||
use MintyPHP\Service\User\UserScopeGateway;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ImportServiceTest extends TestCase
|
||||
{
|
||||
public function testAnalyzeUploadBuildsTokenStateAndAutoMapping(): void
|
||||
{
|
||||
$profile = new ImportServiceTestProfile('users', false);
|
||||
$csvReader = $this->createMock(CsvReaderService::class);
|
||||
$csvReader->expects($this->once())
|
||||
->method('analyze')
|
||||
->willReturn([
|
||||
'ok' => true,
|
||||
'delimiter' => ';',
|
||||
'headers' => ['E-Mail'],
|
||||
'rows_total' => 2,
|
||||
]);
|
||||
|
||||
$tempFileService = $this->createMock(ImportTempFileService::class);
|
||||
$tempFileService->expects($this->once())
|
||||
->method('storeUploadedFile')
|
||||
->willReturn(['ok' => true, 'path' => '/tmp/import.csv']);
|
||||
|
||||
$stateStore = $this->createMock(ImportStateStoreService::class);
|
||||
$stateStore->expects($this->once())
|
||||
->method('setState')
|
||||
->with(
|
||||
$this->isString(),
|
||||
$this->callback(function (array $state): bool {
|
||||
return (string) ($state['path'] ?? '') === '/tmp/import.csv'
|
||||
&& (string) ($state['type'] ?? '') === 'users'
|
||||
&& is_int($state['created_at'] ?? null);
|
||||
})
|
||||
);
|
||||
|
||||
$service = $this->newImportService($profile, $csvReader, $tempFileService, $stateStore);
|
||||
$result = $service->analyzeUpload([
|
||||
'tmp_name' => '/tmp/php-upload',
|
||||
'name' => 'users.csv',
|
||||
'size' => 10,
|
||||
'error' => UPLOAD_ERR_OK,
|
||||
], 'users', 7);
|
||||
|
||||
$this->assertTrue($result['ok']);
|
||||
$this->assertSame(';', $result['delimiter']);
|
||||
$this->assertSame(['E-Mail' => 'email'], $result['auto_mapping']);
|
||||
}
|
||||
|
||||
public function testPreviewFailsWhenRequiredMappingIsMissing(): void
|
||||
{
|
||||
$profile = new ImportServiceTestProfile('users', false);
|
||||
$stateStore = $this->createMock(ImportStateStoreService::class);
|
||||
$stateStore->method('getState')->willReturn([
|
||||
'token' => 'tok',
|
||||
'type' => 'users',
|
||||
'headers' => ['email'],
|
||||
'path' => '/tmp/import.csv',
|
||||
'delimiter' => ',',
|
||||
'user_id' => 5,
|
||||
'created_at' => time(),
|
||||
]);
|
||||
|
||||
$service = $this->newImportService($profile, null, null, $stateStore);
|
||||
$result = $service->preview('tok', ['mapping' => []], 5);
|
||||
|
||||
$this->assertFalse($result['ok']);
|
||||
$this->assertSame('mapping_required_missing', $result['code']);
|
||||
}
|
||||
|
||||
public function testPreviewFailsWhenAssignmentPermissionIsMissing(): void
|
||||
{
|
||||
$profile = new ImportServiceTestProfile('users', true);
|
||||
$stateStore = $this->createMock(ImportStateStoreService::class);
|
||||
$stateStore->method('getState')->willReturn([
|
||||
'token' => 'tok',
|
||||
'type' => 'users',
|
||||
'headers' => ['email', 'tenant'],
|
||||
'path' => '/tmp/import.csv',
|
||||
'delimiter' => ',',
|
||||
'user_id' => 0,
|
||||
'created_at' => time(),
|
||||
]);
|
||||
|
||||
$service = $this->newImportService($profile, null, null, $stateStore);
|
||||
$result = $service->preview('tok', ['mapping' => ['email' => 'email', 'tenant' => 'tenant']], 0);
|
||||
|
||||
$this->assertFalse($result['ok']);
|
||||
$this->assertSame('assignment_permission_required', $result['code']);
|
||||
}
|
||||
|
||||
public function testMessageForCodeUsesKnownMappingAndFallback(): void
|
||||
{
|
||||
$service = $this->newImportService(new ImportServiceTestProfile('users', false));
|
||||
|
||||
$this->assertSame('Invalid file type', $service->messageForCode('invalid_file_type'));
|
||||
$this->assertSame('Unexpected error during import', $service->messageForCode('something_unknown'));
|
||||
}
|
||||
|
||||
private function newImportService(
|
||||
ImportProfileInterface $profile,
|
||||
?CsvReaderService $csvReader = null,
|
||||
?ImportTempFileService $tempFileService = null,
|
||||
?ImportStateStoreService $stateStore = null
|
||||
): ImportService {
|
||||
$csvReader = $csvReader ?? $this->createMock(CsvReaderService::class);
|
||||
$tempFileService = $tempFileService ?? $this->createMock(ImportTempFileService::class);
|
||||
$auditService = $this->createMock(ImportAuditService::class);
|
||||
$stateStore = $stateStore ?? $this->createMock(ImportStateStoreService::class);
|
||||
$permissionGateway = $this->createMock(PermissionGateway::class);
|
||||
$permissionGateway->method('userHas')->willReturn(false);
|
||||
$settingService = $this->createMock('MintyPHP\\Service\\Settings\\SettingService');
|
||||
$settingGateway = new SettingGateway($settingService);
|
||||
$userScopeGateway = $this->createMock(UserScopeGateway::class);
|
||||
$userScopeGateway->method('hasGlobalAccess')->willReturn(false);
|
||||
$userScopeGateway->method('getUserTenantIds')->willReturn([]);
|
||||
|
||||
return new ImportService(
|
||||
$csvReader,
|
||||
$tempFileService,
|
||||
$auditService,
|
||||
$stateStore,
|
||||
[$profile->key() => $profile],
|
||||
$permissionGateway,
|
||||
$settingGateway,
|
||||
$userScopeGateway
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ImportServiceTestProfile implements ImportProfileInterface
|
||||
{
|
||||
public function __construct(private readonly string $key, private readonly bool $requiresAssignmentPermission)
|
||||
{
|
||||
}
|
||||
|
||||
public function key(): string
|
||||
{
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
public function label(): string
|
||||
{
|
||||
return 'Test';
|
||||
}
|
||||
|
||||
public function allowedTargets(): array
|
||||
{
|
||||
return [
|
||||
'email' => 'Email',
|
||||
'tenant' => 'Tenant',
|
||||
];
|
||||
}
|
||||
|
||||
public function requiredTargets(): array
|
||||
{
|
||||
return ['email'];
|
||||
}
|
||||
|
||||
public function autoMapAliases(): array
|
||||
{
|
||||
return [
|
||||
'email' => ['e-mail', 'email'],
|
||||
'tenant' => ['tenant'],
|
||||
];
|
||||
}
|
||||
|
||||
public function supportsAssignments(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function requiresAssignmentPermission(): bool
|
||||
{
|
||||
return $this->requiresAssignmentPermission;
|
||||
}
|
||||
|
||||
public function validateMappedRow(array $mapped, array $context): array
|
||||
{
|
||||
return ['ok' => true, 'normalized' => $mapped, 'errors' => []];
|
||||
}
|
||||
|
||||
public function dryRunRow(array $normalized, array $context): array
|
||||
{
|
||||
return ['status' => 'would_create'];
|
||||
}
|
||||
|
||||
public function commitRow(array $normalized, array $context): array
|
||||
{
|
||||
return ['status' => 'created'];
|
||||
}
|
||||
|
||||
public function inFileDuplicateKey(array $normalized): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function rowIdentifier(array $normalized): string
|
||||
{
|
||||
return (string) ($normalized['email'] ?? '');
|
||||
}
|
||||
}
|
||||
33
tests/Service/Import/ImportServicesFactoryTest.php
Normal file
33
tests/Service/Import/ImportServicesFactoryTest.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Tests\Service\Import;
|
||||
|
||||
use MintyPHP\Service\Audit\ImportAuditService;
|
||||
use MintyPHP\Service\Import\ImportService;
|
||||
use MintyPHP\Service\Import\ImportServicesFactory;
|
||||
use MintyPHP\Service\Import\ImportStateStoreService;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ImportServicesFactoryTest extends TestCase
|
||||
{
|
||||
public function testFactoryReturnsStableInstancesPerFactoryObject(): void
|
||||
{
|
||||
$factory = new ImportServicesFactory();
|
||||
|
||||
$importServiceA = $factory->createImportService();
|
||||
$importServiceB = $factory->createImportService();
|
||||
$this->assertInstanceOf(ImportService::class, $importServiceA);
|
||||
$this->assertSame($importServiceA, $importServiceB);
|
||||
|
||||
$auditServiceA = $factory->createImportAuditService();
|
||||
$auditServiceB = $factory->createImportAuditService();
|
||||
$this->assertInstanceOf(ImportAuditService::class, $auditServiceA);
|
||||
$this->assertSame($auditServiceA, $auditServiceB);
|
||||
|
||||
$stateStoreA = $factory->createImportStateStoreService();
|
||||
$stateStoreB = $factory->createImportStateStoreService();
|
||||
$this->assertInstanceOf(ImportStateStoreService::class, $stateStoreA);
|
||||
$this->assertSame($stateStoreA, $stateStoreB);
|
||||
}
|
||||
}
|
||||
|
||||
47
tests/Service/Import/ImportStateStoreServiceTest.php
Normal file
47
tests/Service/Import/ImportStateStoreServiceTest.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Tests\Service\Import;
|
||||
|
||||
use MintyPHP\Service\Import\ImportStateStoreService;
|
||||
use MintyPHP\Service\Import\ImportTempFileService;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ImportStateStoreServiceTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
$_SESSION = [];
|
||||
}
|
||||
|
||||
public function testSetGetAndClearState(): void
|
||||
{
|
||||
$tempFileService = $this->createMock(ImportTempFileService::class);
|
||||
$stateStore = new ImportStateStoreService($tempFileService);
|
||||
|
||||
$stateStore->setState('token_a', ['token' => 'token_a', 'created_at' => time(), 'path' => '/tmp/a.csv']);
|
||||
$loaded = $stateStore->getState('token_a');
|
||||
$this->assertIsArray($loaded);
|
||||
$this->assertSame('token_a', $loaded['token']);
|
||||
|
||||
$stateStore->clearState('token_a');
|
||||
$this->assertNull($stateStore->getState('token_a'));
|
||||
}
|
||||
|
||||
public function testExpiredStateGetsDeletedAndReturnsNull(): void
|
||||
{
|
||||
$tempFileService = $this->createMock(ImportTempFileService::class);
|
||||
$tempFileService->expects($this->once())
|
||||
->method('delete')
|
||||
->with('/tmp/expired.csv');
|
||||
|
||||
$stateStore = new ImportStateStoreService($tempFileService);
|
||||
$stateStore->setState('token_b', [
|
||||
'token' => 'token_b',
|
||||
'created_at' => time() - 7201,
|
||||
'path' => '/tmp/expired.csv',
|
||||
]);
|
||||
|
||||
$this->assertNull($stateStore->getState('token_b'));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user