tenantRepository = $this->createMock(TenantRepositoryInterface::class); $this->departmentRepository = $this->createMock(DepartmentRepositoryInterface::class); $this->settingsGateway = $this->createMock(DirectorySettingsGateway::class); $this->settingsGateway->method('isAllowedTheme')->willReturn(true); $this->settingsGateway->method('normalizeTheme') ->willReturnCallback(static fn (?string $t): string => $t ?? 'light'); $this->systemAuditService = $this->createMock(AuditRecorderInterface::class); $this->service = new TenantService( $this->tenantRepository, $this->departmentRepository, $this->settingsGateway, $this->systemAuditService ); } public function testCreateFromAdminSucceeds(): void { $input = $this->validInput(); $this->tenantRepository->expects($this->once()) ->method('create') ->willReturn(42); $this->tenantRepository->expects($this->once()) ->method('find') ->with(42) ->willReturn(['id' => 42, 'uuid' => 'abc-uuid-123']); $this->systemAuditService->expects($this->once()) ->method('record'); $result = $this->service->createFromAdmin($input, 5); self::assertTrue($result['ok']); self::assertSame('abc-uuid-123', $result['uuid']); self::assertSame(42, $result['id']); self::assertSame('Test Tenant', $result['form']['description']); } public function testCreateFromAdminRejectsEmptyDescription(): void { $input = $this->validInput(); $input['description'] = ''; $this->tenantRepository->expects($this->never()) ->method('create'); $result = $this->service->createFromAdmin($input); self::assertFalse($result['ok']); self::assertNotEmpty($result['errors']); } public function testUpdateFromAdminSucceeds(): void { $input = $this->validInput(); $this->tenantRepository->expects($this->once()) ->method('find') ->with(10) ->willReturn(['id' => 10, 'uuid' => 'existing-uuid', 'status' => 'active']); $this->tenantRepository->expects($this->once()) ->method('update') ->with(10, $this->isArray()) ->willReturn(true); $this->systemAuditService->expects($this->once()) ->method('record'); $result = $this->service->updateFromAdmin(10, $input, 5); self::assertTrue($result['ok']); self::assertSame('Test Tenant', $result['form']['description']); } public function testDeleteByUuidSucceeds(): void { $tenant = ['id' => 7, 'uuid' => 'del-uuid-789']; $this->tenantRepository->expects($this->once()) ->method('findByUuid') ->with('del-uuid-789') ->willReturn($tenant); $this->departmentRepository->expects($this->once()) ->method('countByTenantId') ->with(7) ->willReturn(0); $this->tenantRepository->expects($this->once()) ->method('delete') ->with(7) ->willReturn(true); $this->systemAuditService->expects($this->once()) ->method('record'); $result = $this->service->deleteByUuid('del-uuid-789'); self::assertTrue($result['ok']); self::assertSame($tenant, $result['tenant']); } public function testDeleteByUuidBlocksWhenDepartmentsExist(): void { $tenant = ['id' => 7, 'uuid' => 'dep-uuid-789']; $this->tenantRepository->expects($this->once()) ->method('findByUuid') ->with('dep-uuid-789') ->willReturn($tenant); $this->departmentRepository->expects($this->once()) ->method('countByTenantId') ->with(7) ->willReturn(3); $this->tenantRepository->expects($this->never()) ->method('delete'); $result = $this->service->deleteByUuid('dep-uuid-789'); self::assertFalse($result['ok']); self::assertSame(409, $result['status']); self::assertSame('tenant_has_departments', $result['error']); } public function testDeleteByUuidReturnsNotFoundForEmptyUuid(): void { $this->tenantRepository->expects($this->never()) ->method('findByUuid'); $result = $this->service->deleteByUuid(''); self::assertFalse($result['ok']); self::assertSame(404, $result['status']); self::assertSame('not_found', $result['error']); } public function testDeleteByUuidReturnsNotFoundForMissingTenant(): void { $this->tenantRepository->expects($this->once()) ->method('findByUuid') ->with('nonexistent-uuid') ->willReturn(null); $result = $this->service->deleteByUuid('nonexistent-uuid'); self::assertFalse($result['ok']); self::assertSame(404, $result['status']); self::assertSame('not_found', $result['error']); } /** * @return array */ private function validInput(): array { return [ 'description' => 'Test Tenant', 'status' => 'active', 'address' => '', 'postal_code' => '', 'city' => '', 'country' => '', 'region' => '', 'vat_id' => '', 'tax_number' => '', 'phone' => '', 'fax' => '', 'email' => '', 'support_email' => '', 'support_phone' => '', 'billing_email' => '', 'website' => '', 'privacy_url' => '', 'imprint_url' => '', 'primary_color' => '#2fa4a4', 'default_theme' => 'light', 'allow_user_theme' => '1', ]; } }