You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

840 lines
25 KiB

  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OCA\Talk\Tests\php\Chat;
  8. use OCA\Talk\Chat\ChatManager;
  9. use OCA\Talk\Chat\CommentsManager;
  10. use OCA\Talk\Chat\Notifier;
  11. use OCA\Talk\Model\Attendee;
  12. use OCA\Talk\Model\AttendeeMapper;
  13. use OCA\Talk\Model\Invitation;
  14. use OCA\Talk\Participant;
  15. use OCA\Talk\Room;
  16. use OCA\Talk\Service\AttachmentService;
  17. use OCA\Talk\Service\ParticipantService;
  18. use OCA\Talk\Service\PollService;
  19. use OCA\Talk\Service\RoomService;
  20. use OCA\Talk\Share\RoomShareProvider;
  21. use OCP\AppFramework\Utility\ITimeFactory;
  22. use OCP\Collaboration\Reference\IReferenceManager;
  23. use OCP\Comments\IComment;
  24. use OCP\Comments\ICommentsManager;
  25. use OCP\EventDispatcher\IEventDispatcher;
  26. use OCP\ICacheFactory;
  27. use OCP\IDBConnection;
  28. use OCP\IL10N;
  29. use OCP\IRequest;
  30. use OCP\IUser;
  31. use OCP\Notification\IManager as INotificationManager;
  32. use OCP\Security\RateLimiting\ILimiter;
  33. use OCP\Share\Exceptions\ShareNotFound;
  34. use OCP\Share\IManager;
  35. use OCP\Share\IShare;
  36. use PHPUnit\Framework\Attributes\DataProvider;
  37. use PHPUnit\Framework\MockObject\MockObject;
  38. use Psr\Log\LoggerInterface;
  39. use Test\TestCase;
  40. /**
  41. * @group DB
  42. */
  43. class ChatManagerTest extends TestCase {
  44. protected CommentsManager|ICommentsManager|MockObject $commentsManager;
  45. protected IEventDispatcher&MockObject $dispatcher;
  46. protected INotificationManager&MockObject $notificationManager;
  47. protected IManager&MockObject $shareManager;
  48. protected RoomShareProvider&MockObject $shareProvider;
  49. protected ParticipantService&MockObject $participantService;
  50. protected RoomService&MockObject $roomService;
  51. protected PollService&MockObject $pollService;
  52. protected Notifier&MockObject $notifier;
  53. protected ITimeFactory&MockObject $timeFactory;
  54. protected AttachmentService&MockObject $attachmentService;
  55. protected IReferenceManager&MockObject $referenceManager;
  56. protected ILimiter&MockObject $rateLimiter;
  57. protected IRequest&MockObject $request;
  58. protected LoggerInterface&MockObject $logger;
  59. protected IL10N&MockObject $l;
  60. protected ?ChatManager $chatManager = null;
  61. public function setUp(): void {
  62. parent::setUp();
  63. $this->commentsManager = $this->createMock(CommentsManager::class);
  64. $this->dispatcher = $this->createMock(IEventDispatcher::class);
  65. $this->notificationManager = $this->createMock(INotificationManager::class);
  66. $this->shareManager = $this->createMock(IManager::class);
  67. $this->shareProvider = $this->createMock(RoomShareProvider::class);
  68. $this->participantService = $this->createMock(ParticipantService::class);
  69. $this->roomService = $this->createMock(RoomService::class);
  70. $this->pollService = $this->createMock(PollService::class);
  71. $this->notifier = $this->createMock(Notifier::class);
  72. $this->timeFactory = $this->createMock(ITimeFactory::class);
  73. $this->attachmentService = $this->createMock(AttachmentService::class);
  74. $this->referenceManager = $this->createMock(IReferenceManager::class);
  75. $this->rateLimiter = $this->createMock(ILimiter::class);
  76. $this->request = $this->createMock(IRequest::class);
  77. $this->l = $this->createMock(IL10N::class);
  78. $this->logger = $this->createMock(LoggerInterface::class);
  79. $this->l->method('n')
  80. ->willReturnCallback(function (string $singular, string $plural, int $count, array $parameters = []) {
  81. $text = $count === 1 ? $singular : $plural;
  82. return vsprintf(str_replace('%n', (string)$count, $text), $parameters);
  83. });
  84. $this->chatManager = $this->getManager();
  85. }
  86. /**
  87. * @param string[] $methods
  88. * @return ChatManager|MockObject
  89. */
  90. protected function getManager(array $methods = []): ChatManager {
  91. $cacheFactory = $this->createMock(ICacheFactory::class);
  92. if (!empty($methods)) {
  93. return $this->getMockBuilder(ChatManager::class)
  94. ->setConstructorArgs([
  95. $this->commentsManager,
  96. $this->dispatcher,
  97. \OCP\Server::get(IDBConnection::class),
  98. $this->notificationManager,
  99. $this->shareManager,
  100. $this->shareProvider,
  101. $this->participantService,
  102. $this->roomService,
  103. $this->pollService,
  104. $this->notifier,
  105. $cacheFactory,
  106. $this->timeFactory,
  107. $this->attachmentService,
  108. $this->referenceManager,
  109. $this->rateLimiter,
  110. $this->request,
  111. $this->l,
  112. $this->logger,
  113. ])
  114. ->onlyMethods($methods)
  115. ->getMock();
  116. }
  117. return new ChatManager(
  118. $this->commentsManager,
  119. $this->dispatcher,
  120. \OCP\Server::get(IDBConnection::class),
  121. $this->notificationManager,
  122. $this->shareManager,
  123. $this->shareProvider,
  124. $this->participantService,
  125. $this->roomService,
  126. $this->pollService,
  127. $this->notifier,
  128. $cacheFactory,
  129. $this->timeFactory,
  130. $this->attachmentService,
  131. $this->referenceManager,
  132. $this->rateLimiter,
  133. $this->request,
  134. $this->l,
  135. $this->logger,
  136. );
  137. }
  138. private function newComment($id, string $actorType, string $actorId, \DateTime $creationDateTime, string $message): IComment {
  139. $comment = $this->createMock(IComment::class);
  140. $id = (string)$id;
  141. $comment->method('getId')->willReturn($id);
  142. $comment->method('getActorType')->willReturn($actorType);
  143. $comment->method('getActorId')->willReturn($actorId);
  144. $comment->method('getCreationDateTime')->willReturn($creationDateTime);
  145. $comment->method('getMessage')->willReturn($message);
  146. return $comment;
  147. }
  148. /**
  149. * @param array $data
  150. * @return IComment|MockObject
  151. */
  152. private function newCommentFromArray(array $data): IComment {
  153. $comment = $this->createMock(IComment::class);
  154. foreach ($data as $key => $value) {
  155. if ($key === 'id') {
  156. $value = (string)$value;
  157. }
  158. $comment->method('get' . ucfirst($key))->willReturn($value);
  159. }
  160. return $comment;
  161. }
  162. protected function assertCommentEquals(array $data, IComment $comment): void {
  163. if (isset($data['id'])) {
  164. $id = $data['id'];
  165. unset($data['id']);
  166. $this->assertEquals($id, $comment->getId());
  167. }
  168. $this->assertEquals($data, [
  169. 'actorType' => $comment->getActorType(),
  170. 'actorId' => $comment->getActorId(),
  171. 'creationDateTime' => $comment->getCreationDateTime(),
  172. 'message' => $comment->getMessage(),
  173. 'referenceId' => $comment->getReferenceId(),
  174. 'parentId' => $comment->getParentId(),
  175. ]);
  176. }
  177. public static function dataSendMessage(): array {
  178. return [
  179. 'simple message' => ['testUser1', 'testMessage1', '', '0'],
  180. 'reference id' => ['testUser2', 'testMessage2', 'referenceId2', '0'],
  181. 'as a reply' => ['testUser3', 'testMessage3', '', '23'],
  182. 'reply w/ ref' => ['testUser4', 'testMessage4', 'referenceId4', '23'],
  183. ];
  184. }
  185. #[DataProvider('dataSendMessage')]
  186. public function testSendMessage(string $userId, string $message, string $referenceId, string $parentId): void {
  187. $creationDateTime = new \DateTime();
  188. $commentExpected = [
  189. 'actorType' => 'users',
  190. 'actorId' => $userId,
  191. 'creationDateTime' => $creationDateTime,
  192. 'message' => $message,
  193. 'referenceId' => $referenceId,
  194. 'parentId' => $parentId,
  195. ];
  196. $comment = $this->newCommentFromArray($commentExpected);
  197. if ($parentId !== '0') {
  198. $replyTo = $this->newCommentFromArray([
  199. 'id' => $parentId,
  200. ]);
  201. $comment->expects($this->once())
  202. ->method('setParentId')
  203. ->with($parentId);
  204. } else {
  205. $replyTo = null;
  206. }
  207. $this->commentsManager->expects($this->once())
  208. ->method('create')
  209. ->with('users', $userId, 'chat', 1234)
  210. ->willReturn($comment);
  211. $comment->expects($this->once())
  212. ->method('setMessage')
  213. ->with($message);
  214. $comment->expects($this->once())
  215. ->method('setCreationDateTime')
  216. ->with($creationDateTime);
  217. $comment->expects($referenceId === '' ? $this->never() : $this->once())
  218. ->method('setReferenceId')
  219. ->with($referenceId);
  220. $comment->expects($this->once())
  221. ->method('setVerb')
  222. ->with('comment');
  223. $this->commentsManager->expects($this->once())
  224. ->method('save')
  225. ->with($comment);
  226. $chat = $this->createMock(Room::class);
  227. $chat->expects($this->any())
  228. ->method('getId')
  229. ->willReturn(1234);
  230. $this->notifier->expects($this->once())
  231. ->method('notifyMentionedUsers')
  232. ->with($chat, $comment);
  233. $participant = $this->createMock(Participant::class);
  234. $return = $this->chatManager->sendMessage($chat, $participant, 'users', $userId, $message, $creationDateTime, $replyTo, $referenceId, false);
  235. $this->assertCommentEquals($commentExpected, $return);
  236. }
  237. public function testGetHistory(): void {
  238. $offset = 1;
  239. $limit = 42;
  240. $expected = [
  241. $this->newComment(110, 'users', 'testUnknownUser', new \DateTime('@' . 1000000042), 'testMessage3'),
  242. $this->newComment(109, 'guests', 'testSpreedSession', new \DateTime('@' . 1000000023), 'testMessage2'),
  243. $this->newComment(108, 'users', 'testUser', new \DateTime('@' . 1000000016), 'testMessage1')
  244. ];
  245. $chat = $this->createMock(Room::class);
  246. $chat->expects($this->any())
  247. ->method('getId')
  248. ->willReturn(1234);
  249. $this->commentsManager->expects($this->once())
  250. ->method('getForObjectSince')
  251. ->with('chat', 1234, $offset, 'desc', $limit)
  252. ->willReturn($expected);
  253. $comments = $this->chatManager->getHistory($chat, $offset, $limit, false);
  254. $this->assertEquals($expected, $comments);
  255. }
  256. public function testWaitForNewMessages(): void {
  257. $offset = 1;
  258. $limit = 42;
  259. $timeout = 23;
  260. $expected = [
  261. $this->newComment(108, 'users', 'testUser', new \DateTime('@' . 1000000016), 'testMessage1'),
  262. $this->newComment(109, 'guests', 'testSpreedSession', new \DateTime('@' . 1000000023), 'testMessage2'),
  263. $this->newComment(110, 'users', 'testUnknownUser', new \DateTime('@' . 1000000042), 'testMessage3'),
  264. ];
  265. $chat = $this->createMock(Room::class);
  266. $chat->expects($this->any())
  267. ->method('getId')
  268. ->willReturn(1234);
  269. $this->commentsManager->expects($this->once())
  270. ->method('getForObjectSince')
  271. ->with('chat', 1234, $offset, 'asc', $limit)
  272. ->willReturn($expected);
  273. $this->notifier->expects($this->once())
  274. ->method('markMentionNotificationsRead')
  275. ->with($chat, 'userId');
  276. /** @var IUser&MockObject $user */
  277. $user = $this->createMock(IUser::class);
  278. $user->expects($this->any())
  279. ->method('getUID')
  280. ->willReturn('userId');
  281. $comments = $this->chatManager->waitForNewMessages($chat, $offset, $limit, $timeout, $user, false, true);
  282. $this->assertEquals($expected, $comments);
  283. }
  284. public function testWaitForNewMessagesWithWaiting(): void {
  285. $offset = 1;
  286. $limit = 42;
  287. $timeout = 23;
  288. $expected = [
  289. $this->newComment(108, 'users', 'testUser', new \DateTime('@' . 1000000016), 'testMessage1'),
  290. $this->newComment(109, 'guests', 'testSpreedSession', new \DateTime('@' . 1000000023), 'testMessage2'),
  291. $this->newComment(110, 'users', 'testUnknownUser', new \DateTime('@' . 1000000042), 'testMessage3'),
  292. ];
  293. $chat = $this->createMock(Room::class);
  294. $chat->expects($this->any())
  295. ->method('getId')
  296. ->willReturn(1234);
  297. $this->commentsManager->expects($this->exactly(2))
  298. ->method('getForObjectSince')
  299. ->with('chat', 1234, $offset, 'asc', $limit)
  300. ->willReturnOnConsecutiveCalls(
  301. [],
  302. $expected
  303. );
  304. $this->notifier->expects($this->once())
  305. ->method('markMentionNotificationsRead')
  306. ->with($chat, 'userId');
  307. /** @var IUser&MockObject $user */
  308. $user = $this->createMock(IUser::class);
  309. $user->expects($this->any())
  310. ->method('getUID')
  311. ->willReturn('userId');
  312. $comments = $this->chatManager->waitForNewMessages($chat, $offset, $limit, $timeout, $user, false, true);
  313. $this->assertEquals($expected, $comments);
  314. }
  315. public function testGetUnreadCount(): void {
  316. /** @var Room&MockObject $chat */
  317. $chat = $this->createMock(Room::class);
  318. $chat->expects($this->atLeastOnce())
  319. ->method('getId')
  320. ->willReturn(23);
  321. $this->commentsManager->expects($this->once())
  322. ->method('getNumberOfCommentsWithVerbsForObjectSinceComment')
  323. ->with('chat', 23, 42, ['comment', 'object_shared']);
  324. $this->chatManager->getUnreadCount($chat, 42);
  325. }
  326. public function testDeleteMessages(): void {
  327. $chat = $this->createMock(Room::class);
  328. $chat->expects($this->any())
  329. ->method('getId')
  330. ->willReturn(1234);
  331. $this->commentsManager->expects($this->once())
  332. ->method('deleteCommentsAtObject')
  333. ->with('chat', 1234);
  334. $this->notifier->expects($this->once())
  335. ->method('removePendingNotificationsForRoom')
  336. ->with($chat);
  337. $this->chatManager->deleteMessages($chat);
  338. }
  339. public function testDeleteMessage(): void {
  340. $mapper = new AttendeeMapper(\OCP\Server::get(IDBConnection::class));
  341. $attendee = $mapper->createAttendeeFromRow([
  342. 'a_id' => 1,
  343. 'room_id' => 123,
  344. 'actor_type' => Attendee::ACTOR_USERS,
  345. 'actor_id' => 'user',
  346. 'display_name' => 'user-display',
  347. 'pin' => '',
  348. 'participant_type' => Participant::USER,
  349. 'favorite' => true,
  350. 'notification_level' => Participant::NOTIFY_MENTION,
  351. 'notification_calls' => Participant::NOTIFY_CALLS_ON,
  352. 'last_joined_call' => 0,
  353. 'last_read_message' => 0,
  354. 'last_mention_message' => 0,
  355. 'last_mention_direct' => 0,
  356. 'read_privacy' => Participant::PRIVACY_PUBLIC,
  357. 'permissions' => Attendee::PERMISSIONS_DEFAULT,
  358. 'access_token' => '',
  359. 'remote_id' => '',
  360. 'phone_number' => '',
  361. 'call_id' => '',
  362. 'invited_cloud_id' => '',
  363. 'state' => Invitation::STATE_ACCEPTED,
  364. 'unread_messages' => 0,
  365. 'last_attendee_activity' => 0,
  366. 'archived' => 0,
  367. 'important' => 0,
  368. 'sensitive' => 0,
  369. ]);
  370. $chat = $this->createMock(Room::class);
  371. $chat->expects($this->any())
  372. ->method('getId')
  373. ->willReturn(1234);
  374. $participant = new Participant($chat, $attendee, null);
  375. $date = new \DateTime();
  376. $comment = $this->createMock(IComment::class);
  377. $comment->method('getId')
  378. ->willReturn('123456');
  379. $comment->method('getVerb')
  380. ->willReturn('comment');
  381. $comment->expects($this->once())
  382. ->method('setMessage');
  383. $comment->expects($this->once())
  384. ->method('setVerb')
  385. ->with('comment_deleted');
  386. $this->commentsManager->expects($this->once())
  387. ->method('save')
  388. ->with($comment);
  389. $systemMessage = $this->createMock(IComment::class);
  390. $chatManager = $this->getManager(['addSystemMessage']);
  391. $chatManager->expects($this->once())
  392. ->method('addSystemMessage')
  393. ->with($chat, Attendee::ACTOR_USERS, 'user', $this->anything(), $this->anything(), false, null, $comment)
  394. ->willReturn($systemMessage);
  395. $this->assertSame($systemMessage, $chatManager->deleteMessage($chat, $comment, $participant, $date));
  396. }
  397. public function testDeleteMessageFileShare(): void {
  398. $mapper = new AttendeeMapper(\OCP\Server::get(IDBConnection::class));
  399. $attendee = $mapper->createAttendeeFromRow([
  400. 'a_id' => 1,
  401. 'room_id' => 123,
  402. 'actor_type' => Attendee::ACTOR_USERS,
  403. 'actor_id' => 'user',
  404. 'display_name' => 'user-display',
  405. 'pin' => '',
  406. 'participant_type' => Participant::USER,
  407. 'favorite' => true,
  408. 'notification_level' => Participant::NOTIFY_MENTION,
  409. 'notification_calls' => Participant::NOTIFY_CALLS_ON,
  410. 'last_joined_call' => 0,
  411. 'last_read_message' => 0,
  412. 'last_mention_message' => 0,
  413. 'last_mention_direct' => 0,
  414. 'read_privacy' => Participant::PRIVACY_PUBLIC,
  415. 'permissions' => Attendee::PERMISSIONS_DEFAULT,
  416. 'access_token' => '',
  417. 'remote_id' => '',
  418. 'phone_number' => '',
  419. 'call_id' => '',
  420. 'invited_cloud_id' => '',
  421. 'state' => Invitation::STATE_ACCEPTED,
  422. 'unread_messages' => 0,
  423. 'last_attendee_activity' => 0,
  424. 'archived' => 0,
  425. 'important' => 0,
  426. 'sensitive' => 0,
  427. ]);
  428. $chat = $this->createMock(Room::class);
  429. $chat->expects($this->any())
  430. ->method('getId')
  431. ->willReturn(1234);
  432. $chat->expects($this->any())
  433. ->method('getToken')
  434. ->willReturn('T0k3N');
  435. $participant = new Participant($chat, $attendee, null);
  436. $date = new \DateTime();
  437. $comment = $this->createMock(IComment::class);
  438. $comment->method('getId')
  439. ->willReturn('123456');
  440. $comment->method('getVerb')
  441. ->willReturn('object_shared');
  442. $comment->expects($this->once())
  443. ->method('getMessage')
  444. ->willReturn(json_encode(['message' => 'file_shared', 'parameters' => ['share' => '42']]));
  445. $comment->expects($this->once())
  446. ->method('setMessage');
  447. $comment->expects($this->once())
  448. ->method('setVerb')
  449. ->with('comment_deleted');
  450. $share = $this->createMock(IShare::class);
  451. $share->method('getShareType')
  452. ->willReturn(IShare::TYPE_ROOM);
  453. $share->method('getSharedWith')
  454. ->willReturn('T0k3N');
  455. $share->method('getShareOwner')
  456. ->willReturn('user');
  457. $this->shareManager->method('getShareById')
  458. ->with('ocRoomShare:42')
  459. ->willReturn($share);
  460. $this->shareManager->expects($this->once())
  461. ->method('deleteShare')
  462. ->willReturn($share);
  463. $this->commentsManager->expects($this->once())
  464. ->method('save')
  465. ->with($comment);
  466. $systemMessage = $this->createMock(IComment::class);
  467. $chatManager = $this->getManager(['addSystemMessage']);
  468. $chatManager->expects($this->once())
  469. ->method('addSystemMessage')
  470. ->with($chat, Attendee::ACTOR_USERS, 'user', $this->anything(), $this->anything(), false, null, $comment)
  471. ->willReturn($systemMessage);
  472. $this->assertSame($systemMessage, $chatManager->deleteMessage($chat, $comment, $participant, $date));
  473. }
  474. public function testDeleteMessageFileShareNotFound(): void {
  475. $mapper = new AttendeeMapper(\OCP\Server::get(IDBConnection::class));
  476. $attendee = $mapper->createAttendeeFromRow([
  477. 'a_id' => 1,
  478. 'room_id' => 123,
  479. 'actor_type' => Attendee::ACTOR_USERS,
  480. 'actor_id' => 'user',
  481. 'display_name' => 'user-display',
  482. 'pin' => '',
  483. 'participant_type' => Participant::USER,
  484. 'favorite' => true,
  485. 'notification_level' => Participant::NOTIFY_MENTION,
  486. 'notification_calls' => Participant::NOTIFY_CALLS_ON,
  487. 'last_joined_call' => 0,
  488. 'last_read_message' => 0,
  489. 'last_mention_message' => 0,
  490. 'last_mention_direct' => 0,
  491. 'read_privacy' => Participant::PRIVACY_PUBLIC,
  492. 'permissions' => Attendee::PERMISSIONS_DEFAULT,
  493. 'access_token' => '',
  494. 'remote_id' => '',
  495. 'phone_number' => '',
  496. 'call_id' => '',
  497. 'invited_cloud_id' => '',
  498. 'state' => Invitation::STATE_ACCEPTED,
  499. 'unread_messages' => 0,
  500. 'last_attendee_activity' => 0,
  501. 'archived' => 0,
  502. 'important' => 0,
  503. 'sensitive' => 0,
  504. ]);
  505. $chat = $this->createMock(Room::class);
  506. $chat->expects($this->any())
  507. ->method('getId')
  508. ->willReturn(1234);
  509. $participant = new Participant($chat, $attendee, null);
  510. $date = new \DateTime();
  511. $comment = $this->createMock(IComment::class);
  512. $comment->method('getId')
  513. ->willReturn('123456');
  514. $comment->method('getVerb')
  515. ->willReturn('object_shared');
  516. $comment->expects($this->once())
  517. ->method('getMessage')
  518. ->willReturn(json_encode(['message' => 'file_shared', 'parameters' => ['share' => '42']]));
  519. $this->shareManager->method('getShareById')
  520. ->with('ocRoomShare:42')
  521. ->willThrowException(new ShareNotFound());
  522. $this->commentsManager->expects($this->never())
  523. ->method('save');
  524. $systemMessage = $this->createMock(IComment::class);
  525. $chatManager = $this->getManager(['addSystemMessage']);
  526. $chatManager->expects($this->never())
  527. ->method('addSystemMessage');
  528. $this->expectException(ShareNotFound::class);
  529. $this->assertSame($systemMessage, $chatManager->deleteMessage($chat, $comment, $participant, $date));
  530. }
  531. public function testClearHistory(): void {
  532. $chat = $this->createMock(Room::class);
  533. $chat->expects($this->any())
  534. ->method('getId')
  535. ->willReturn(1234);
  536. $chat->expects($this->any())
  537. ->method('getToken')
  538. ->willReturn('t0k3n');
  539. $this->commentsManager->expects($this->once())
  540. ->method('deleteCommentsAtObject')
  541. ->with('chat', 1234);
  542. $this->shareProvider->expects($this->once())
  543. ->method('deleteInRoom')
  544. ->with('t0k3n');
  545. $this->notifier->expects($this->once())
  546. ->method('removePendingNotificationsForRoom')
  547. ->with($chat, true);
  548. $this->participantService->expects($this->once())
  549. ->method('resetChatDetails')
  550. ->with($chat);
  551. $date = new \DateTime();
  552. $this->timeFactory->method('getDateTime')
  553. ->willReturn($date);
  554. $manager = $this->getManager(['addSystemMessage']);
  555. $manager->expects($this->once())
  556. ->method('addSystemMessage')
  557. ->with(
  558. $chat,
  559. 'users',
  560. 'admin',
  561. json_encode(['message' => 'history_cleared', 'parameters' => []]),
  562. $date,
  563. false
  564. );
  565. $manager->clearHistory($chat, 'users', 'admin');
  566. }
  567. public static function dataSearchIsPartOfConversationNameOrAtAll(): array {
  568. return [
  569. 'found a in all' => [
  570. 'a', 'room', true
  571. ],
  572. 'found h in here' => [
  573. 'h', 'room', true
  574. ],
  575. 'case sensitive, not found A in all' => [
  576. 'A', 'room', false
  577. ],
  578. 'case sensitive, not found H in here' => [
  579. 'H', 'room', false
  580. ],
  581. 'non case sensitive, found r in room' => [
  582. 'R', 'room', true
  583. ],
  584. 'found r in begin of room' => [
  585. 'r', 'room', true
  586. ],
  587. 'found o in middle of room' => [
  588. 'o', 'room', true
  589. ],
  590. 'not found all in middle of text' => [
  591. 'notbeginingall', 'room', false
  592. ],
  593. 'not found here in middle of text' => [
  594. 'notbegininghere', 'room', false
  595. ],
  596. 'not found room in middle of text' => [
  597. 'notbeginingroom', 'room', false
  598. ],
  599. ];
  600. }
  601. #[DataProvider('dataSearchIsPartOfConversationNameOrAtAll')]
  602. public function testSearchIsPartOfConversationNameOrAtAll(string $search, string $roomDisplayName, bool $expected): void {
  603. $actual = self::invokePrivate($this->chatManager, 'searchIsPartOfConversationNameOrAtAll', [$search, $roomDisplayName]);
  604. $this->assertEquals($expected, $actual);
  605. }
  606. public static function dataAddConversationNotify(): array {
  607. return [
  608. [
  609. '',
  610. ['getType' => Room::TYPE_ONE_TO_ONE],
  611. [],
  612. null,
  613. [],
  614. ],
  615. [
  616. '',
  617. ['getDisplayName' => 'test', 'getMentionPermissions' => 0],
  618. ['getAttendee' => Attendee::fromRow([
  619. 'actor_type' => Attendee::ACTOR_USERS,
  620. 'actor_id' => 'user',
  621. ])],
  622. 324,
  623. [['id' => 'all', 'label' => 'test', 'source' => 'calls', 'mentionId' => 'all', 'details' => 'All 324 participants']]
  624. ],
  625. [
  626. '',
  627. ['getMentionPermissions' => 1],
  628. ['hasModeratorPermissions' => false],
  629. null,
  630. [],
  631. ],
  632. [
  633. 'all',
  634. ['getDisplayName' => 'test', 'getMentionPermissions' => 0],
  635. ['getAttendee' => Attendee::fromRow([
  636. 'actor_type' => Attendee::ACTOR_USERS,
  637. 'actor_id' => 'user',
  638. ])],
  639. 1,
  640. [['id' => 'all', 'label' => 'test', 'source' => 'calls', 'mentionId' => 'all']],
  641. ],
  642. [
  643. 'all',
  644. ['getDisplayName' => 'test', 'getMentionPermissions' => 1],
  645. [
  646. 'getAttendee' => Attendee::fromRow([
  647. 'actor_type' => Attendee::ACTOR_USERS,
  648. 'actor_id' => 'user',
  649. ]),
  650. 'hasModeratorPermissions' => true,
  651. ],
  652. 8,
  653. [['id' => 'all', 'label' => 'test', 'source' => 'calls', 'mentionId' => 'all', 'details' => 'All 8 participants']],
  654. ],
  655. [
  656. 'here',
  657. ['getDisplayName' => 'test', 'getMentionPermissions' => 0],
  658. ['getAttendee' => Attendee::fromRow([
  659. 'actor_type' => Attendee::ACTOR_GUESTS,
  660. 'actor_id' => 'guest',
  661. ])],
  662. 12,
  663. [['id' => 'all', 'label' => 'test', 'source' => 'calls', 'mentionId' => 'all', 'details' => 'All 12 participants']],
  664. ],
  665. ];
  666. }
  667. #[DataProvider('dataAddConversationNotify')]
  668. public function testAddConversationNotify(string $search, array $roomMocks, array $participantMocks, ?int $totalCount, array $expected): void {
  669. $room = $this->createMock(Room::class);
  670. foreach ($roomMocks as $method => $return) {
  671. $room->expects($this->once())
  672. ->method($method)
  673. ->willReturn($return);
  674. }
  675. $participant = $this->createMock(Participant::class);
  676. foreach ($participantMocks as $method => $return) {
  677. $participant->expects($this->once())
  678. ->method($method)
  679. ->willReturn($return);
  680. }
  681. if ($totalCount !== null) {
  682. $this->participantService->method('getNumberOfUsers')
  683. ->willReturn($totalCount);
  684. }
  685. $actual = $this->chatManager->addConversationNotify([], $search, $room, $participant);
  686. $this->assertEquals($expected, $actual);
  687. }
  688. #[DataProvider('dataIsSharedFile')]
  689. public function testIsSharedFile(string $message, bool $expected): void {
  690. $actual = $this->chatManager->isSharedFile($message);
  691. $this->assertEquals($expected, $actual);
  692. }
  693. public static function dataIsSharedFile(): array {
  694. return [
  695. ['', false],
  696. [json_encode([]), false],
  697. [json_encode(['parameters' => '']), false],
  698. [json_encode(['parameters' => []]), false],
  699. [json_encode(['parameters' => ['share' => null]]), false],
  700. [json_encode(['parameters' => ['share' => '']]), false],
  701. [json_encode(['parameters' => ['share' => []]]), false],
  702. [json_encode(['parameters' => ['share' => 0]]), false],
  703. [json_encode(['parameters' => ['share' => 1]]), true],
  704. ];
  705. }
  706. #[DataProvider('dataFilterCommentsWithNonExistingFiles')]
  707. public function testFilterCommentsWithNonExistingFiles(array $list, int $expectedCount): void {
  708. // Transform text messages in instance of comment and mock with the message
  709. foreach ($list as $key => $message) {
  710. $list[$key] = $this->createMock(IComment::class);
  711. $list[$key]->method('getMessage')
  712. ->willReturn($message);
  713. $messageDecoded = json_decode($message, true);
  714. if (isset($messageDecoded['parameters']['share']) && $messageDecoded['parameters']['share'] === 'notExists') {
  715. $this->shareProvider->expects($this->once())
  716. ->method('getShareById')
  717. ->with('notExists')
  718. ->willThrowException(new ShareNotFound());
  719. }
  720. }
  721. if (count($list) !== $expectedCount) {
  722. }
  723. $result = $this->chatManager->filterCommentsWithNonExistingFiles($list);
  724. $this->assertCount($expectedCount, $result);
  725. }
  726. public static function dataFilterCommentsWithNonExistingFiles(): array {
  727. return [
  728. [[], 0],
  729. [[json_encode(['parameters' => ['not a shared file']])], 1],
  730. [[json_encode(['parameters' => ['share' => 'notExists']])], 0],
  731. [[json_encode(['parameters' => ['share' => 1]])], 1],
  732. ];
  733. }
  734. }