aboutsummaryrefslogtreecommitdiffstats
path: root/apps/dav/tests/unit/Service
diff options
context:
space:
mode:
Diffstat (limited to 'apps/dav/tests/unit/Service')
-rw-r--r--apps/dav/tests/unit/Service/AbsenceServiceTest.php445
-rw-r--r--apps/dav/tests/unit/Service/ExampleContactServiceTest.php194
-rw-r--r--apps/dav/tests/unit/Service/ExampleEventServiceTest.php196
-rw-r--r--apps/dav/tests/unit/Service/UpcomingEventsServiceTest.php89
4 files changed, 924 insertions, 0 deletions
diff --git a/apps/dav/tests/unit/Service/AbsenceServiceTest.php b/apps/dav/tests/unit/Service/AbsenceServiceTest.php
new file mode 100644
index 00000000000..c16c715d5c2
--- /dev/null
+++ b/apps/dav/tests/unit/Service/AbsenceServiceTest.php
@@ -0,0 +1,445 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\DAV\Tests\unit\Service;
+
+use DateTimeImmutable;
+use DateTimeZone;
+use OCA\DAV\BackgroundJob\OutOfOfficeEventDispatcherJob;
+use OCA\DAV\CalDAV\TimezoneService;
+use OCA\DAV\Db\Absence;
+use OCA\DAV\Db\AbsenceMapper;
+use OCA\DAV\Service\AbsenceService;
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\BackgroundJob\IJobList;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\IUser;
+use OCP\User\Events\OutOfOfficeChangedEvent;
+use OCP\User\Events\OutOfOfficeScheduledEvent;
+use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+
+class AbsenceServiceTest extends TestCase {
+ private AbsenceService $absenceService;
+ private AbsenceMapper&MockObject $absenceMapper;
+ private IEventDispatcher&MockObject $eventDispatcher;
+ private IJobList&MockObject $jobList;
+ private TimezoneService&MockObject $timezoneService;
+ private ITimeFactory&MockObject $timeFactory;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->absenceMapper = $this->createMock(AbsenceMapper::class);
+ $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
+ $this->jobList = $this->createMock(IJobList::class);
+ $this->timezoneService = $this->createMock(TimezoneService::class);
+ $this->timeFactory = $this->createMock(ITimeFactory::class);
+
+ $this->absenceService = new AbsenceService(
+ $this->absenceMapper,
+ $this->eventDispatcher,
+ $this->jobList,
+ $this->timezoneService,
+ $this->timeFactory,
+ );
+ }
+
+ public function testCreateAbsenceEmitsScheduledEvent(): void {
+ $tz = new DateTimeZone('Europe/Berlin');
+ $user = $this->createMock(IUser::class);
+ $user->method('getUID')
+ ->willReturn('user');
+
+ $this->absenceMapper->expects(self::once())
+ ->method('findByUserId')
+ ->with('user')
+ ->willThrowException(new DoesNotExistException('foo bar'));
+ $this->absenceMapper->expects(self::once())
+ ->method('insert')
+ ->willReturnCallback(function (Absence $absence): Absence {
+ $absence->setId(1);
+ return $absence;
+ });
+ $this->timezoneService->expects(self::once())
+ ->method('getUserTimezone')
+ ->with('user')
+ ->willReturn('Europe/Berlin');
+ $this->eventDispatcher->expects(self::once())
+ ->method('dispatchTyped')
+ ->with(self::callback(static function (Event $event) use ($user, $tz): bool {
+ self::assertInstanceOf(OutOfOfficeScheduledEvent::class, $event);
+ /** @var OutOfOfficeScheduledEvent $event */
+ $data = $event->getData();
+ self::assertEquals('1', $data->getId());
+ self::assertEquals($user, $data->getUser());
+ self::assertEquals(
+ (new DateTimeImmutable('2023-01-05', $tz))->getTimeStamp(),
+ $data->getStartDate(),
+ );
+ self::assertEquals(
+ (new DateTimeImmutable('2023-01-10', $tz))->getTimeStamp() + 3600 * 23 + 59 * 60,
+ $data->getEndDate(),
+ );
+ self::assertEquals('status', $data->getShortMessage());
+ self::assertEquals('message', $data->getMessage());
+ return true;
+ }));
+ $this->timeFactory->expects(self::once())
+ ->method('getTime')
+ ->willReturn(PHP_INT_MAX);
+ $this->jobList->expects(self::never())
+ ->method('scheduleAfter');
+
+ $this->absenceService->createOrUpdateAbsence(
+ $user,
+ '2023-01-05',
+ '2023-01-10',
+ 'status',
+ 'message',
+ );
+ }
+
+ public function testUpdateAbsenceEmitsChangedEvent(): void {
+ $tz = new DateTimeZone('Europe/Berlin');
+ $user = $this->createMock(IUser::class);
+ $user->method('getUID')
+ ->willReturn('user');
+ $absence = new Absence();
+ $absence->setId(1);
+ $absence->setFirstDay('1970-01-01');
+ $absence->setLastDay('1970-01-10');
+ $absence->setStatus('old status');
+ $absence->setMessage('old message');
+
+ $this->absenceMapper->expects(self::once())
+ ->method('findByUserId')
+ ->with('user')
+ ->willReturn($absence);
+ $this->absenceMapper->expects(self::once())
+ ->method('update')
+ ->willReturnCallback(static function (Absence $absence): Absence {
+ self::assertEquals('2023-01-05', $absence->getFirstDay());
+ self::assertEquals('2023-01-10', $absence->getLastDay());
+ self::assertEquals('status', $absence->getStatus());
+ self::assertEquals('message', $absence->getMessage());
+ return $absence;
+ });
+ $this->timezoneService->expects(self::once())
+ ->method('getUserTimezone')
+ ->with('user')
+ ->willReturn('Europe/Berlin');
+ $this->eventDispatcher->expects(self::once())
+ ->method('dispatchTyped')
+ ->with(self::callback(static function (Event $event) use ($user, $tz): bool {
+ self::assertInstanceOf(OutOfOfficeChangedEvent::class, $event);
+ /** @var OutOfOfficeChangedEvent $event */
+ $data = $event->getData();
+ self::assertEquals('1', $data->getId());
+ self::assertEquals($user, $data->getUser());
+ self::assertEquals(
+ (new DateTimeImmutable('2023-01-05', $tz))->getTimeStamp(),
+ $data->getStartDate(),
+ );
+ self::assertEquals(
+ (new DateTimeImmutable('2023-01-10', $tz))->getTimeStamp() + 3600 * 23 + 59 * 60,
+ $data->getEndDate(),
+ );
+ self::assertEquals('status', $data->getShortMessage());
+ self::assertEquals('message', $data->getMessage());
+ return true;
+ }));
+ $this->timeFactory->expects(self::once())
+ ->method('getTime')
+ ->willReturn(PHP_INT_MAX);
+ $this->jobList->expects(self::never())
+ ->method('scheduleAfter');
+
+ $this->absenceService->createOrUpdateAbsence(
+ $user,
+ '2023-01-05',
+ '2023-01-10',
+ 'status',
+ 'message',
+ );
+ }
+
+ public function testCreateAbsenceSchedulesBothJobs(): void {
+ $tz = new DateTimeZone('Europe/Berlin');
+ $startDateString = '2023-01-05';
+ $startDate = new DateTimeImmutable($startDateString, $tz);
+ $endDateString = '2023-01-10';
+ $endDate = new DateTimeImmutable($endDateString, $tz);
+ $user = $this->createMock(IUser::class);
+ $user->method('getUID')
+ ->willReturn('user');
+
+ $this->absenceMapper->expects(self::once())
+ ->method('findByUserId')
+ ->with('user')
+ ->willThrowException(new DoesNotExistException('foo bar'));
+ $this->absenceMapper->expects(self::once())
+ ->method('insert')
+ ->willReturnCallback(function (Absence $absence): Absence {
+ $absence->setId(1);
+ return $absence;
+ });
+ $this->timezoneService->expects(self::once())
+ ->method('getUserTimezone')
+ ->with('user')
+ ->willReturn($tz->getName());
+ $this->timeFactory->expects(self::once())
+ ->method('getTime')
+ ->willReturn((new DateTimeImmutable('2023-01-01', $tz))->getTimestamp());
+ $this->jobList->expects(self::exactly(2))
+ ->method('scheduleAfter')
+ ->willReturnMap([
+ [OutOfOfficeEventDispatcherJob::class, $startDate->getTimestamp(), [
+ 'id' => '1',
+ 'event' => OutOfOfficeEventDispatcherJob::EVENT_START,
+ ]],
+ [OutOfOfficeEventDispatcherJob::class, $endDate->getTimestamp() + 3600 * 23 + 59 * 60, [
+ 'id' => '1',
+ 'event' => OutOfOfficeEventDispatcherJob::EVENT_END,
+ ]],
+ ]);
+
+ $this->absenceService->createOrUpdateAbsence(
+ $user,
+ $startDateString,
+ $endDateString,
+ '',
+ '',
+ );
+ }
+
+ public function testCreateAbsenceSchedulesOnlyEndJob(): void {
+ $tz = new DateTimeZone('Europe/Berlin');
+ $endDateString = '2023-01-10';
+ $endDate = new DateTimeImmutable($endDateString, $tz);
+ $user = $this->createMock(IUser::class);
+ $user->method('getUID')
+ ->willReturn('user');
+
+ $this->absenceMapper->expects(self::once())
+ ->method('findByUserId')
+ ->with('user')
+ ->willThrowException(new DoesNotExistException('foo bar'));
+ $this->absenceMapper->expects(self::once())
+ ->method('insert')
+ ->willReturnCallback(function (Absence $absence): Absence {
+ $absence->setId(1);
+ return $absence;
+ });
+ $this->timezoneService->expects(self::once())
+ ->method('getUserTimezone')
+ ->with('user')
+ ->willReturn($tz->getName());
+ $this->timeFactory->expects(self::once())
+ ->method('getTime')
+ ->willReturn((new DateTimeImmutable('2023-01-07', $tz))->getTimestamp());
+ $this->jobList->expects(self::once())
+ ->method('scheduleAfter')
+ ->with(OutOfOfficeEventDispatcherJob::class, $endDate->getTimestamp() + 3600 * 23 + 59 * 60, [
+ 'id' => '1',
+ 'event' => OutOfOfficeEventDispatcherJob::EVENT_END,
+ ]);
+
+ $this->absenceService->createOrUpdateAbsence(
+ $user,
+ '2023-01-05',
+ $endDateString,
+ '',
+ '',
+ );
+ }
+
+ public function testCreateAbsenceSchedulesNoJob(): void {
+ $tz = new DateTimeZone('Europe/Berlin');
+ $user = $this->createMock(IUser::class);
+ $user->method('getUID')
+ ->willReturn('user');
+
+ $this->absenceMapper->expects(self::once())
+ ->method('findByUserId')
+ ->with('user')
+ ->willThrowException(new DoesNotExistException('foo bar'));
+ $this->absenceMapper->expects(self::once())
+ ->method('insert')
+ ->willReturnCallback(function (Absence $absence): Absence {
+ $absence->setId(1);
+ return $absence;
+ });
+ $this->timezoneService->expects(self::once())
+ ->method('getUserTimezone')
+ ->with('user')
+ ->willReturn($tz->getName());
+ $this->timeFactory->expects(self::once())
+ ->method('getTime')
+ ->willReturn((new DateTimeImmutable('2023-01-12', $tz))->getTimestamp());
+ $this->jobList->expects(self::never())
+ ->method('scheduleAfter');
+
+ $this->absenceService->createOrUpdateAbsence(
+ $user,
+ '2023-01-05',
+ '2023-01-10',
+ '',
+ '',
+ );
+ }
+
+ public function testUpdateAbsenceSchedulesBothJobs(): void {
+ $tz = new DateTimeZone('Europe/Berlin');
+ $startDateString = '2023-01-05';
+ $startDate = new DateTimeImmutable($startDateString, $tz);
+ $endDateString = '2023-01-10';
+ $endDate = new DateTimeImmutable($endDateString, $tz);
+ $user = $this->createMock(IUser::class);
+ $user->method('getUID')
+ ->willReturn('user');
+ $absence = new Absence();
+ $absence->setId(1);
+ $absence->setFirstDay('1970-01-01');
+ $absence->setLastDay('1970-01-10');
+ $absence->setStatus('old status');
+ $absence->setMessage('old message');
+
+ $this->absenceMapper->expects(self::once())
+ ->method('findByUserId')
+ ->with('user')
+ ->willReturn($absence);
+ $this->absenceMapper->expects(self::once())
+ ->method('update')
+ ->willReturnCallback(static function (Absence $absence) use ($startDateString, $endDateString): Absence {
+ self::assertEquals($startDateString, $absence->getFirstDay());
+ self::assertEquals($endDateString, $absence->getLastDay());
+ return $absence;
+ });
+ $this->timezoneService->expects(self::once())
+ ->method('getUserTimezone')
+ ->with('user')
+ ->willReturn($tz->getName());
+ $this->timeFactory->expects(self::once())
+ ->method('getTime')
+ ->willReturn((new DateTimeImmutable('2023-01-01', $tz))->getTimestamp());
+ $this->jobList->expects(self::exactly(2))
+ ->method('scheduleAfter')
+ ->willReturnMap([
+ [OutOfOfficeEventDispatcherJob::class, $startDate->getTimestamp(), [
+ 'id' => '1',
+ 'event' => OutOfOfficeEventDispatcherJob::EVENT_START,
+ ]],
+ [OutOfOfficeEventDispatcherJob::class, $endDate->getTimestamp() + 3600 * 23 + 59 * 60, [
+ 'id' => '1',
+ 'event' => OutOfOfficeEventDispatcherJob::EVENT_END,
+ ]],
+ ]);
+
+ $this->absenceService->createOrUpdateAbsence(
+ $user,
+ $startDateString,
+ $endDateString,
+ '',
+ '',
+ );
+ }
+
+ public function testUpdateSchedulesOnlyEndJob(): void {
+ $tz = new DateTimeZone('Europe/Berlin');
+ $endDateString = '2023-01-10';
+ $endDate = new DateTimeImmutable($endDateString, $tz);
+ $user = $this->createMock(IUser::class);
+ $user->method('getUID')
+ ->willReturn('user');
+ $absence = new Absence();
+ $absence->setId(1);
+ $absence->setFirstDay('1970-01-01');
+ $absence->setLastDay('1970-01-10');
+ $absence->setStatus('old status');
+ $absence->setMessage('old message');
+
+ $this->absenceMapper->expects(self::once())
+ ->method('findByUserId')
+ ->with('user')
+ ->willReturn($absence);
+ $this->absenceMapper->expects(self::once())
+ ->method('update')
+ ->willReturnCallback(static function (Absence $absence) use ($endDateString): Absence {
+ self::assertEquals('2023-01-05', $absence->getFirstDay());
+ self::assertEquals($endDateString, $absence->getLastDay());
+ return $absence;
+ });
+ $this->timezoneService->expects(self::once())
+ ->method('getUserTimezone')
+ ->with('user')
+ ->willReturn($tz->getName());
+ $this->timeFactory->expects(self::once())
+ ->method('getTime')
+ ->willReturn((new DateTimeImmutable('2023-01-07', $tz))->getTimestamp());
+ $this->jobList->expects(self::once())
+ ->method('scheduleAfter')
+ ->with(OutOfOfficeEventDispatcherJob::class, $endDate->getTimestamp() + 23 * 3600 + 59 * 60, [
+ 'id' => '1',
+ 'event' => OutOfOfficeEventDispatcherJob::EVENT_END,
+ ]);
+
+ $this->absenceService->createOrUpdateAbsence(
+ $user,
+ '2023-01-05',
+ $endDateString,
+ '',
+ '',
+ );
+ }
+
+ public function testUpdateAbsenceSchedulesNoJob(): void {
+ $tz = new DateTimeZone('Europe/Berlin');
+ $user = $this->createMock(IUser::class);
+ $user->method('getUID')
+ ->willReturn('user');
+ $absence = new Absence();
+ $absence->setId(1);
+ $absence->setFirstDay('1970-01-01');
+ $absence->setLastDay('1970-01-10');
+ $absence->setStatus('old status');
+ $absence->setMessage('old message');
+
+ $this->absenceMapper->expects(self::once())
+ ->method('findByUserId')
+ ->with('user')
+ ->willReturn($absence);
+ $this->absenceMapper->expects(self::once())
+ ->method('update')
+ ->willReturnCallback(static function (Absence $absence): Absence {
+ self::assertEquals('2023-01-05', $absence->getFirstDay());
+ self::assertEquals('2023-01-10', $absence->getLastDay());
+ return $absence;
+ });
+ $this->timezoneService->expects(self::once())
+ ->method('getUserTimezone')
+ ->with('user')
+ ->willReturn($tz->getName());
+ $this->timeFactory->expects(self::once())
+ ->method('getTime')
+ ->willReturn((new DateTimeImmutable('2023-01-12', $tz))->getTimestamp());
+ $this->jobList->expects(self::never())
+ ->method('scheduleAfter');
+
+ $this->absenceService->createOrUpdateAbsence(
+ $user,
+ '2023-01-05',
+ '2023-01-10',
+ '',
+ '',
+ );
+ }
+}
diff --git a/apps/dav/tests/unit/Service/ExampleContactServiceTest.php b/apps/dav/tests/unit/Service/ExampleContactServiceTest.php
new file mode 100644
index 00000000000..027b66a6fb2
--- /dev/null
+++ b/apps/dav/tests/unit/Service/ExampleContactServiceTest.php
@@ -0,0 +1,194 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\DAV\Tests\unit\Service;
+
+use OCA\DAV\CardDAV\CardDavBackend;
+use OCA\DAV\Service\ExampleContactService;
+use OCP\App\IAppManager;
+use OCP\AppFramework\Services\IAppConfig;
+use OCP\Files\AppData\IAppDataFactory;
+use OCP\Files\IAppData;
+use OCP\Files\NotFoundException;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\Files\SimpleFS\ISimpleFolder;
+use PHPUnit\Framework\MockObject\MockObject;
+use Psr\Log\LoggerInterface;
+use Symfony\Component\Uid\Uuid;
+use Test\TestCase;
+
+class ExampleContactServiceTest extends TestCase {
+ protected ExampleContactService $service;
+ protected CardDavBackend&MockObject $cardDav;
+ protected IAppManager&MockObject $appManager;
+ protected IAppDataFactory&MockObject $appDataFactory;
+ protected LoggerInterface&MockObject $logger;
+ protected IAppConfig&MockObject $appConfig;
+ protected IAppData&MockObject $appData;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->cardDav = $this->createMock(CardDavBackend::class);
+ $this->appDataFactory = $this->createMock(IAppDataFactory::class);
+ $this->logger = $this->createMock(LoggerInterface::class);
+ $this->appConfig = $this->createMock(IAppConfig::class);
+
+ $this->appData = $this->createMock(IAppData::class);
+ $this->appDataFactory->method('get')
+ ->with('dav')
+ ->willReturn($this->appData);
+
+ $this->service = new ExampleContactService(
+ $this->appDataFactory,
+ $this->appConfig,
+ $this->logger,
+ $this->cardDav,
+ );
+ }
+
+ public function testCreateDefaultContactWithInvalidCard(): void {
+ // Invalid vCard missing required FN property
+ $vcardContent = "BEGIN:VCARD\nVERSION:3.0\nEND:VCARD";
+ $this->appConfig->method('getAppValueBool')
+ ->with('enableDefaultContact', true)
+ ->willReturn(true);
+ $folder = $this->createMock(ISimpleFolder::class);
+ $file = $this->createMock(ISimpleFile::class);
+ $file->method('getContent')->willReturn($vcardContent);
+ $folder->method('getFile')->willReturn($file);
+ $this->appData->method('getFolder')->willReturn($folder);
+
+ $this->logger->expects($this->once())
+ ->method('error')
+ ->with('Default contact is invalid', $this->anything());
+
+ $this->cardDav->expects($this->never())
+ ->method('createCard');
+
+ $this->service->createDefaultContact(123);
+ }
+
+ public function testUidAndRevAreUpdated(): void {
+ $originalUid = 'original-uid';
+ $originalRev = '20200101T000000Z';
+ $vcardContent = "BEGIN:VCARD\nVERSION:3.0\nFN:Test User\nUID:$originalUid\nREV:$originalRev\nEND:VCARD";
+
+ $this->appConfig->method('getAppValueBool')
+ ->with('enableDefaultContact', true)
+ ->willReturn(true);
+ $folder = $this->createMock(ISimpleFolder::class);
+ $file = $this->createMock(ISimpleFile::class);
+ $file->method('getContent')->willReturn($vcardContent);
+ $folder->method('getFile')->willReturn($file);
+ $this->appData->method('getFolder')->willReturn($folder);
+
+ $capturedCardData = null;
+ $this->cardDav->expects($this->once())
+ ->method('createCard')
+ ->with(
+ $this->anything(),
+ $this->anything(),
+ $this->callback(function ($cardData) use (&$capturedCardData) {
+ $capturedCardData = $cardData;
+ return true;
+ }),
+ $this->anything()
+ )->willReturn(null);
+
+ $this->service->createDefaultContact(123);
+
+ $vcard = \Sabre\VObject\Reader::read($capturedCardData);
+ $this->assertNotEquals($originalUid, $vcard->UID->getValue());
+ $this->assertTrue(Uuid::isValid($vcard->UID->getValue()));
+ $this->assertNotEquals($originalRev, $vcard->REV->getValue());
+ }
+
+ public function testDefaultContactFileDoesNotExist(): void {
+ $this->appConfig->method('getAppValueBool')
+ ->with('enableDefaultContact', true)
+ ->willReturn(true);
+ $this->appData->method('getFolder')->willThrowException(new NotFoundException());
+
+ $this->cardDav->expects($this->never())
+ ->method('createCard');
+
+ $this->service->createDefaultContact(123);
+ }
+
+ public function testUidAndRevAreAddedIfMissing(): void {
+ $vcardContent = "BEGIN:VCARD\nVERSION:3.0\nFN:Test User\nEND:VCARD";
+
+ $this->appConfig->method('getAppValueBool')
+ ->with('enableDefaultContact', true)
+ ->willReturn(true);
+ $folder = $this->createMock(ISimpleFolder::class);
+ $file = $this->createMock(ISimpleFile::class);
+ $file->method('getContent')->willReturn($vcardContent);
+ $folder->method('getFile')->willReturn($file);
+ $this->appData->method('getFolder')->willReturn($folder);
+
+ $capturedCardData = 'new-card-data';
+
+ $this->cardDav
+ ->expects($this->once())
+ ->method('createCard')
+ ->with(
+ $this->anything(),
+ $this->anything(),
+ $this->callback(function ($cardData) use (&$capturedCardData) {
+ $capturedCardData = $cardData;
+ return true;
+ }),
+ $this->anything()
+ );
+
+ $this->service->createDefaultContact(123);
+ $vcard = \Sabre\VObject\Reader::read($capturedCardData);
+
+ $this->assertNotNull($vcard->REV);
+ $this->assertNotNull($vcard->UID);
+ $this->assertTrue(Uuid::isValid($vcard->UID->getValue()));
+ }
+
+ public function testDefaultContactIsNotCreatedIfEnabled(): void {
+ $this->appConfig->method('getAppValueBool')
+ ->with('enableDefaultContact', true)
+ ->willReturn(false);
+ $this->logger->expects($this->never())
+ ->method('error');
+ $this->cardDav->expects($this->never())
+ ->method('createCard');
+
+ $this->service->createDefaultContact(123);
+ }
+
+ public static function provideDefaultContactEnableData(): array {
+ return [[true], [false]];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('provideDefaultContactEnableData')]
+ public function testIsDefaultContactEnabled(bool $enabled): void {
+ $this->appConfig->expects(self::once())
+ ->method('getAppValueBool')
+ ->with('enableDefaultContact', true)
+ ->willReturn($enabled);
+
+ $this->assertEquals($enabled, $this->service->isDefaultContactEnabled());
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('provideDefaultContactEnableData')]
+ public function testSetDefaultContactEnabled(bool $enabled): void {
+ $this->appConfig->expects(self::once())
+ ->method('setAppValueBool')
+ ->with('enableDefaultContact', $enabled);
+
+ $this->service->setDefaultContactEnabled($enabled);
+ }
+}
diff --git a/apps/dav/tests/unit/Service/ExampleEventServiceTest.php b/apps/dav/tests/unit/Service/ExampleEventServiceTest.php
new file mode 100644
index 00000000000..0f423624fb8
--- /dev/null
+++ b/apps/dav/tests/unit/Service/ExampleEventServiceTest.php
@@ -0,0 +1,196 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\DAV\Tests\unit\Service;
+
+use OCA\DAV\CalDAV\CalDavBackend;
+use OCA\DAV\Service\ExampleEventService;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\Files\IAppData;
+use OCP\Files\NotFoundException;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\Files\SimpleFS\ISimpleFolder;
+use OCP\IAppConfig;
+use OCP\IL10N;
+use OCP\Security\ISecureRandom;
+use PHPUnit\Framework\MockObject\MockObject;
+use Test\TestCase;
+
+class ExampleEventServiceTest extends TestCase {
+ private ExampleEventService $service;
+
+ private CalDavBackend&MockObject $calDavBackend;
+ private ISecureRandom&MockObject $random;
+ private ITimeFactory&MockObject $time;
+ private IAppData&MockObject $appData;
+ private IAppConfig&MockObject $appConfig;
+ private IL10N&MockObject $l10n;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->calDavBackend = $this->createMock(CalDavBackend::class);
+ $this->random = $this->createMock(ISecureRandom::class);
+ $this->time = $this->createMock(ITimeFactory::class);
+ $this->appData = $this->createMock(IAppData::class);
+ $this->appConfig = $this->createMock(IAppConfig::class);
+ $this->l10n = $this->createMock(IL10N::class);
+
+ $this->l10n->method('t')
+ ->willReturnArgument(0);
+
+ $this->service = new ExampleEventService(
+ $this->calDavBackend,
+ $this->random,
+ $this->time,
+ $this->appData,
+ $this->appConfig,
+ $this->l10n,
+ );
+ }
+
+ public static function provideCustomEventData(): array {
+ return [
+ [file_get_contents(__DIR__ . '/../test_fixtures/example-event.ics')],
+ [file_get_contents(__DIR__ . '/../test_fixtures/example-event-with-attendees.ics')],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('provideCustomEventData')]
+ public function testCreateExampleEventWithCustomEvent($customEventIcs): void {
+ $this->appConfig->expects(self::once())
+ ->method('getValueBool')
+ ->with('dav', 'create_example_event', true)
+ ->willReturn(true);
+
+ $exampleEventFolder = $this->createMock(ISimpleFolder::class);
+ $this->appData->expects(self::once())
+ ->method('getFolder')
+ ->with('example_event')
+ ->willReturn($exampleEventFolder);
+ $exampleEventFile = $this->createMock(ISimpleFile::class);
+ $exampleEventFolder->expects(self::once())
+ ->method('getFile')
+ ->with('example_event.ics')
+ ->willReturn($exampleEventFile);
+ $exampleEventFile->expects(self::once())
+ ->method('getContent')
+ ->willReturn($customEventIcs);
+
+ $this->random->expects(self::once())
+ ->method('generate')
+ ->with(32, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')
+ ->willReturn('RANDOM-UID');
+
+ $now = new \DateTimeImmutable('2025-01-21T00:00:00Z');
+ $this->time->expects(self::exactly(2))
+ ->method('now')
+ ->willReturn($now);
+
+ $expectedIcs = file_get_contents(__DIR__ . '/../test_fixtures/example-event-expected.ics');
+ $this->calDavBackend->expects(self::once())
+ ->method('createCalendarObject')
+ ->with(1000, 'RANDOM-UID.ics', $expectedIcs);
+
+ $this->service->createExampleEvent(1000);
+ }
+
+ public function testCreateExampleEventWithDefaultEvent(): void {
+ $this->appConfig->expects(self::once())
+ ->method('getValueBool')
+ ->with('dav', 'create_example_event', true)
+ ->willReturn(true);
+
+ $this->appData->expects(self::once())
+ ->method('getFolder')
+ ->with('example_event')
+ ->willThrowException(new NotFoundException());
+
+ $this->random->expects(self::once())
+ ->method('generate')
+ ->with(32, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')
+ ->willReturn('RANDOM-UID');
+
+ $now = new \DateTimeImmutable('2025-01-21T00:00:00Z');
+ $this->time->expects(self::exactly(3))
+ ->method('now')
+ ->willReturn($now);
+
+ $expectedIcs = file_get_contents(__DIR__ . '/../test_fixtures/example-event-default-expected.ics');
+ $this->calDavBackend->expects(self::once())
+ ->method('createCalendarObject')
+ ->with(1000, 'RANDOM-UID.ics', $expectedIcs);
+
+ $this->service->createExampleEvent(1000);
+ }
+
+ public function testCreateExampleWhenDisabled(): void {
+ $this->appConfig->expects(self::once())
+ ->method('getValueBool')
+ ->with('dav', 'create_example_event', true)
+ ->willReturn(false);
+
+ $this->calDavBackend->expects(self::never())
+ ->method('createCalendarObject');
+
+ $this->service->createExampleEvent(1000);
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('provideCustomEventData')]
+ public function testGetExampleEventWithCustomEvent($customEventIcs): void {
+ $exampleEventFolder = $this->createMock(ISimpleFolder::class);
+ $this->appData->expects(self::once())
+ ->method('getFolder')
+ ->with('example_event')
+ ->willReturn($exampleEventFolder);
+ $exampleEventFile = $this->createMock(ISimpleFile::class);
+ $exampleEventFolder->expects(self::once())
+ ->method('getFile')
+ ->with('example_event.ics')
+ ->willReturn($exampleEventFile);
+ $exampleEventFile->expects(self::once())
+ ->method('getContent')
+ ->willReturn($customEventIcs);
+
+ $this->random->expects(self::once())
+ ->method('generate')
+ ->with(32, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')
+ ->willReturn('RANDOM-UID');
+
+ $now = new \DateTimeImmutable('2025-01-21T00:00:00Z');
+ $this->time->expects(self::exactly(2))
+ ->method('now')
+ ->willReturn($now);
+
+ $expectedIcs = file_get_contents(__DIR__ . '/../test_fixtures/example-event-expected.ics');
+ $actualIcs = $this->service->getExampleEvent()->getIcs();
+ $this->assertEquals($expectedIcs, $actualIcs);
+ }
+
+ public function testGetExampleEventWithDefault(): void {
+ $this->appData->expects(self::once())
+ ->method('getFolder')
+ ->with('example_event')
+ ->willThrowException(new NotFoundException());
+
+ $this->random->expects(self::once())
+ ->method('generate')
+ ->with(32, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')
+ ->willReturn('RANDOM-UID');
+
+ $now = new \DateTimeImmutable('2025-01-21T00:00:00Z');
+ $this->time->expects(self::exactly(3))
+ ->method('now')
+ ->willReturn($now);
+
+ $expectedIcs = file_get_contents(__DIR__ . '/../test_fixtures/example-event-default-expected.ics');
+ $actualIcs = $this->service->getExampleEvent()->getIcs();
+ $this->assertEquals($expectedIcs, $actualIcs);
+ }
+}
diff --git a/apps/dav/tests/unit/Service/UpcomingEventsServiceTest.php b/apps/dav/tests/unit/Service/UpcomingEventsServiceTest.php
new file mode 100644
index 00000000000..fdfe37d8918
--- /dev/null
+++ b/apps/dav/tests/unit/Service/UpcomingEventsServiceTest.php
@@ -0,0 +1,89 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\DAV\Tests\unit\DAV\Service;
+
+use DateTimeImmutable;
+use OCA\DAV\CalDAV\UpcomingEventsService;
+use OCP\App\IAppManager;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\Calendar\ICalendarQuery;
+use OCP\Calendar\IManager;
+use OCP\IURLGenerator;
+use OCP\IUserManager;
+use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+
+class UpcomingEventsServiceTest extends TestCase {
+
+ private IManager&MockObject $calendarManager;
+ private ITimeFactory&MockObject $timeFactory;
+ private IUserManager&MockObject $userManager;
+ private IAppManager&MockObject $appManager;
+ private IURLGenerator&MockObject $urlGenerator;
+ private UpcomingEventsService $service;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->calendarManager = $this->createMock(IManager::class);
+ $this->timeFactory = $this->createMock(ITimeFactory::class);
+ $this->userManager = $this->createMock(IUserManager::class);
+ $this->appManager = $this->createMock(IAppManager::class);
+ $this->urlGenerator = $this->createMock(IURLGenerator::class);
+
+ $this->service = new UpcomingEventsService(
+ $this->calendarManager,
+ $this->timeFactory,
+ $this->userManager,
+ $this->appManager,
+ $this->urlGenerator,
+ );
+ }
+
+ public function testGetEventsByLocation(): void {
+ $now = new DateTimeImmutable('2024-07-08T18:20:20Z');
+ $this->timeFactory->method('now')
+ ->willReturn($now);
+ $query = $this->createMock(ICalendarQuery::class);
+ $this->appManager->method('isEnabledForUser')->willReturn(false);
+ $this->calendarManager->method('newQuery')
+ ->with('principals/users/user1')
+ ->willReturn($query);
+ $query->expects(self::once())
+ ->method('addSearchProperty')
+ ->with('LOCATION');
+ $query->expects(self::once())
+ ->method('setSearchPattern')
+ ->with('https://cloud.example.com/call/123');
+ $this->calendarManager->expects(self::once())
+ ->method('searchForPrincipal')
+ ->with($query)
+ ->willReturn([
+ [
+ 'uri' => 'ev1',
+ 'calendar-key' => '1',
+ 'calendar-uri' => 'personal',
+ 'objects' => [
+ 0 => [
+ 'DTSTART' => [
+ new DateTimeImmutable('now'),
+ ],
+ ],
+ ],
+ ],
+ ]);
+
+ $events = $this->service->getEvents('user1', 'https://cloud.example.com/call/123');
+
+ self::assertCount(1, $events);
+ $event1 = $events[0];
+ self::assertEquals('ev1', $event1->getUri());
+ }
+}