forked from fa/breadcrumb-the-shire
Strengthen service workflow tests
This commit is contained in:
@@ -84,6 +84,37 @@ class RoleServiceTest extends TestCase
|
||||
$this->assertNotEmpty($result['errors']);
|
||||
}
|
||||
|
||||
public function testCreateFromAdminReturnsErrorWhenRepositoryCreateFails(): void
|
||||
{
|
||||
$this->roleRepo
|
||||
->expects($this->once())
|
||||
->method('existsByCode')
|
||||
->with('EDITOR', 0)
|
||||
->willReturn(false);
|
||||
|
||||
$this->roleRepo
|
||||
->expects($this->once())
|
||||
->method('create')
|
||||
->willReturn(false);
|
||||
|
||||
$this->roleRepo
|
||||
->expects($this->never())
|
||||
->method('find');
|
||||
|
||||
$this->auditService
|
||||
->expects($this->never())
|
||||
->method('record');
|
||||
|
||||
$result = $this->service->createFromAdmin([
|
||||
'description' => 'Editor',
|
||||
'code' => 'EDITOR',
|
||||
'active' => 1,
|
||||
], 5);
|
||||
|
||||
$this->assertFalse($result['ok']);
|
||||
$this->assertNotEmpty($result['errors']);
|
||||
}
|
||||
|
||||
public function testCreateFromAdminSetsDefaultRoleWhenRequested(): void
|
||||
{
|
||||
$this->roleRepo
|
||||
@@ -175,6 +206,40 @@ class RoleServiceTest extends TestCase
|
||||
$this->assertNotEmpty($result['errors']);
|
||||
}
|
||||
|
||||
public function testUpdateFromAdminReturnsErrorWhenRepositoryUpdateFails(): void
|
||||
{
|
||||
$this->roleRepo
|
||||
->expects($this->once())
|
||||
->method('existsByCode')
|
||||
->with('MGR', 10)
|
||||
->willReturn(false);
|
||||
|
||||
$this->roleRepo
|
||||
->expects($this->once())
|
||||
->method('find')
|
||||
->with(10)
|
||||
->willReturn(['id' => 10, 'uuid' => 'uuid-10', 'active' => 1]);
|
||||
|
||||
$this->roleRepo
|
||||
->expects($this->once())
|
||||
->method('update')
|
||||
->with(10, $this->anything())
|
||||
->willReturn(false);
|
||||
|
||||
$this->auditService
|
||||
->expects($this->never())
|
||||
->method('record');
|
||||
|
||||
$result = $this->service->updateFromAdmin(10, [
|
||||
'description' => 'Manager',
|
||||
'code' => 'MGR',
|
||||
'active' => 1,
|
||||
], 5);
|
||||
|
||||
$this->assertFalse($result['ok']);
|
||||
$this->assertNotEmpty($result['errors']);
|
||||
}
|
||||
|
||||
public function testDeleteByUuidSucceeds(): void
|
||||
{
|
||||
$role = ['id' => 7, 'uuid' => 'uuid-7', 'description' => 'Guest'];
|
||||
|
||||
@@ -9,6 +9,7 @@ use MintyPHP\Service\Directory\DirectorySettingsGateway;
|
||||
use MintyPHP\Service\Org\DepartmentService;
|
||||
use MintyPHP\Service\Tenant\TenantScopeService;
|
||||
use MintyPHP\Service\User\UserServicesFactory;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
@@ -109,26 +110,16 @@ class DepartmentServiceTest extends TestCase
|
||||
$this->assertSame('Beta', $result[2][0]['description']);
|
||||
}
|
||||
|
||||
public function testGroupActiveByTenantIdsReturnsEmptyForInvalidIds(): void
|
||||
#[DataProvider('groupActiveByTenantIdsInputProvider')]
|
||||
public function testGroupActiveByTenantIdsNormalizesInput(array $tenantIds, array $expectedRepositoryIds): void
|
||||
{
|
||||
$this->departmentRepository
|
||||
->expects($this->never())
|
||||
->method('listByTenantIds');
|
||||
|
||||
$result = $this->service->groupActiveByTenantIds([0, -1, -5]);
|
||||
|
||||
$this->assertSame([], $result);
|
||||
}
|
||||
|
||||
public function testGroupActiveByTenantIdsDeduplicatesIds(): void
|
||||
{
|
||||
$this->departmentRepository
|
||||
->expects($this->once())
|
||||
->expects($expectedRepositoryIds ? $this->once() : $this->never())
|
||||
->method('listByTenantIds')
|
||||
->with([1])
|
||||
->with($expectedRepositoryIds)
|
||||
->willReturn([]);
|
||||
|
||||
$this->service->groupActiveByTenantIds([1, 1, 1]);
|
||||
$this->assertSame([], $this->service->groupActiveByTenantIds($tenantIds));
|
||||
}
|
||||
|
||||
public function testCreateFromAdminSucceeds(): void
|
||||
@@ -193,36 +184,9 @@ class DepartmentServiceTest extends TestCase
|
||||
$this->assertTrue($result['ok']);
|
||||
}
|
||||
|
||||
public function testCreateFromAdminRejectsEmptyDescription(): void
|
||||
#[DataProvider('invalidDepartmentInputProvider')]
|
||||
public function testCreateFromAdminRejectsInvalidInput(array $input): void
|
||||
{
|
||||
$input = [
|
||||
'description' => '',
|
||||
'tenant_id' => 1,
|
||||
'code' => '',
|
||||
'cost_center' => '',
|
||||
'active' => 1,
|
||||
];
|
||||
|
||||
$this->departmentRepository
|
||||
->expects($this->never())
|
||||
->method('create');
|
||||
|
||||
$result = $this->service->createFromAdmin($input);
|
||||
|
||||
$this->assertFalse($result['ok']);
|
||||
$this->assertNotEmpty($result['errors']);
|
||||
}
|
||||
|
||||
public function testCreateFromAdminRejectsMissingTenantId(): void
|
||||
{
|
||||
$input = [
|
||||
'description' => 'Sales',
|
||||
'tenant_id' => 0,
|
||||
'code' => '',
|
||||
'cost_center' => '',
|
||||
'active' => 1,
|
||||
];
|
||||
|
||||
$this->departmentRepository
|
||||
->expects($this->never())
|
||||
->method('create');
|
||||
@@ -291,6 +255,31 @@ class DepartmentServiceTest extends TestCase
|
||||
$this->assertSame(404, $result['status']);
|
||||
}
|
||||
|
||||
public function testDeleteByUuidReturnsDeleteFailedOnRepositoryFailure(): void
|
||||
{
|
||||
$this->departmentRepository
|
||||
->expects($this->once())
|
||||
->method('findByUuid')
|
||||
->with('abc-999')
|
||||
->willReturn(['id' => 9, 'uuid' => 'abc-999', 'description' => 'Ops']);
|
||||
|
||||
$this->departmentRepository
|
||||
->expects($this->once())
|
||||
->method('delete')
|
||||
->with(9)
|
||||
->willReturn(false);
|
||||
|
||||
$this->systemAuditService
|
||||
->expects($this->never())
|
||||
->method('record');
|
||||
|
||||
$result = $this->service->deleteByUuid('abc-999');
|
||||
|
||||
$this->assertFalse($result['ok']);
|
||||
$this->assertSame(500, $result['status']);
|
||||
$this->assertSame('delete_failed', $result['error']);
|
||||
}
|
||||
|
||||
public function testSyncTenantsUsesFirstId(): void
|
||||
{
|
||||
$this->departmentRepository
|
||||
@@ -322,4 +311,32 @@ class DepartmentServiceTest extends TestCase
|
||||
|
||||
$this->assertSame(-1, $result);
|
||||
}
|
||||
|
||||
public static function groupActiveByTenantIdsInputProvider(): array
|
||||
{
|
||||
return [
|
||||
'invalid ids are ignored completely' => [[0, -1, -5], []],
|
||||
'duplicate ids are reduced before querying' => [[1, 1, 1], [1]],
|
||||
];
|
||||
}
|
||||
|
||||
public static function invalidDepartmentInputProvider(): array
|
||||
{
|
||||
return [
|
||||
'missing description' => [[
|
||||
'description' => '',
|
||||
'tenant_id' => 1,
|
||||
'code' => '',
|
||||
'cost_center' => '',
|
||||
'active' => 1,
|
||||
]],
|
||||
'missing tenant id' => [[
|
||||
'description' => 'Sales',
|
||||
'tenant_id' => 0,
|
||||
'code' => '',
|
||||
'cost_center' => '',
|
||||
'active' => 1,
|
||||
]],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ use MintyPHP\Service\User\UserAssignmentService;
|
||||
use MintyPHP\Service\User\UserDirectoryGateway;
|
||||
use MintyPHP\Service\User\UserPasswordService;
|
||||
use MintyPHP\Service\User\UserSettingsGateway;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class UserAccountServiceTest extends TestCase
|
||||
@@ -40,11 +41,22 @@ class UserAccountServiceTest extends TestCase
|
||||
$this->assertSame(0, (int) ($result['total'] ?? -1));
|
||||
}
|
||||
|
||||
public function testDeleteByUuidReturnsNotFoundForEmptyUuid(): void
|
||||
#[DataProvider('missingDeleteByUuidInputProvider')]
|
||||
public function testDeleteByUuidReturnsNotFoundForMissingInput(string $uuid, ?array $resolvedUser): void
|
||||
{
|
||||
$service = $this->newService();
|
||||
$readRepository = $this->createMock(UserReadRepositoryInterface::class);
|
||||
if ($uuid !== '') {
|
||||
$readRepository->expects($this->once())
|
||||
->method('findByUuid')
|
||||
->with($uuid)
|
||||
->willReturn($resolvedUser);
|
||||
} else {
|
||||
$readRepository->expects($this->never())->method('findByUuid');
|
||||
}
|
||||
|
||||
$result = $service->deleteByUuid('');
|
||||
$service = $this->newService($readRepository);
|
||||
|
||||
$result = $service->deleteByUuid($uuid);
|
||||
|
||||
$this->assertFalse($result['ok']);
|
||||
$this->assertSame(404, (int) ($result['status'] ?? 0));
|
||||
@@ -104,6 +116,31 @@ class UserAccountServiceTest extends TestCase
|
||||
$this->assertSame(11, (int) (($result['user'] ?? [])['id'] ?? 0));
|
||||
}
|
||||
|
||||
public function testDeleteByUuidReturnsDeleteFailedWhenRepositoryDeleteFails(): void
|
||||
{
|
||||
$readRepository = $this->createMock(UserReadRepositoryInterface::class);
|
||||
$readRepository->expects($this->once())
|
||||
->method('findByUuid')
|
||||
->with('user-uuid')
|
||||
->willReturn(['id' => 11, 'uuid' => 'user-uuid']);
|
||||
|
||||
$writeRepository = $this->createMock(UserWriteRepositoryInterface::class);
|
||||
$writeRepository->expects($this->once())
|
||||
->method('delete')
|
||||
->with(11)
|
||||
->willReturn(false);
|
||||
|
||||
$auditService = $this->createMock(SystemAuditService::class);
|
||||
$auditService->expects($this->never())->method('record');
|
||||
|
||||
$service = $this->newService($readRepository, $writeRepository, null, null, null, null, null, null, $auditService);
|
||||
$result = $service->deleteByUuid('user-uuid', 44);
|
||||
|
||||
$this->assertFalse($result['ok']);
|
||||
$this->assertSame(500, (int) ($result['status'] ?? 0));
|
||||
$this->assertSame('delete_failed', (string) ($result['error'] ?? ''));
|
||||
}
|
||||
|
||||
public function testDeleteByUuidsReturnsPermissionDeniedWhenNothingIsInScope(): void
|
||||
{
|
||||
$readRepository = $this->createMock(UserReadRepositoryInterface::class);
|
||||
@@ -160,6 +197,50 @@ class UserAccountServiceTest extends TestCase
|
||||
$this->assertSame('self_deactivate', (string) ($result['error'] ?? ''));
|
||||
}
|
||||
|
||||
public function testSetActiveByUuidReturnsNotFoundForMissingUser(): void
|
||||
{
|
||||
$readRepository = $this->createMock(UserReadRepositoryInterface::class);
|
||||
$readRepository->expects($this->once())
|
||||
->method('findByUuid')
|
||||
->with('u-missing')
|
||||
->willReturn(null);
|
||||
|
||||
$writeRepository = $this->createMock(UserWriteRepositoryInterface::class);
|
||||
$writeRepository->expects($this->never())->method('setActive');
|
||||
|
||||
$service = $this->newService($readRepository, $writeRepository);
|
||||
$result = $service->setActiveByUuid('u-missing', true, 42);
|
||||
|
||||
$this->assertFalse($result['ok']);
|
||||
$this->assertSame(404, (int) ($result['status'] ?? 0));
|
||||
$this->assertSame('not_found', (string) ($result['error'] ?? ''));
|
||||
}
|
||||
|
||||
public function testSetActiveByUuidReturnsUpdateFailedWhenRepositoryRejects(): void
|
||||
{
|
||||
$readRepository = $this->createMock(UserReadRepositoryInterface::class);
|
||||
$readRepository->method('findByUuid')->willReturn(['id' => 33, 'uuid' => 'u-33', 'active' => 0]);
|
||||
|
||||
$writeRepository = $this->createMock(UserWriteRepositoryInterface::class);
|
||||
$writeRepository->expects($this->once())
|
||||
->method('setActive')
|
||||
->with(33, true, 90)
|
||||
->willReturn(false);
|
||||
|
||||
$assignmentService = $this->createMock(UserAssignmentService::class);
|
||||
$assignmentService->expects($this->never())->method('bumpAuthzVersion');
|
||||
|
||||
$auditService = $this->createMock(SystemAuditService::class);
|
||||
$auditService->expects($this->never())->method('record');
|
||||
|
||||
$service = $this->newService($readRepository, $writeRepository, null, $assignmentService, null, null, null, null, $auditService);
|
||||
$result = $service->setActiveByUuid('u-33', true, 90);
|
||||
|
||||
$this->assertFalse($result['ok']);
|
||||
$this->assertSame(500, (int) ($result['status'] ?? 0));
|
||||
$this->assertSame('update_failed', (string) ($result['error'] ?? ''));
|
||||
}
|
||||
|
||||
public function testSetActiveByUuidUpdatesAssignmentsAndAudit(): void
|
||||
{
|
||||
$readRepository = $this->createMock(UserReadRepositoryInterface::class);
|
||||
@@ -238,6 +319,8 @@ class UserAccountServiceTest extends TestCase
|
||||
$settingsGateway->method('getDefaultTenantId')->willReturn(3);
|
||||
$settingsGateway->method('getDefaultRoleId')->willReturn(4);
|
||||
$settingsGateway->method('getDefaultDepartmentId')->willReturn(5);
|
||||
$settingsGateway->method('normalizeTheme')
|
||||
->willReturnCallback(static fn (?string $theme): string => $theme ?? 'light');
|
||||
|
||||
$writeRepository = $this->createMock(UserWriteRepositoryInterface::class);
|
||||
$writeRepository->expects($this->once())
|
||||
@@ -294,6 +377,8 @@ class UserAccountServiceTest extends TestCase
|
||||
$settingsGateway->method('getDefaultRoleId')->willReturn(null);
|
||||
$settingsGateway->method('getDefaultDepartmentId')->willReturn(null);
|
||||
$settingsGateway->method('getAppTheme')->willReturn('light');
|
||||
$settingsGateway->method('normalizeTheme')
|
||||
->willReturnCallback(static fn (?string $theme): string => $theme ?? 'light');
|
||||
|
||||
$writeRepository = $this->createMock(UserWriteRepositoryInterface::class);
|
||||
$writeRepository->expects($this->once())->method('create')->willReturn(88);
|
||||
@@ -358,6 +443,8 @@ class UserAccountServiceTest extends TestCase
|
||||
$settingsGateway->method('getDefaultTenantId')->willReturn(3);
|
||||
$settingsGateway->method('getDefaultRoleId')->willReturn(4);
|
||||
$settingsGateway->method('getDefaultDepartmentId')->willReturn(5);
|
||||
$settingsGateway->method('normalizeTheme')
|
||||
->willReturnCallback(static fn (?string $theme): string => $theme ?? 'light');
|
||||
|
||||
$writeRepository = $this->createMock(UserWriteRepositoryInterface::class);
|
||||
$writeRepository->expects($this->once())->method('create')->willReturn(77);
|
||||
@@ -602,4 +689,12 @@ class UserAccountServiceTest extends TestCase
|
||||
$databaseSessionRepository
|
||||
);
|
||||
}
|
||||
|
||||
public static function missingDeleteByUuidInputProvider(): array
|
||||
{
|
||||
return [
|
||||
'empty uuid' => ['', null],
|
||||
'missing user' => ['missing-uuid', null],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user