diff options
Diffstat (limited to 'apps/comments/tests/Unit')
-rw-r--r-- | apps/comments/tests/Unit/Activity/ListenerTest.php | 159 | ||||
-rw-r--r-- | apps/comments/tests/Unit/AppInfo/ApplicationTest.php | 62 | ||||
-rw-r--r-- | apps/comments/tests/Unit/Collaboration/CommentersSorterTest.php | 136 | ||||
-rw-r--r-- | apps/comments/tests/Unit/Controller/NotificationsTest.php | 214 | ||||
-rw-r--r-- | apps/comments/tests/Unit/EventHandlerTest.php | 87 | ||||
-rw-r--r-- | apps/comments/tests/Unit/Notification/ListenerTest.php | 195 | ||||
-rw-r--r-- | apps/comments/tests/Unit/Notification/NotifierTest.php | 554 |
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); + } +} |