aboutsummaryrefslogtreecommitdiffstats
path: root/apps/comments/tests/Unit
diff options
context:
space:
mode:
Diffstat (limited to 'apps/comments/tests/Unit')
-rw-r--r--apps/comments/tests/Unit/Activity/ListenerTest.php159
-rw-r--r--apps/comments/tests/Unit/AppInfo/ApplicationTest.php62
-rw-r--r--apps/comments/tests/Unit/Collaboration/CommentersSorterTest.php136
-rw-r--r--apps/comments/tests/Unit/Controller/NotificationsTest.php214
-rw-r--r--apps/comments/tests/Unit/EventHandlerTest.php87
-rw-r--r--apps/comments/tests/Unit/Notification/ListenerTest.php195
-rw-r--r--apps/comments/tests/Unit/Notification/NotifierTest.php554
7 files changed, 1407 insertions, 0 deletions
diff --git a/apps/comments/tests/Unit/Activity/ListenerTest.php b/apps/comments/tests/Unit/Activity/ListenerTest.php
new file mode 100644
index 00000000000..675a28a16b1
--- /dev/null
+++ b/apps/comments/tests/Unit/Activity/ListenerTest.php
@@ -0,0 +1,159 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Comments\Tests\Unit\Activity;
+
+use OCA\Comments\Activity\Listener;
+use OCP\Activity\IEvent;
+use OCP\Activity\IManager;
+use OCP\App\IAppManager;
+use OCP\Comments\CommentsEvent;
+use OCP\Comments\IComment;
+use OCP\Files\Config\ICachedMountFileInfo;
+use OCP\Files\Config\IMountProviderCollection;
+use OCP\Files\Config\IUserMountCache;
+use OCP\Files\Folder;
+use OCP\Files\IRootFolder;
+use OCP\Files\Node;
+use OCP\IUser;
+use OCP\IUserSession;
+use OCP\Share\IShareHelper;
+use PHPUnit\Framework\MockObject\MockObject;
+use Test\TestCase;
+
+class ListenerTest extends TestCase {
+ protected IManager&MockObject $activityManager;
+ protected IUserSession&MockObject $session;
+ protected IAppManager&MockObject $appManager;
+ protected IMountProviderCollection&MockObject $mountProviderCollection;
+ protected IRootFolder&MockObject $rootFolder;
+ protected IShareHelper&MockObject $shareHelper;
+ protected Listener $listener;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->activityManager = $this->createMock(IManager::class);
+ $this->session = $this->createMock(IUserSession::class);
+ $this->appManager = $this->createMock(IAppManager::class);
+ $this->mountProviderCollection = $this->createMock(IMountProviderCollection::class);
+ $this->rootFolder = $this->createMock(IRootFolder::class);
+ $this->shareHelper = $this->createMock(IShareHelper::class);
+
+ $this->listener = new Listener(
+ $this->activityManager,
+ $this->session,
+ $this->appManager,
+ $this->mountProviderCollection,
+ $this->rootFolder,
+ $this->shareHelper
+ );
+ }
+
+ public function testCommentEvent(): void {
+ $this->appManager->expects($this->any())
+ ->method('isEnabledForAnyone')
+ ->with('activity')
+ ->willReturn(true);
+
+ $comment = $this->createMock(IComment::class);
+ $comment->expects($this->any())
+ ->method('getObjectType')
+ ->willReturn('files');
+
+ /** @var CommentsEvent|MockObject $event */
+ $event = $this->createMock(CommentsEvent::class);
+ $event->expects($this->any())
+ ->method('getComment')
+ ->willReturn($comment);
+ $event->expects($this->any())
+ ->method('getEvent')
+ ->willReturn(CommentsEvent::EVENT_ADD);
+
+ /** @var IUser|MockObject $ownerUser */
+ $ownerUser = $this->createMock(IUser::class);
+ $ownerUser->expects($this->any())
+ ->method('getUID')
+ ->willReturn('937393');
+
+ /** @var MockObject $mount */
+ $mount = $this->createMock(ICachedMountFileInfo::class);
+ $mount->expects($this->any())
+ ->method('getUser')
+ ->willReturn($ownerUser); // perhaps not the right user, but does not matter in this scenario
+
+ $mounts = [ $mount, $mount ]; // to make sure duplicates are dealt with
+
+ $userMountCache = $this->createMock(IUserMountCache::class);
+ $userMountCache->expects($this->any())
+ ->method('getMountsForFileId')
+ ->willReturn($mounts);
+
+ $this->mountProviderCollection->expects($this->any())
+ ->method('getMountCache')
+ ->willReturn($userMountCache);
+
+ $node = $this->createMock(Node::class);
+ $nodes = [ $node ];
+
+ $ownerFolder = $this->createMock(Folder::class);
+ $ownerFolder->expects($this->any())
+ ->method('getById')
+ ->willReturn($nodes);
+
+ $this->rootFolder->expects($this->any())
+ ->method('getUserFolder')
+ ->willReturn($ownerFolder);
+
+ $al = [ 'users' => [
+ '873304' => 'i/got/it/here',
+ '254342' => 'there/i/have/it',
+ 'sandra' => 'and/here/i/placed/it'
+ ]];
+ $this->shareHelper->expects($this->any())
+ ->method('getPathsForAccessList')
+ ->willReturn($al);
+
+ $this->session->expects($this->any())
+ ->method('getUser')
+ ->willReturn($ownerUser);
+
+ /** @var MockObject $activity */
+ $activity = $this->createMock(IEvent::class);
+ $activity->expects($this->exactly(count($al['users'])))
+ ->method('setAffectedUser');
+ $activity->expects($this->once())
+ ->method('setApp')
+ ->with('comments')
+ ->willReturnSelf();
+ $activity->expects($this->once())
+ ->method('setType')
+ ->with('comments')
+ ->willReturnSelf();
+ $activity->expects($this->once())
+ ->method('setAuthor')
+ ->with($ownerUser->getUID())
+ ->willReturnSelf();
+ $activity->expects($this->once())
+ ->method('setObject')
+ ->with('files', $this->anything())
+ ->willReturnSelf();
+ $activity->expects($this->once())
+ ->method('setMessage')
+ ->with('add_comment_message', $this->anything())
+ ->willReturnSelf();
+
+ $this->activityManager->expects($this->once())
+ ->method('generateEvent')
+ ->willReturn($activity);
+ $this->activityManager->expects($this->exactly(count($al['users'])))
+ ->method('publish');
+
+ $this->listener->commentEvent($event);
+ }
+}
diff --git a/apps/comments/tests/Unit/AppInfo/ApplicationTest.php b/apps/comments/tests/Unit/AppInfo/ApplicationTest.php
new file mode 100644
index 00000000000..119db5333b5
--- /dev/null
+++ b/apps/comments/tests/Unit/AppInfo/ApplicationTest.php
@@ -0,0 +1,62 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+namespace OCA\Comments\Tests\Unit\AppInfo;
+
+use OCA\Comments\Activity\Filter;
+use OCA\Comments\Activity\Listener;
+use OCA\Comments\Activity\Provider;
+use OCA\Comments\Activity\Setting;
+use OCA\Comments\AppInfo\Application;
+use OCA\Comments\Controller\NotificationsController;
+use OCA\Comments\Notification\Notifier;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use OCP\Server;
+use Test\TestCase;
+
+/**
+ * Class ApplicationTest
+ *
+ * @group DB
+ *
+ * @package OCA\Comments\Tests\Unit\AppInfo
+ */
+class ApplicationTest extends TestCase {
+ protected function setUp(): void {
+ parent::setUp();
+ Server::get(IUserManager::class)->createUser('dummy', '456');
+ Server::get(IUserSession::class)->setUser(Server::get(IUserManager::class)->get('dummy'));
+ }
+
+ protected function tearDown(): void {
+ Server::get(IUserManager::class)->get('dummy')->delete();
+ parent::tearDown();
+ }
+
+ public function test(): void {
+ $app = new Application();
+ $c = $app->getContainer();
+
+ $services = [
+ NotificationsController::class,
+ Filter::class,
+ Listener::class,
+ Provider::class,
+ Setting::class,
+ \OCA\Comments\Notification\Listener::class,
+ Notifier::class,
+ ];
+
+ foreach ($services as $service) {
+ $s = $c->get($service);
+ $this->assertInstanceOf($service, $s);
+ }
+ }
+}
diff --git a/apps/comments/tests/Unit/Collaboration/CommentersSorterTest.php b/apps/comments/tests/Unit/Collaboration/CommentersSorterTest.php
new file mode 100644
index 00000000000..4d3392a562d
--- /dev/null
+++ b/apps/comments/tests/Unit/Collaboration/CommentersSorterTest.php
@@ -0,0 +1,136 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Comments\Tests\Unit\Collaboration;
+
+use OCA\Comments\Collaboration\CommentersSorter;
+use OCP\Comments\IComment;
+use OCP\Comments\ICommentsManager;
+use PHPUnit\Framework\MockObject\MockObject;
+use Test\TestCase;
+
+class CommentersSorterTest extends TestCase {
+ protected ICommentsManager&MockObject $commentsManager;
+ protected CommentersSorter $sorter;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->commentsManager = $this->createMock(ICommentsManager::class);
+
+ $this->sorter = new CommentersSorter($this->commentsManager);
+ }
+
+ /**
+ * @param $data
+ */
+ #[\PHPUnit\Framework\Attributes\DataProvider('sortDataProvider')]
+ public function testSort($data): void {
+ $commentMocks = [];
+ foreach ($data['actors'] as $actorType => $actors) {
+ foreach ($actors as $actorId => $noOfComments) {
+ for ($i = 0;$i < $noOfComments;$i++) {
+ $mock = $this->createMock(IComment::class);
+ $mock->expects($this->atLeastOnce())
+ ->method('getActorType')
+ ->willReturn($actorType);
+ $mock->expects($this->atLeastOnce())
+ ->method('getActorId')
+ ->willReturn($actorId);
+ $commentMocks[] = $mock;
+ }
+ }
+ }
+
+ $this->commentsManager->expects($this->once())
+ ->method('getForObject')
+ ->willReturn($commentMocks);
+
+ $workArray = $data['input'];
+ $this->sorter->sort($workArray, ['itemType' => 'files', 'itemId' => '24']);
+
+ $this->assertEquals($data['expected'], $workArray);
+ }
+
+ public static function sortDataProvider(): array {
+ return [[
+ [
+ #1 – sort properly and otherwise keep existing order
+ 'actors' => ['users' => ['celia' => 3, 'darius' => 7, 'faruk' => 5, 'gail' => 5], 'bots' => ['r2-d2' => 8]],
+ 'input' => [
+ 'users' => [
+ ['value' => ['shareWith' => 'alice']],
+ ['value' => ['shareWith' => 'bob']],
+ ['value' => ['shareWith' => 'celia']],
+ ['value' => ['shareWith' => 'darius']],
+ ['value' => ['shareWith' => 'elena']],
+ ['value' => ['shareWith' => 'faruk']],
+ ['value' => ['shareWith' => 'gail']],
+ ],
+ 'bots' => [
+ ['value' => ['shareWith' => 'c-3po']],
+ ['value' => ['shareWith' => 'r2-d2']],
+ ]
+ ],
+ 'expected' => [
+ 'users' => [
+ ['value' => ['shareWith' => 'darius']],
+ ['value' => ['shareWith' => 'faruk']],
+ ['value' => ['shareWith' => 'gail']],
+ ['value' => ['shareWith' => 'celia']],
+ ['value' => ['shareWith' => 'alice']],
+ ['value' => ['shareWith' => 'bob']],
+ ['value' => ['shareWith' => 'elena']],
+ ],
+ 'bots' => [
+ ['value' => ['shareWith' => 'r2-d2']],
+ ['value' => ['shareWith' => 'c-3po']],
+ ]
+ ],
+ ],
+ [
+ #2 – no commentors, input equals output
+ 'actors' => [],
+ 'input' => [
+ 'users' => [
+ ['value' => ['shareWith' => 'alice']],
+ ['value' => ['shareWith' => 'bob']],
+ ['value' => ['shareWith' => 'celia']],
+ ['value' => ['shareWith' => 'darius']],
+ ['value' => ['shareWith' => 'elena']],
+ ['value' => ['shareWith' => 'faruk']],
+ ['value' => ['shareWith' => 'gail']],
+ ],
+ 'bots' => [
+ ['value' => ['shareWith' => 'c-3po']],
+ ['value' => ['shareWith' => 'r2-d2']],
+ ]
+ ],
+ 'expected' => [
+ 'users' => [
+ ['value' => ['shareWith' => 'alice']],
+ ['value' => ['shareWith' => 'bob']],
+ ['value' => ['shareWith' => 'celia']],
+ ['value' => ['shareWith' => 'darius']],
+ ['value' => ['shareWith' => 'elena']],
+ ['value' => ['shareWith' => 'faruk']],
+ ['value' => ['shareWith' => 'gail']],
+ ],
+ 'bots' => [
+ ['value' => ['shareWith' => 'c-3po']],
+ ['value' => ['shareWith' => 'r2-d2']],
+ ]
+ ],
+ ],
+ [
+ #3 – no nothing
+ 'actors' => [],
+ 'input' => [],
+ 'expected' => [],
+ ],
+ ]];
+ }
+}
diff --git a/apps/comments/tests/Unit/Controller/NotificationsTest.php b/apps/comments/tests/Unit/Controller/NotificationsTest.php
new file mode 100644
index 00000000000..04490ca63e8
--- /dev/null
+++ b/apps/comments/tests/Unit/Controller/NotificationsTest.php
@@ -0,0 +1,214 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+namespace OCA\Comments\Tests\Unit\Controller;
+
+use OCA\Comments\Controller\NotificationsController;
+use OCP\AppFramework\Http\NotFoundResponse;
+use OCP\AppFramework\Http\RedirectResponse;
+use OCP\Comments\IComment;
+use OCP\Comments\ICommentsManager;
+use OCP\Comments\NotFoundException;
+use OCP\Files\Folder;
+use OCP\Files\IRootFolder;
+use OCP\Files\Node;
+use OCP\IRequest;
+use OCP\IURLGenerator;
+use OCP\IUser;
+use OCP\IUserSession;
+use OCP\Notification\IManager;
+use OCP\Notification\INotification;
+use PHPUnit\Framework\MockObject\MockObject;
+use Test\TestCase;
+
+class NotificationsTest extends TestCase {
+ protected ICommentsManager&MockObject $commentsManager;
+ protected IRootFolder&MockObject $rootFolder;
+ protected IUserSession&MockObject $session;
+ protected IManager&MockObject $notificationManager;
+ protected IURLGenerator&MockObject $urlGenerator;
+ protected NotificationsController $notificationsController;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->commentsManager = $this->createMock(ICommentsManager::class);
+ $this->rootFolder = $this->createMock(IRootFolder::class);
+ $this->session = $this->createMock(IUserSession::class);
+ $this->notificationManager = $this->createMock(IManager::class);
+ $this->urlGenerator = $this->createMock(IURLGenerator::class);
+
+ $this->notificationsController = new NotificationsController(
+ 'comments',
+ $this->createMock(IRequest::class),
+ $this->commentsManager,
+ $this->rootFolder,
+ $this->urlGenerator,
+ $this->notificationManager,
+ $this->session
+ );
+ }
+
+ public function testViewGuestRedirect(): void {
+ $this->commentsManager->expects($this->never())
+ ->method('get');
+
+ $this->rootFolder->expects($this->never())
+ ->method('getUserFolder');
+
+ $this->session->expects($this->once())
+ ->method('getUser')
+ ->willReturn(null);
+
+ $this->notificationManager->expects($this->never())
+ ->method('createNotification');
+ $this->notificationManager->expects($this->never())
+ ->method('markProcessed');
+
+ $this->urlGenerator->expects($this->exactly(2))
+ ->method('linkToRoute')
+ ->willReturnMap([
+ ['comments.Notifications.view', ['id' => '42'], 'link-to-comment'],
+ ['core.login.showLoginForm', ['redirect_url' => 'link-to-comment'], 'link-to-login'],
+ ]);
+
+ /** @var RedirectResponse $response */
+ $response = $this->notificationsController->view('42');
+ $this->assertInstanceOf(RedirectResponse::class, $response);
+ $this->assertSame('link-to-login', $response->getRedirectURL());
+ }
+
+ public function testViewSuccess(): void {
+ $comment = $this->createMock(IComment::class);
+ $comment->expects($this->any())
+ ->method('getObjectType')
+ ->willReturn('files');
+ $comment->expects($this->any())
+ ->method('getId')
+ ->willReturn('1234');
+
+ $this->commentsManager->expects($this->any())
+ ->method('get')
+ ->with('42')
+ ->willReturn($comment);
+
+ $file = $this->createMock(Node::class);
+ $folder = $this->createMock(Folder::class);
+ $user = $this->createMock(IUser::class);
+
+ $this->rootFolder->expects($this->once())
+ ->method('getUserFolder')
+ ->willReturn($folder);
+
+ $folder->expects($this->once())
+ ->method('getById')
+ ->willReturn([$file]);
+
+ $this->session->expects($this->once())
+ ->method('getUser')
+ ->willReturn($user);
+
+ $user->expects($this->any())
+ ->method('getUID')
+ ->willReturn('user');
+
+ $notification = $this->createMock(INotification::class);
+ $notification->expects($this->any())
+ ->method($this->anything())
+ ->willReturn($notification);
+
+ $this->notificationManager->expects($this->once())
+ ->method('createNotification')
+ ->willReturn($notification);
+ $this->notificationManager->expects($this->once())
+ ->method('markProcessed')
+ ->with($notification);
+
+ $response = $this->notificationsController->view('42');
+ $this->assertInstanceOf(RedirectResponse::class, $response);
+ }
+
+ public function testViewInvalidComment(): void {
+ $this->commentsManager->expects($this->any())
+ ->method('get')
+ ->with('42')
+ ->willThrowException(new NotFoundException());
+
+ $this->rootFolder->expects($this->never())
+ ->method('getUserFolder');
+
+ $user = $this->createMock(IUser::class);
+
+ $this->session->expects($this->once())
+ ->method('getUser')
+ ->willReturn($user);
+
+ $user->expects($this->any())
+ ->method('getUID')
+ ->willReturn('user');
+
+ $this->notificationManager->expects($this->never())
+ ->method('createNotification');
+ $this->notificationManager->expects($this->never())
+ ->method('markProcessed');
+
+ $response = $this->notificationsController->view('42');
+ $this->assertInstanceOf(NotFoundResponse::class, $response);
+ }
+
+ public function testViewNoFile(): void {
+ $comment = $this->createMock(IComment::class);
+ $comment->expects($this->any())
+ ->method('getObjectType')
+ ->willReturn('files');
+ $comment->expects($this->any())
+ ->method('getId')
+ ->willReturn('1234');
+
+ $this->commentsManager->expects($this->any())
+ ->method('get')
+ ->with('42')
+ ->willReturn($comment);
+
+ $folder = $this->createMock(Folder::class);
+
+ $this->rootFolder->expects($this->once())
+ ->method('getUserFolder')
+ ->willReturn($folder);
+
+ $folder->expects($this->once())
+ ->method('getById')
+ ->willReturn([]);
+
+ $user = $this->createMock(IUser::class);
+
+ $this->session->expects($this->once())
+ ->method('getUser')
+ ->willReturn($user);
+
+ $user->expects($this->any())
+ ->method('getUID')
+ ->willReturn('user');
+
+ $notification = $this->createMock(INotification::class);
+ $notification->expects($this->any())
+ ->method($this->anything())
+ ->willReturn($notification);
+
+ $this->notificationManager->expects($this->once())
+ ->method('createNotification')
+ ->willReturn($notification);
+ $this->notificationManager->expects($this->once())
+ ->method('markProcessed')
+ ->with($notification);
+
+ $response = $this->notificationsController->view('42');
+ $this->assertInstanceOf(NotFoundResponse::class, $response);
+ }
+}
diff --git a/apps/comments/tests/Unit/EventHandlerTest.php b/apps/comments/tests/Unit/EventHandlerTest.php
new file mode 100644
index 00000000000..9d26f828d70
--- /dev/null
+++ b/apps/comments/tests/Unit/EventHandlerTest.php
@@ -0,0 +1,87 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Comments\Tests\Unit\Notification;
+
+use OCA\Comments\Activity\Listener as ActivityListener;
+use OCA\Comments\Listener\CommentsEventListener;
+use OCA\Comments\Notification\Listener as NotificationListener;
+use OCP\Comments\CommentsEvent;
+use OCP\Comments\IComment;
+use PHPUnit\Framework\MockObject\MockObject;
+use Test\TestCase;
+
+class EventHandlerTest extends TestCase {
+ protected ActivityListener&MockObject $activityListener;
+ protected NotificationListener&MockObject $notificationListener;
+ protected CommentsEventListener $eventHandler;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->activityListener = $this->createMock(ActivityListener::class);
+ $this->notificationListener = $this->createMock(NotificationListener::class);
+
+ $this->eventHandler = new CommentsEventListener($this->activityListener, $this->notificationListener);
+ }
+
+ public function testNotFiles(): void {
+ /** @var IComment|MockObject $comment */
+ $comment = $this->createMock(IComment::class);
+ $comment->expects($this->once())
+ ->method('getObjectType')
+ ->willReturn('smiles');
+
+ /** @var CommentsEvent|MockObject $event */
+ $event = $this->createMock(CommentsEvent::class);
+ $event->expects($this->once())
+ ->method('getComment')
+ ->willReturn($comment);
+ $event->expects($this->never())
+ ->method('getEvent');
+
+ $this->eventHandler->handle($event);
+ }
+
+ public static function handledProvider(): array {
+ return [
+ [CommentsEvent::EVENT_DELETE],
+ [CommentsEvent::EVENT_UPDATE],
+ [CommentsEvent::EVENT_PRE_UPDATE],
+ [CommentsEvent::EVENT_ADD]
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('handledProvider')]
+ public function testHandled(string $eventType): void {
+ /** @var IComment|MockObject $comment */
+ $comment = $this->createMock(IComment::class);
+ $comment->expects($this->once())
+ ->method('getObjectType')
+ ->willReturn('files');
+
+ /** @var CommentsEvent|MockObject $event */
+ $event = $this->createMock(CommentsEvent::class);
+ $event->expects($this->atLeastOnce())
+ ->method('getComment')
+ ->willReturn($comment);
+ $event->expects($this->atLeastOnce())
+ ->method('getEvent')
+ ->willReturn($eventType);
+
+ $this->notificationListener->expects($this->once())
+ ->method('evaluate')
+ ->with($event);
+
+ $this->activityListener->expects($this->any())
+ ->method('commentEvent')
+ ->with($event);
+
+ $this->eventHandler->handle($event);
+ }
+}
diff --git a/apps/comments/tests/Unit/Notification/ListenerTest.php b/apps/comments/tests/Unit/Notification/ListenerTest.php
new file mode 100644
index 00000000000..356a26f23cd
--- /dev/null
+++ b/apps/comments/tests/Unit/Notification/ListenerTest.php
@@ -0,0 +1,195 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+namespace OCA\Comments\Tests\Unit\Notification;
+
+use OCA\Comments\Notification\Listener;
+use OCP\Comments\CommentsEvent;
+use OCP\Comments\IComment;
+use OCP\IURLGenerator;
+use OCP\IUserManager;
+use OCP\Notification\IManager;
+use OCP\Notification\INotification;
+use PHPUnit\Framework\MockObject\MockObject;
+use Test\TestCase;
+
+class ListenerTest extends TestCase {
+ protected IManager&MockObject $notificationManager;
+ protected IUserManager&MockObject $userManager;
+ protected IURLGenerator&MockObject $urlGenerator;
+ protected Listener $listener;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->notificationManager = $this->createMock(IManager::class);
+ $this->userManager = $this->createMock(IUserManager::class);
+
+ $this->listener = new Listener(
+ $this->notificationManager,
+ $this->userManager
+ );
+ }
+
+ public static function eventProvider(): array {
+ return [
+ [CommentsEvent::EVENT_ADD, 'notify'],
+ [CommentsEvent::EVENT_UPDATE, 'notify'],
+ [CommentsEvent::EVENT_PRE_UPDATE, 'markProcessed'],
+ [CommentsEvent::EVENT_DELETE, 'markProcessed']
+ ];
+ }
+
+ /**
+ * @param string $eventType
+ * @param string $notificationMethod
+ */
+ #[\PHPUnit\Framework\Attributes\DataProvider('eventProvider')]
+ public function testEvaluate($eventType, $notificationMethod): void {
+ /** @var IComment|MockObject $comment */
+ $comment = $this->createMock(IComment::class);
+ $comment->expects($this->any())
+ ->method('getObjectType')
+ ->willReturn('files');
+ $comment->expects($this->any())
+ ->method('getCreationDateTime')
+ ->willReturn(new \DateTime());
+ $comment->expects($this->once())
+ ->method('getMentions')
+ ->willReturn([
+ [ 'type' => 'user', 'id' => 'foobar'],
+ [ 'type' => 'user', 'id' => 'barfoo'],
+ [ 'type' => 'user', 'id' => 'foo@bar.com'],
+ [ 'type' => 'user', 'id' => 'bar@foo.org@foobar.io'],
+ [ 'type' => 'user', 'id' => '23452-4333-54353-2342'],
+ [ 'type' => 'user', 'id' => 'yolo'],
+ ]);
+ $comment->expects($this->atLeastOnce())
+ ->method('getId')
+ ->willReturn('1234');
+
+ /** @var CommentsEvent|MockObject $event */
+ $event = $this->createMock(CommentsEvent::class);
+ $event->expects($this->once())
+ ->method('getComment')
+ ->willReturn($comment);
+ $event->expects(($this->any()))
+ ->method(('getEvent'))
+ ->willReturn($eventType);
+
+ /** @var INotification|MockObject $notification */
+ $notification = $this->createMock(INotification::class);
+ $notification->expects($this->any())
+ ->method($this->anything())
+ ->willReturn($notification);
+ $notification->expects($this->exactly(6))
+ ->method('setUser');
+
+ $this->notificationManager->expects($this->once())
+ ->method('createNotification')
+ ->willReturn($notification);
+ $this->notificationManager->expects($this->exactly(6))
+ ->method($notificationMethod)
+ ->with($this->isInstanceOf('\OCP\Notification\INotification'));
+
+ $this->userManager->expects($this->exactly(6))
+ ->method('userExists')
+ ->willReturnMap([
+ ['foobar', true],
+ ['barfoo', true],
+ ['foo@bar.com', true],
+ ['bar@foo.org@foobar.io', true],
+ ['23452-4333-54353-2342', true],
+ ['yolo', true]
+ ]);
+
+ $this->listener->evaluate($event);
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('eventProvider')]
+ public function testEvaluateNoMentions(string $eventType): void {
+ /** @var IComment|MockObject $comment */
+ $comment = $this->createMock(IComment::class);
+ $comment->expects($this->any())
+ ->method('getObjectType')
+ ->willReturn('files');
+ $comment->expects($this->any())
+ ->method('getCreationDateTime')
+ ->willReturn(new \DateTime());
+ $comment->expects($this->once())
+ ->method('getMentions')
+ ->willReturn([]);
+
+ /** @var CommentsEvent|MockObject $event */
+ $event = $this->createMock(CommentsEvent::class);
+ $event->expects($this->once())
+ ->method('getComment')
+ ->willReturn($comment);
+ $event->expects(($this->any()))
+ ->method(('getEvent'))
+ ->willReturn($eventType);
+
+ $this->notificationManager->expects($this->never())
+ ->method('createNotification');
+ $this->notificationManager->expects($this->never())
+ ->method('notify');
+ $this->notificationManager->expects($this->never())
+ ->method('markProcessed');
+
+ $this->userManager->expects($this->never())
+ ->method('userExists');
+
+ $this->listener->evaluate($event);
+ }
+
+ public function testEvaluateUserDoesNotExist(): void {
+ /** @var IComment|MockObject $comment */
+ $comment = $this->createMock(IComment::class);
+ $comment->expects($this->any())
+ ->method('getObjectType')
+ ->willReturn('files');
+ $comment->expects($this->any())
+ ->method('getCreationDateTime')
+ ->willReturn(new \DateTime());
+ $comment->expects($this->once())
+ ->method('getMentions')
+ ->willReturn([[ 'type' => 'user', 'id' => 'foobar']]);
+ $comment->expects($this->atLeastOnce())
+ ->method('getId')
+ ->willReturn('1234');
+
+ /** @var CommentsEvent|MockObject $event */
+ $event = $this->createMock(CommentsEvent::class);
+ $event->expects($this->once())
+ ->method('getComment')
+ ->willReturn($comment);
+ $event->expects(($this->any()))
+ ->method(('getEvent'))
+ ->willReturn(CommentsEvent::EVENT_ADD);
+
+ /** @var INotification|MockObject $notification */
+ $notification = $this->createMock(INotification::class);
+ $notification->expects($this->any())
+ ->method($this->anything())
+ ->willReturn($notification);
+ $notification->expects($this->never())
+ ->method('setUser');
+
+ $this->notificationManager->expects($this->once())
+ ->method('createNotification')
+ ->willReturn($notification);
+ $this->notificationManager->expects($this->never())
+ ->method('notify');
+
+ $this->userManager->expects($this->once())
+ ->method('userExists')
+ ->with('foobar')
+ ->willReturn(false);
+
+ $this->listener->evaluate($event);
+ }
+}
diff --git a/apps/comments/tests/Unit/Notification/NotifierTest.php b/apps/comments/tests/Unit/Notification/NotifierTest.php
new file mode 100644
index 00000000000..37cad0b43df
--- /dev/null
+++ b/apps/comments/tests/Unit/Notification/NotifierTest.php
@@ -0,0 +1,554 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\Comments\Tests\Unit\Notification;
+
+use OCA\Comments\Notification\Notifier;
+use OCP\Comments\IComment;
+use OCP\Comments\ICommentsManager;
+use OCP\Comments\NotFoundException;
+use OCP\Files\Folder;
+use OCP\Files\IRootFolder;
+use OCP\Files\Node;
+use OCP\IL10N;
+use OCP\IURLGenerator;
+use OCP\IUserManager;
+use OCP\L10N\IFactory;
+use OCP\Notification\AlreadyProcessedException;
+use OCP\Notification\INotification;
+use OCP\Notification\UnknownNotificationException;
+use PHPUnit\Framework\MockObject\MockObject;
+use Test\TestCase;
+
+class NotifierTest extends TestCase {
+ protected IFactory&MockObject $l10nFactory;
+ protected IL10N&MockObject $l;
+ protected IRootFolder&MockObject $folder;
+ protected ICommentsManager&MockObject $commentsManager;
+ protected IURLGenerator&MockObject $url;
+ protected IUserManager&MockObject $userManager;
+ protected INotification&MockObject $notification;
+ protected IComment&MockObject $comment;
+ protected Notifier $notifier;
+ protected string $lc = 'tlh_KX';
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->l10nFactory = $this->createMock(IFactory::class);
+ $this->folder = $this->createMock(IRootFolder::class);
+ $this->commentsManager = $this->createMock(ICommentsManager::class);
+ $this->url = $this->createMock(IURLGenerator::class);
+ $this->userManager = $this->createMock(IUserManager::class);
+
+ $this->notifier = new Notifier(
+ $this->l10nFactory,
+ $this->folder,
+ $this->commentsManager,
+ $this->url,
+ $this->userManager
+ );
+
+ $this->l = $this->createMock(IL10N::class);
+ $this->l->expects($this->any())
+ ->method('t')
+ ->willReturnCallback(function ($text, $parameters = []) {
+ return vsprintf($text, $parameters);
+ });
+
+ $this->notification = $this->createMock(INotification::class);
+ $this->comment = $this->createMock(IComment::class);
+ }
+
+ public function testPrepareSuccess(): void {
+ $fileName = 'Gre\'thor.odp';
+ $displayName = 'Huraga';
+
+ /** @var Node&MockObject $node */
+ $node = $this->createMock(Node::class);
+ $node
+ ->expects($this->atLeastOnce())
+ ->method('getName')
+ ->willReturn($fileName);
+ $node
+ ->expects($this->atLeastOnce())
+ ->method('getPath')
+ ->willReturn('/you/files/' . $fileName);
+
+ $userFolder = $this->createMock(Folder::class);
+ $this->folder->expects($this->once())
+ ->method('getUserFolder')
+ ->with('you')
+ ->willReturn($userFolder);
+ $userFolder->expects($this->once())
+ ->method('getById')
+ ->with('678')
+ ->willReturn([$node]);
+
+ $this->notification->expects($this->exactly(2))
+ ->method('getUser')
+ ->willReturn('you');
+ $this->notification
+ ->expects($this->once())
+ ->method('getApp')
+ ->willReturn('comments');
+ $this->notification
+ ->expects($this->once())
+ ->method('getSubject')
+ ->willReturn('mention');
+ $this->notification
+ ->expects($this->once())
+ ->method('getSubjectParameters')
+ ->willReturn(['files', '678']);
+ $this->notification
+ ->expects($this->never())
+ ->method('setParsedSubject');
+ $this->notification
+ ->expects($this->once())
+ ->method('setRichSubject')
+ ->with('{user} mentioned you in a comment on "{file}"', $this->anything())
+ ->willReturnSelf();
+ $this->notification
+ ->expects($this->once())
+ ->method('setRichMessage')
+ ->with('Hi {mention-user1}!', ['mention-user1' => ['type' => 'user', 'id' => 'you', 'name' => 'Your name']])
+ ->willReturnSelf();
+ $this->notification
+ ->expects($this->never())
+ ->method('setParsedMessage');
+ $this->notification
+ ->expects($this->once())
+ ->method('setIcon')
+ ->with('absolute-image-path')
+ ->willReturnSelf();
+
+ $this->url->expects($this->once())
+ ->method('imagePath')
+ ->with('core', 'actions/comment.svg')
+ ->willReturn('image-path');
+ $this->url->expects($this->once())
+ ->method('getAbsoluteURL')
+ ->with('image-path')
+ ->willReturn('absolute-image-path');
+
+ $this->l10nFactory
+ ->expects($this->once())
+ ->method('get')
+ ->willReturn($this->l);
+
+ $this->comment
+ ->expects($this->any())
+ ->method('getActorId')
+ ->willReturn('huraga');
+ $this->comment
+ ->expects($this->any())
+ ->method('getActorType')
+ ->willReturn('users');
+ $this->comment
+ ->expects($this->any())
+ ->method('getMessage')
+ ->willReturn('Hi @you!');
+ $this->comment
+ ->expects($this->any())
+ ->method('getMentions')
+ ->willReturn([['type' => 'user', 'id' => 'you']]);
+ $this->comment->expects($this->atLeastOnce())
+ ->method('getId')
+ ->willReturn('1234');
+
+ $this->commentsManager
+ ->expects($this->once())
+ ->method('get')
+ ->willReturn($this->comment);
+ $this->commentsManager
+ ->expects($this->once())
+ ->method('resolveDisplayName')
+ ->with('user', 'you')
+ ->willReturn('Your name');
+
+ $this->userManager
+ ->expects($this->exactly(2))
+ ->method('getDisplayName')
+ ->willReturnMap([
+ ['huraga', $displayName],
+ ['you', 'You'],
+ ]);
+
+ $this->notifier->prepare($this->notification, $this->lc);
+ }
+
+ public function testPrepareSuccessDeletedUser(): void {
+ $fileName = 'Gre\'thor.odp';
+
+ /** @var Node|MockObject $node */
+ $node = $this->createMock(Node::class);
+ $node
+ ->expects($this->atLeastOnce())
+ ->method('getName')
+ ->willReturn($fileName);
+ $node
+ ->expects($this->atLeastOnce())
+ ->method('getPath')
+ ->willReturn('/you/files/' . $fileName);
+
+ $userFolder = $this->createMock(Folder::class);
+ $this->folder->expects($this->once())
+ ->method('getUserFolder')
+ ->with('you')
+ ->willReturn($userFolder);
+ $userFolder->expects($this->once())
+ ->method('getById')
+ ->with('678')
+ ->willReturn([$node]);
+
+ $this->notification->expects($this->exactly(2))
+ ->method('getUser')
+ ->willReturn('you');
+ $this->notification
+ ->expects($this->once())
+ ->method('getApp')
+ ->willReturn('comments');
+ $this->notification
+ ->expects($this->once())
+ ->method('getSubject')
+ ->willReturn('mention');
+ $this->notification
+ ->expects($this->once())
+ ->method('getSubjectParameters')
+ ->willReturn(['files', '678']);
+ $this->notification
+ ->expects($this->never())
+ ->method('setParsedSubject');
+ $this->notification
+ ->expects($this->once())
+ ->method('setRichSubject')
+ ->with('You were mentioned on "{file}", in a comment by an account that has since been deleted', $this->anything())
+ ->willReturnSelf();
+ $this->notification
+ ->expects($this->once())
+ ->method('setRichMessage')
+ ->with('Hi {mention-user1}!', ['mention-user1' => ['type' => 'user', 'id' => 'you', 'name' => 'Your name']])
+ ->willReturnSelf();
+ $this->notification
+ ->expects($this->never())
+ ->method('setParsedMessage');
+ $this->notification
+ ->expects($this->once())
+ ->method('setIcon')
+ ->with('absolute-image-path')
+ ->willReturnSelf();
+
+ $this->url->expects($this->once())
+ ->method('imagePath')
+ ->with('core', 'actions/comment.svg')
+ ->willReturn('image-path');
+ $this->url->expects($this->once())
+ ->method('getAbsoluteURL')
+ ->with('image-path')
+ ->willReturn('absolute-image-path');
+
+ $this->l10nFactory
+ ->expects($this->once())
+ ->method('get')
+ ->willReturn($this->l);
+
+ $this->comment
+ ->expects($this->any())
+ ->method('getActorId')
+ ->willReturn('huraga');
+ $this->comment
+ ->expects($this->any())
+ ->method('getActorType')
+ ->willReturn(ICommentsManager::DELETED_USER);
+ $this->comment
+ ->expects($this->any())
+ ->method('getMessage')
+ ->willReturn('Hi @you!');
+ $this->comment
+ ->expects($this->any())
+ ->method('getMentions')
+ ->willReturn([['type' => 'user', 'id' => 'you']]);
+
+ $this->commentsManager
+ ->expects($this->once())
+ ->method('get')
+ ->willReturn($this->comment);
+ $this->commentsManager
+ ->expects($this->once())
+ ->method('resolveDisplayName')
+ ->with('user', 'you')
+ ->willReturn('Your name');
+
+ $this->userManager
+ ->expects($this->once())
+ ->method('getDisplayName')
+ ->willReturnMap([
+ ['huraga', null],
+ ['you', 'You'],
+ ]);
+
+ $this->notifier->prepare($this->notification, $this->lc);
+ }
+
+
+ public function testPrepareDifferentApp(): void {
+ $this->expectException(UnknownNotificationException::class);
+
+ $this->folder
+ ->expects($this->never())
+ ->method('getById');
+
+ $this->notification
+ ->expects($this->once())
+ ->method('getApp')
+ ->willReturn('constructions');
+ $this->notification
+ ->expects($this->never())
+ ->method('getSubject');
+ $this->notification
+ ->expects($this->never())
+ ->method('getSubjectParameters');
+ $this->notification
+ ->expects($this->never())
+ ->method('setParsedSubject');
+
+ $this->l10nFactory
+ ->expects($this->never())
+ ->method('get');
+
+ $this->commentsManager
+ ->expects($this->never())
+ ->method('get');
+
+ $this->userManager
+ ->expects($this->never())
+ ->method('getDisplayName');
+
+ $this->notifier->prepare($this->notification, $this->lc);
+ }
+
+
+ public function testPrepareNotFound(): void {
+ $this->expectException(UnknownNotificationException::class);
+
+ $this->folder
+ ->expects($this->never())
+ ->method('getById');
+
+ $this->notification
+ ->expects($this->once())
+ ->method('getApp')
+ ->willReturn('comments');
+ $this->notification
+ ->expects($this->never())
+ ->method('getSubject');
+ $this->notification
+ ->expects($this->never())
+ ->method('getSubjectParameters');
+ $this->notification
+ ->expects($this->never())
+ ->method('setParsedSubject');
+
+ $this->l10nFactory
+ ->expects($this->never())
+ ->method('get');
+
+ $this->commentsManager
+ ->expects($this->once())
+ ->method('get')
+ ->willThrowException(new NotFoundException());
+
+ $this->userManager
+ ->expects($this->never())
+ ->method('getDisplayName');
+
+ $this->notifier->prepare($this->notification, $this->lc);
+ }
+
+
+ public function testPrepareDifferentSubject(): void {
+ $this->expectException(UnknownNotificationException::class);
+
+ $displayName = 'Huraga';
+
+ $this->folder
+ ->expects($this->never())
+ ->method('getById');
+
+ $this->notification
+ ->expects($this->once())
+ ->method('getApp')
+ ->willReturn('comments');
+ $this->notification
+ ->expects($this->once())
+ ->method('getSubject')
+ ->willReturn('unlike');
+ $this->notification
+ ->expects($this->never())
+ ->method('getSubjectParameters');
+ $this->notification
+ ->expects($this->never())
+ ->method('setParsedSubject');
+
+ $this->l
+ ->expects($this->never())
+ ->method('t');
+
+ $this->l10nFactory
+ ->expects($this->once())
+ ->method('get')
+ ->willReturn($this->l);
+
+ $this->comment
+ ->expects($this->any())
+ ->method('getActorId')
+ ->willReturn('huraga');
+ $this->comment
+ ->expects($this->any())
+ ->method('getActorType')
+ ->willReturn('users');
+
+ $this->commentsManager
+ ->expects($this->once())
+ ->method('get')
+ ->willReturn($this->comment);
+
+ $this->userManager
+ ->expects($this->once())
+ ->method('getDisplayName')
+ ->with('huraga')
+ ->willReturn($displayName);
+
+ $this->notifier->prepare($this->notification, $this->lc);
+ }
+
+
+ public function testPrepareNotFiles(): void {
+ $this->expectException(UnknownNotificationException::class);
+
+ $displayName = 'Huraga';
+
+ $this->folder
+ ->expects($this->never())
+ ->method('getById');
+
+ $this->notification
+ ->expects($this->once())
+ ->method('getApp')
+ ->willReturn('comments');
+ $this->notification
+ ->expects($this->once())
+ ->method('getSubject')
+ ->willReturn('mention');
+ $this->notification
+ ->expects($this->once())
+ ->method('getSubjectParameters')
+ ->willReturn(['ships', '678']);
+ $this->notification
+ ->expects($this->never())
+ ->method('setParsedSubject');
+
+ $this->l
+ ->expects($this->never())
+ ->method('t');
+
+ $this->l10nFactory
+ ->expects($this->once())
+ ->method('get')
+ ->willReturn($this->l);
+
+ $this->comment
+ ->expects($this->any())
+ ->method('getActorId')
+ ->willReturn('huraga');
+ $this->comment
+ ->expects($this->any())
+ ->method('getActorType')
+ ->willReturn('users');
+
+ $this->commentsManager
+ ->expects($this->once())
+ ->method('get')
+ ->willReturn($this->comment);
+
+ $this->userManager
+ ->expects($this->once())
+ ->method('getDisplayName')
+ ->with('huraga')
+ ->willReturn($displayName);
+
+ $this->notifier->prepare($this->notification, $this->lc);
+ }
+
+
+ public function testPrepareUnresolvableFileID(): void {
+ $this->expectException(AlreadyProcessedException::class);
+
+ $displayName = 'Huraga';
+
+ $userFolder = $this->createMock(Folder::class);
+ $this->folder->expects($this->once())
+ ->method('getUserFolder')
+ ->with('you')
+ ->willReturn($userFolder);
+ $userFolder->expects($this->once())
+ ->method('getById')
+ ->with('678')
+ ->willReturn([]);
+
+ $this->notification->expects($this->once())
+ ->method('getUser')
+ ->willReturn('you');
+ $this->notification
+ ->expects($this->once())
+ ->method('getApp')
+ ->willReturn('comments');
+ $this->notification
+ ->expects($this->once())
+ ->method('getSubject')
+ ->willReturn('mention');
+ $this->notification
+ ->expects($this->once())
+ ->method('getSubjectParameters')
+ ->willReturn(['files', '678']);
+ $this->notification
+ ->expects($this->never())
+ ->method('setParsedSubject');
+
+ $this->l
+ ->expects($this->never())
+ ->method('t');
+
+ $this->l10nFactory
+ ->expects($this->once())
+ ->method('get')
+ ->willReturn($this->l);
+
+ $this->comment
+ ->expects($this->any())
+ ->method('getActorId')
+ ->willReturn('huraga');
+ $this->comment
+ ->expects($this->any())
+ ->method('getActorType')
+ ->willReturn('users');
+
+ $this->commentsManager
+ ->expects($this->once())
+ ->method('get')
+ ->willReturn($this->comment);
+
+ $this->userManager
+ ->expects($this->once())
+ ->method('getDisplayName')
+ ->with('huraga')
+ ->willReturn($displayName);
+
+ $this->notifier->prepare($this->notification, $this->lc);
+ }
+}