UserStatusControllerTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2020, Georg Ehrke
  5. *
  6. * @author Georg Ehrke <oc.list@georgehrke.com>
  7. * @author Joas Schilling <coding@schilljs.com>
  8. *
  9. * @license GNU AGPL version 3 or any later version
  10. *
  11. * This program is free software: you can redistribute it and/or modify
  12. * it under the terms of the GNU Affero General Public License as
  13. * published by the Free Software Foundation, either version 3 of the
  14. * License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU Affero General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Affero General Public License
  22. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. *
  24. */
  25. namespace OCA\UserStatus\Tests\Controller;
  26. use OCA\UserStatus\Controller\UserStatusController;
  27. use OCA\UserStatus\Db\UserStatus;
  28. use OCA\UserStatus\Exception\InvalidClearAtException;
  29. use OCA\UserStatus\Exception\InvalidMessageIdException;
  30. use OCA\UserStatus\Exception\InvalidStatusIconException;
  31. use OCA\UserStatus\Exception\InvalidStatusTypeException;
  32. use OCA\UserStatus\Exception\StatusMessageTooLongException;
  33. use OCA\UserStatus\Service\StatusService;
  34. use OCP\AppFramework\Db\DoesNotExistException;
  35. use OCP\AppFramework\OCS\OCSBadRequestException;
  36. use OCP\AppFramework\OCS\OCSNotFoundException;
  37. use OCP\ILogger;
  38. use OCP\IRequest;
  39. use Test\TestCase;
  40. use Throwable;
  41. class UserStatusControllerTest extends TestCase {
  42. /** @var ILogger|\PHPUnit\Framework\MockObject\MockObject */
  43. private $logger;
  44. /** @var StatusService|\PHPUnit\Framework\MockObject\MockObject */
  45. private $service;
  46. /** @var UserStatusController */
  47. private $controller;
  48. protected function setUp(): void {
  49. parent::setUp();
  50. $request = $this->createMock(IRequest::class);
  51. $userId = 'john.doe';
  52. $this->logger = $this->createMock(ILogger::class);
  53. $this->service = $this->createMock(StatusService::class);
  54. $this->controller = new UserStatusController('user_status', $request, $userId, $this->logger, $this->service);
  55. }
  56. public function testGetStatus(): void {
  57. $userStatus = $this->getUserStatus();
  58. $this->service->expects($this->once())
  59. ->method('findByUserId')
  60. ->with('john.doe')
  61. ->willReturn($userStatus);
  62. $response = $this->controller->getStatus();
  63. $this->assertEquals([
  64. 'userId' => 'john.doe',
  65. 'status' => 'invisible',
  66. 'icon' => '🏝',
  67. 'message' => 'On vacation',
  68. 'clearAt' => 60000,
  69. 'statusIsUserDefined' => true,
  70. 'messageIsPredefined' => false,
  71. 'messageId' => null,
  72. ], $response->getData());
  73. }
  74. public function testGetStatusDoesNotExist(): void {
  75. $this->service->expects($this->once())
  76. ->method('findByUserId')
  77. ->with('john.doe')
  78. ->willThrowException(new DoesNotExistException(''));
  79. $this->expectException(OCSNotFoundException::class);
  80. $this->expectExceptionMessage('No status for the current user');
  81. $this->controller->getStatus();
  82. }
  83. /**
  84. * @param string $statusType
  85. * @param string|null $statusIcon
  86. * @param string|null $message
  87. * @param int|null $clearAt
  88. * @param bool $expectSuccess
  89. * @param bool $expectException
  90. * @param Throwable|null $exception
  91. * @param bool $expectLogger
  92. * @param string|null $expectedLogMessage
  93. *
  94. * @dataProvider setStatusDataProvider
  95. */
  96. public function testSetStatus(string $statusType,
  97. ?string $statusIcon,
  98. ?string $message,
  99. ?int $clearAt,
  100. bool $expectSuccess,
  101. bool $expectException,
  102. ?Throwable $exception,
  103. bool $expectLogger,
  104. ?string $expectedLogMessage): void {
  105. $userStatus = $this->getUserStatus();
  106. if ($expectException) {
  107. $this->service->expects($this->once())
  108. ->method('setStatus')
  109. ->with('john.doe', $statusType, null, true)
  110. ->willThrowException($exception);
  111. } else {
  112. $this->service->expects($this->once())
  113. ->method('setStatus')
  114. ->with('john.doe', $statusType, null, true)
  115. ->willReturn($userStatus);
  116. }
  117. if ($expectLogger) {
  118. $this->logger->expects($this->once())
  119. ->method('debug')
  120. ->with($expectedLogMessage);
  121. }
  122. if ($expectException) {
  123. $this->expectException(OCSBadRequestException::class);
  124. $this->expectExceptionMessage('Original exception message');
  125. }
  126. $response = $this->controller->setStatus($statusType);
  127. if ($expectSuccess) {
  128. $this->assertEquals([
  129. 'userId' => 'john.doe',
  130. 'status' => 'invisible',
  131. 'icon' => '🏝',
  132. 'message' => 'On vacation',
  133. 'clearAt' => 60000,
  134. 'statusIsUserDefined' => true,
  135. 'messageIsPredefined' => false,
  136. 'messageId' => null,
  137. ], $response->getData());
  138. }
  139. }
  140. public function setStatusDataProvider(): array {
  141. return [
  142. ['busy', '👨🏽‍💻', 'Busy developing the status feature', 500, true, false, null, false, null],
  143. ['busy', '👨🏽‍💻', 'Busy developing the status feature', 500, false, true, new InvalidStatusTypeException('Original exception message'), true,
  144. 'New user-status for "john.doe" was rejected due to an invalid status type "busy"'],
  145. ];
  146. }
  147. /**
  148. * @param string $messageId
  149. * @param int|null $clearAt
  150. * @param bool $expectSuccess
  151. * @param bool $expectException
  152. * @param Throwable|null $exception
  153. * @param bool $expectLogger
  154. * @param string|null $expectedLogMessage
  155. *
  156. * @dataProvider setPredefinedMessageDataProvider
  157. */
  158. public function testSetPredefinedMessage(string $messageId,
  159. ?int $clearAt,
  160. bool $expectSuccess,
  161. bool $expectException,
  162. ?Throwable $exception,
  163. bool $expectLogger,
  164. ?string $expectedLogMessage): void {
  165. $userStatus = $this->getUserStatus();
  166. if ($expectException) {
  167. $this->service->expects($this->once())
  168. ->method('setPredefinedMessage')
  169. ->with('john.doe', $messageId, $clearAt)
  170. ->willThrowException($exception);
  171. } else {
  172. $this->service->expects($this->once())
  173. ->method('setPredefinedMessage')
  174. ->with('john.doe', $messageId, $clearAt)
  175. ->willReturn($userStatus);
  176. }
  177. if ($expectLogger) {
  178. $this->logger->expects($this->once())
  179. ->method('debug')
  180. ->with($expectedLogMessage);
  181. }
  182. if ($expectException) {
  183. $this->expectException(OCSBadRequestException::class);
  184. $this->expectExceptionMessage('Original exception message');
  185. }
  186. $response = $this->controller->setPredefinedMessage($messageId, $clearAt);
  187. if ($expectSuccess) {
  188. $this->assertEquals([
  189. 'userId' => 'john.doe',
  190. 'status' => 'invisible',
  191. 'icon' => '🏝',
  192. 'message' => 'On vacation',
  193. 'clearAt' => 60000,
  194. 'statusIsUserDefined' => true,
  195. 'messageIsPredefined' => false,
  196. 'messageId' => null,
  197. ], $response->getData());
  198. }
  199. }
  200. public function setPredefinedMessageDataProvider(): array {
  201. return [
  202. ['messageId-42', 500, true, false, null, false, null],
  203. ['messageId-42', 500, false, true, new InvalidClearAtException('Original exception message'), true,
  204. 'New user-status for "john.doe" was rejected due to an invalid clearAt value "500"'],
  205. ['messageId-42', 500, false, true, new InvalidMessageIdException('Original exception message'), true,
  206. 'New user-status for "john.doe" was rejected due to an invalid message-id "messageId-42"'],
  207. ];
  208. }
  209. /**
  210. * @param string|null $statusIcon
  211. * @param string $message
  212. * @param int|null $clearAt
  213. * @param bool $expectSuccess
  214. * @param bool $expectException
  215. * @param Throwable|null $exception
  216. * @param bool $expectLogger
  217. * @param string|null $expectedLogMessage
  218. * @param bool $expectSuccessAsReset
  219. *
  220. * @dataProvider setCustomMessageDataProvider
  221. */
  222. public function testSetCustomMessage(?string $statusIcon,
  223. string $message,
  224. ?int $clearAt,
  225. bool $expectSuccess,
  226. bool $expectException,
  227. ?Throwable $exception,
  228. bool $expectLogger,
  229. ?string $expectedLogMessage,
  230. bool $expectSuccessAsReset = false): void {
  231. $userStatus = $this->getUserStatus();
  232. if ($expectException) {
  233. $this->service->expects($this->once())
  234. ->method('setCustomMessage')
  235. ->with('john.doe', $statusIcon, $message, $clearAt)
  236. ->willThrowException($exception);
  237. } else {
  238. if ($expectSuccessAsReset) {
  239. $this->service->expects($this->never())
  240. ->method('setCustomMessage');
  241. $this->service->expects($this->once())
  242. ->method('clearMessage')
  243. ->with('john.doe');
  244. $this->service->expects($this->once())
  245. ->method('findByUserId')
  246. ->with('john.doe')
  247. ->willReturn($userStatus);
  248. } else {
  249. $this->service->expects($this->once())
  250. ->method('setCustomMessage')
  251. ->with('john.doe', $statusIcon, $message, $clearAt)
  252. ->willReturn($userStatus);
  253. $this->service->expects($this->never())
  254. ->method('clearMessage');
  255. }
  256. }
  257. if ($expectLogger) {
  258. $this->logger->expects($this->once())
  259. ->method('debug')
  260. ->with($expectedLogMessage);
  261. }
  262. if ($expectException) {
  263. $this->expectException(OCSBadRequestException::class);
  264. $this->expectExceptionMessage('Original exception message');
  265. }
  266. $response = $this->controller->setCustomMessage($statusIcon, $message, $clearAt);
  267. if ($expectSuccess) {
  268. $this->assertEquals([
  269. 'userId' => 'john.doe',
  270. 'status' => 'invisible',
  271. 'icon' => '🏝',
  272. 'message' => 'On vacation',
  273. 'clearAt' => 60000,
  274. 'statusIsUserDefined' => true,
  275. 'messageIsPredefined' => false,
  276. 'messageId' => null,
  277. ], $response->getData());
  278. }
  279. }
  280. public function setCustomMessageDataProvider(): array {
  281. return [
  282. ['👨🏽‍💻', 'Busy developing the status feature', 500, true, false, null, false, null],
  283. ['👨🏽‍💻', '', 500, true, false, null, false, null, false],
  284. ['👨🏽‍💻', '', 0, true, false, null, false, null, true],
  285. ['👨🏽‍💻', 'Busy developing the status feature', 500, false, true, new InvalidClearAtException('Original exception message'), true,
  286. 'New user-status for "john.doe" was rejected due to an invalid clearAt value "500"'],
  287. ['👨🏽‍💻', 'Busy developing the status feature', 500, false, true, new InvalidStatusIconException('Original exception message'), true,
  288. 'New user-status for "john.doe" was rejected due to an invalid icon value "👨🏽‍💻"'],
  289. ['👨🏽‍💻', 'Busy developing the status feature', 500, false, true, new StatusMessageTooLongException('Original exception message'), true,
  290. 'New user-status for "john.doe" was rejected due to a too long status message.'],
  291. ];
  292. }
  293. public function testClearStatus(): void {
  294. $this->service->expects($this->once())
  295. ->method('clearStatus')
  296. ->with('john.doe');
  297. $response = $this->controller->clearStatus();
  298. $this->assertEquals([], $response->getData());
  299. }
  300. public function testClearMessage(): void {
  301. $this->service->expects($this->once())
  302. ->method('clearMessage')
  303. ->with('john.doe');
  304. $response = $this->controller->clearMessage();
  305. $this->assertEquals([], $response->getData());
  306. }
  307. private function getUserStatus(): UserStatus {
  308. $userStatus = new UserStatus();
  309. $userStatus->setId(1337);
  310. $userStatus->setUserId('john.doe');
  311. $userStatus->setStatus('invisible');
  312. $userStatus->setStatusTimestamp(5000);
  313. $userStatus->setIsUserDefined(true);
  314. $userStatus->setCustomIcon('🏝');
  315. $userStatus->setCustomMessage('On vacation');
  316. $userStatus->setClearAt(60000);
  317. return $userStatus;
  318. }
  319. }