NavigationManagerTest.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace Test;
  8. use OC\App\AppManager;
  9. use OC\Group\Manager;
  10. use OC\NavigationManager;
  11. use OC\SubAdmin;
  12. use OCP\IConfig;
  13. use OCP\IGroupManager;
  14. use OCP\IL10N;
  15. use OCP\IURLGenerator;
  16. use OCP\IUser;
  17. use OCP\IUserSession;
  18. use OCP\L10N\IFactory;
  19. use Psr\Log\LoggerInterface;
  20. class NavigationManagerTest extends TestCase {
  21. /** @var AppManager|\PHPUnit\Framework\MockObject\MockObject */
  22. protected $appManager;
  23. /** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */
  24. protected $urlGenerator;
  25. /** @var IFactory|\PHPUnit\Framework\MockObject\MockObject */
  26. protected $l10nFac;
  27. /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */
  28. protected $userSession;
  29. /** @var IGroupManager|\PHPUnit\Framework\MockObject\MockObject */
  30. protected $groupManager;
  31. /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
  32. protected $config;
  33. /** @var \OC\NavigationManager */
  34. protected $navigationManager;
  35. protected LoggerInterface $logger;
  36. protected function setUp(): void {
  37. parent::setUp();
  38. $this->appManager = $this->createMock(AppManager::class);
  39. $this->urlGenerator = $this->createMock(IURLGenerator::class);
  40. $this->l10nFac = $this->createMock(IFactory::class);
  41. $this->userSession = $this->createMock(IUserSession::class);
  42. $this->groupManager = $this->createMock(Manager::class);
  43. $this->config = $this->createMock(IConfig::class);
  44. $this->logger = $this->createMock(LoggerInterface::class);
  45. $this->navigationManager = new NavigationManager(
  46. $this->appManager,
  47. $this->urlGenerator,
  48. $this->l10nFac,
  49. $this->userSession,
  50. $this->groupManager,
  51. $this->config,
  52. $this->logger,
  53. );
  54. $this->navigationManager->clear(false);
  55. }
  56. public function addArrayData() {
  57. return [
  58. [
  59. 'entry id' => [
  60. 'id' => 'entry id',
  61. 'name' => 'link text',
  62. 'order' => 1,
  63. 'icon' => 'optional',
  64. 'href' => 'url',
  65. 'type' => 'settings',
  66. 'classes' => '',
  67. 'unread' => 0
  68. ],
  69. 'entry id2' => [
  70. 'id' => 'entry id',
  71. 'name' => 'link text',
  72. 'order' => 1,
  73. 'icon' => 'optional',
  74. 'href' => 'url',
  75. 'active' => false,
  76. 'type' => 'settings',
  77. 'classes' => '',
  78. 'unread' => 0
  79. ]
  80. ],
  81. [
  82. 'entry id' => [
  83. 'id' => 'entry id',
  84. 'name' => 'link text',
  85. 'order' => 1,
  86. //'icon' => 'optional',
  87. 'href' => 'url',
  88. 'active' => true,
  89. 'unread' => 0,
  90. ],
  91. 'entry id2' => [
  92. 'id' => 'entry id',
  93. 'name' => 'link text',
  94. 'order' => 1,
  95. 'icon' => '',
  96. 'href' => 'url',
  97. 'active' => false,
  98. 'type' => 'link',
  99. 'classes' => '',
  100. 'unread' => 0,
  101. 'default' => true,
  102. ]
  103. ]
  104. ];
  105. }
  106. /**
  107. * @dataProvider addArrayData
  108. *
  109. * @param array $entry
  110. * @param array $expectedEntry
  111. */
  112. public function testAddArray(array $entry, array $expectedEntry): void {
  113. $this->assertEmpty($this->navigationManager->getAll('all'), 'Expected no navigation entry exists');
  114. $this->navigationManager->add($entry);
  115. $navigationEntries = $this->navigationManager->getAll('all');
  116. $this->assertCount(1, $navigationEntries, 'Expected that 1 navigation entry exists');
  117. $this->assertEquals($expectedEntry, $navigationEntries['entry id']);
  118. $this->navigationManager->clear(false);
  119. $this->assertEmpty($this->navigationManager->getAll('all'), 'Expected no navigation entry exists after clear()');
  120. }
  121. /**
  122. * @dataProvider addArrayData
  123. *
  124. * @param array $entry
  125. * @param array $expectedEntry
  126. */
  127. public function testAddClosure(array $entry, array $expectedEntry): void {
  128. global $testAddClosureNumberOfCalls;
  129. $testAddClosureNumberOfCalls = 0;
  130. $this->navigationManager->add(function () use ($entry) {
  131. global $testAddClosureNumberOfCalls;
  132. $testAddClosureNumberOfCalls++;
  133. return $entry;
  134. });
  135. $this->assertEquals(0, $testAddClosureNumberOfCalls, 'Expected that the closure is not called by add()');
  136. $navigationEntries = $this->navigationManager->getAll('all');
  137. $this->assertEquals(1, $testAddClosureNumberOfCalls, 'Expected that the closure is called by getAll()');
  138. $this->assertCount(1, $navigationEntries, 'Expected that 1 navigation entry exists');
  139. $this->assertEquals($expectedEntry, $navigationEntries['entry id']);
  140. $navigationEntries = $this->navigationManager->getAll('all');
  141. $this->assertEquals(1, $testAddClosureNumberOfCalls, 'Expected that the closure is only called once for getAll()');
  142. $this->assertCount(1, $navigationEntries, 'Expected that 1 navigation entry exists');
  143. $this->assertEquals($expectedEntry, $navigationEntries['entry id']);
  144. $this->navigationManager->clear(false);
  145. $this->assertEmpty($this->navigationManager->getAll('all'), 'Expected no navigation entry exists after clear()');
  146. }
  147. public function testAddArrayClearGetAll(): void {
  148. $entry = [
  149. 'id' => 'entry id',
  150. 'name' => 'link text',
  151. 'order' => 1,
  152. 'icon' => 'optional',
  153. 'href' => 'url'
  154. ];
  155. $this->assertEmpty($this->navigationManager->getAll(), 'Expected no navigation entry exists');
  156. $this->navigationManager->add($entry);
  157. $this->navigationManager->clear(false);
  158. $this->assertEmpty($this->navigationManager->getAll(), 'Expected no navigation entry exists after clear()');
  159. }
  160. public function testAddClosureClearGetAll(): void {
  161. $this->assertEmpty($this->navigationManager->getAll(), 'Expected no navigation entry exists');
  162. $entry = [
  163. 'id' => 'entry id',
  164. 'name' => 'link text',
  165. 'order' => 1,
  166. 'icon' => 'optional',
  167. 'href' => 'url'
  168. ];
  169. global $testAddClosureNumberOfCalls;
  170. $testAddClosureNumberOfCalls = 0;
  171. $this->navigationManager->add(function () use ($entry) {
  172. global $testAddClosureNumberOfCalls;
  173. $testAddClosureNumberOfCalls++;
  174. return $entry;
  175. });
  176. $this->assertEquals(0, $testAddClosureNumberOfCalls, 'Expected that the closure is not called by add()');
  177. $this->navigationManager->clear(false);
  178. $this->assertEquals(0, $testAddClosureNumberOfCalls, 'Expected that the closure is not called by clear()');
  179. $this->assertEmpty($this->navigationManager->getAll(), 'Expected no navigation entry exists after clear()');
  180. $this->assertEquals(0, $testAddClosureNumberOfCalls, 'Expected that the closure is not called by getAll()');
  181. }
  182. /**
  183. * @dataProvider providesNavigationConfig
  184. */
  185. public function testWithAppManager($expected, $navigation, $isAdmin = false): void {
  186. $l = $this->createMock(IL10N::class);
  187. $l->expects($this->any())->method('t')->willReturnCallback(function ($text, $parameters = []) {
  188. return vsprintf($text, $parameters);
  189. });
  190. /* Return default value */
  191. $this->config->method('getUserValue')
  192. ->willReturnArgument(3);
  193. $this->appManager->expects($this->any())
  194. ->method('isEnabledForUser')
  195. ->with('theming')
  196. ->willReturn(true);
  197. $this->appManager->expects($this->once())
  198. ->method('getAppInfo')
  199. ->with('test')
  200. ->willReturn($navigation);
  201. $this->urlGenerator->expects($this->any())
  202. ->method('imagePath')
  203. ->willReturnCallback(function ($appName, $file) {
  204. return "/apps/$appName/img/$file";
  205. });
  206. $this->appManager->expects($this->any())
  207. ->method('getAppIcon')
  208. ->willReturnCallback(fn (string $appName) => "/apps/$appName/img/app.svg");
  209. $this->l10nFac->expects($this->any())->method('get')->willReturn($l);
  210. $this->urlGenerator->expects($this->any())->method('linkToRoute')->willReturnCallback(function ($route) {
  211. if ($route === 'core.login.logout') {
  212. return 'https://example.com/logout';
  213. }
  214. return '/apps/test/';
  215. });
  216. $user = $this->createMock(IUser::class);
  217. $user->expects($this->any())->method('getUID')->willReturn('user001');
  218. $this->userSession->expects($this->any())->method('getUser')->willReturn($user);
  219. $this->userSession->expects($this->any())->method('isLoggedIn')->willReturn(true);
  220. $this->appManager->expects($this->any())
  221. ->method('getEnabledAppsForUser')
  222. ->with($user)
  223. ->willReturn(['test']);
  224. $this->groupManager->expects($this->any())->method('isAdmin')->willReturn($isAdmin);
  225. $subadmin = $this->createMock(SubAdmin::class);
  226. $subadmin->expects($this->any())->method('isSubAdmin')->with($user)->willReturn(false);
  227. $this->groupManager->expects($this->any())->method('getSubAdmin')->willReturn($subadmin);
  228. $this->navigationManager->clear();
  229. $entries = $this->navigationManager->getAll('all');
  230. $this->assertEquals($expected, $entries);
  231. }
  232. public function providesNavigationConfig() {
  233. $apps = [
  234. 'core_apps' => [
  235. 'id' => 'core_apps',
  236. 'order' => 5,
  237. 'href' => '/apps/test/',
  238. 'icon' => '/apps/settings/img/apps.svg',
  239. 'name' => 'Apps',
  240. 'active' => false,
  241. 'type' => 'settings',
  242. 'classes' => '',
  243. 'unread' => 0
  244. ]
  245. ];
  246. $defaults = [
  247. 'profile' => [
  248. 'type' => 'settings',
  249. 'id' => 'profile',
  250. 'order' => 1,
  251. 'href' => '/apps/test/',
  252. 'name' => 'View profile',
  253. 'icon' => '',
  254. 'active' => false,
  255. 'classes' => '',
  256. 'unread' => 0,
  257. ],
  258. 'accessibility_settings' => [
  259. 'type' => 'settings',
  260. 'id' => 'accessibility_settings',
  261. 'order' => 2,
  262. 'href' => '/apps/test/',
  263. 'name' => 'Appearance and accessibility',
  264. 'icon' => '/apps/theming/img/accessibility-dark.svg',
  265. 'active' => false,
  266. 'classes' => '',
  267. 'unread' => 0,
  268. ],
  269. 'settings' => [
  270. 'id' => 'settings',
  271. 'order' => 3,
  272. 'href' => '/apps/test/',
  273. 'icon' => '/apps/settings/img/admin.svg',
  274. 'name' => 'Settings',
  275. 'active' => false,
  276. 'type' => 'settings',
  277. 'classes' => '',
  278. 'unread' => 0
  279. ],
  280. 'logout' => [
  281. 'id' => 'logout',
  282. 'order' => 99999,
  283. 'href' => 'https://example.com/logout?requesttoken=' . urlencode(\OCP\Util::callRegister()),
  284. 'icon' => '/apps/core/img/actions/logout.svg',
  285. 'name' => 'Log out',
  286. 'active' => false,
  287. 'type' => 'settings',
  288. 'classes' => '',
  289. 'unread' => 0
  290. ]
  291. ];
  292. $adminSettings = [
  293. 'accessibility_settings' => $defaults['accessibility_settings'],
  294. 'settings' => [
  295. 'id' => 'settings',
  296. 'order' => 3,
  297. 'href' => '/apps/test/',
  298. 'icon' => '/apps/settings/img/personal.svg',
  299. 'name' => 'Personal settings',
  300. 'active' => false,
  301. 'type' => 'settings',
  302. 'classes' => '',
  303. 'unread' => 0
  304. ],
  305. 'admin_settings' => [
  306. 'id' => 'admin_settings',
  307. 'order' => 4,
  308. 'href' => '/apps/test/',
  309. 'icon' => '/apps/settings/img/admin.svg',
  310. 'name' => 'Administration settings',
  311. 'active' => false,
  312. 'type' => 'settings',
  313. 'classes' => '',
  314. 'unread' => 0
  315. ]
  316. ];
  317. return [
  318. 'minimalistic' => [
  319. array_merge(
  320. ['profile' => $defaults['profile']],
  321. ['accessibility_settings' => $defaults['accessibility_settings']],
  322. ['settings' => $defaults['settings']],
  323. ['test' => [
  324. 'id' => 'test',
  325. 'order' => 100,
  326. 'href' => '/apps/test/',
  327. 'icon' => '/apps/test/img/app.svg',
  328. 'name' => 'Test',
  329. 'active' => false,
  330. 'type' => 'link',
  331. 'classes' => '',
  332. 'unread' => 0,
  333. 'default' => true,
  334. 'app' => 'test',
  335. ]],
  336. ['logout' => $defaults['logout']]
  337. ),
  338. ['navigations' => [
  339. 'navigation' => [
  340. ['route' => 'test.page.index', 'name' => 'Test']
  341. ]
  342. ]]
  343. ],
  344. 'minimalistic-settings' => [
  345. array_merge(
  346. ['profile' => $defaults['profile']],
  347. ['accessibility_settings' => $defaults['accessibility_settings']],
  348. ['settings' => $defaults['settings']],
  349. ['test' => [
  350. 'id' => 'test',
  351. 'order' => 100,
  352. 'href' => '/apps/test/',
  353. 'icon' => '/apps/test/img/app.svg',
  354. 'name' => 'Test',
  355. 'active' => false,
  356. 'type' => 'settings',
  357. 'classes' => '',
  358. 'unread' => 0,
  359. ]],
  360. ['logout' => $defaults['logout']]
  361. ),
  362. ['navigations' => [
  363. 'navigation' => [
  364. ['route' => 'test.page.index', 'name' => 'Test', 'type' => 'settings']
  365. ],
  366. ]]
  367. ],
  368. 'with-multiple' => [
  369. array_merge(
  370. ['profile' => $defaults['profile']],
  371. ['accessibility_settings' => $defaults['accessibility_settings']],
  372. ['settings' => $defaults['settings']],
  373. ['test' => [
  374. 'id' => 'test',
  375. 'order' => 100,
  376. 'href' => '/apps/test/',
  377. 'icon' => '/apps/test/img/app.svg',
  378. 'name' => 'Test',
  379. 'active' => false,
  380. 'type' => 'link',
  381. 'classes' => '',
  382. 'unread' => 0,
  383. 'default' => false,
  384. 'app' => 'test',
  385. ],
  386. 'test1' => [
  387. 'id' => 'test1',
  388. 'order' => 50,
  389. 'href' => '/apps/test/',
  390. 'icon' => '/apps/test/img/app.svg',
  391. 'name' => 'Other test',
  392. 'active' => false,
  393. 'type' => 'link',
  394. 'classes' => '',
  395. 'unread' => 0,
  396. 'default' => true, // because of order
  397. 'app' => 'test',
  398. ]],
  399. ['logout' => $defaults['logout']]
  400. ),
  401. ['navigations' => [
  402. 'navigation' => [
  403. ['route' => 'test.page.index', 'name' => 'Test'],
  404. ['route' => 'test.page.index', 'name' => 'Other test', 'order' => 50],
  405. ]
  406. ]]
  407. ],
  408. 'admin' => [
  409. array_merge(
  410. ['profile' => $defaults['profile']],
  411. $adminSettings,
  412. $apps,
  413. ['test' => [
  414. 'id' => 'test',
  415. 'order' => 100,
  416. 'href' => '/apps/test/',
  417. 'icon' => '/apps/test/img/app.svg',
  418. 'name' => 'Test',
  419. 'active' => false,
  420. 'type' => 'link',
  421. 'classes' => '',
  422. 'unread' => 0,
  423. 'default' => true,
  424. 'app' => 'test',
  425. ]],
  426. ['logout' => $defaults['logout']]
  427. ),
  428. ['navigations' => [
  429. 'navigation' => [
  430. ['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index', 'name' => 'Test']
  431. ],
  432. ]],
  433. true
  434. ],
  435. 'no name' => [
  436. array_merge(
  437. ['profile' => $defaults['profile']],
  438. $adminSettings,
  439. $apps,
  440. ['logout' => $defaults['logout']]
  441. ),
  442. ['navigations' => [
  443. 'navigation' => [
  444. ['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index']
  445. ],
  446. ]],
  447. true
  448. ],
  449. 'no admin' => [
  450. $defaults,
  451. ['navigations' => [
  452. 'navigation' => [
  453. ['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index', 'name' => 'Test']
  454. ],
  455. ]],
  456. ]
  457. ];
  458. }
  459. public function testWithAppManagerAndApporder(): void {
  460. $l = $this->createMock(IL10N::class);
  461. $l->expects($this->any())->method('t')->willReturnCallback(function ($text, $parameters = []) {
  462. return vsprintf($text, $parameters);
  463. });
  464. $testOrder = 12;
  465. $expected = [
  466. 'test' => [
  467. 'type' => 'link',
  468. 'id' => 'test',
  469. 'order' => $testOrder,
  470. 'href' => '/apps/test/',
  471. 'name' => 'Test',
  472. 'icon' => '/apps/test/img/app.svg',
  473. 'active' => false,
  474. 'classes' => '',
  475. 'unread' => 0,
  476. 'default' => true,
  477. 'app' => 'test',
  478. ],
  479. ];
  480. $navigation = ['navigations' => [
  481. 'navigation' => [
  482. ['route' => 'test.page.index', 'name' => 'Test']
  483. ],
  484. ]];
  485. $this->config->method('getUserValue')
  486. ->willReturnCallback(
  487. function (string $userId, string $appName, string $key, mixed $default = '') use ($testOrder) {
  488. $this->assertEquals('user001', $userId);
  489. if ($key === 'apporder') {
  490. return json_encode(['test' => ['app' => 'test', 'order' => $testOrder]]);
  491. }
  492. return $default;
  493. }
  494. );
  495. $this->appManager->expects($this->any())
  496. ->method('isEnabledForUser')
  497. ->with('theming')
  498. ->willReturn(true);
  499. $this->appManager->expects($this->once())->method('getAppInfo')->with('test')->willReturn($navigation);
  500. $this->appManager->expects($this->once())->method('getAppIcon')->with('test')->willReturn('/apps/test/img/app.svg');
  501. $this->l10nFac->expects($this->any())->method('get')->willReturn($l);
  502. $this->urlGenerator->expects($this->any())->method('imagePath')->willReturnCallback(function ($appName, $file) {
  503. return "/apps/$appName/img/$file";
  504. });
  505. $this->urlGenerator->expects($this->any())->method('linkToRoute')->willReturnCallback(function ($route) {
  506. if ($route === 'core.login.logout') {
  507. return 'https://example.com/logout';
  508. }
  509. return '/apps/test/';
  510. });
  511. $user = $this->createMock(IUser::class);
  512. $user->expects($this->any())->method('getUID')->willReturn('user001');
  513. $this->userSession->expects($this->any())->method('getUser')->willReturn($user);
  514. $this->userSession->expects($this->any())->method('isLoggedIn')->willReturn(true);
  515. $this->appManager->expects($this->any())
  516. ->method('getEnabledAppsForUser')
  517. ->with($user)
  518. ->willReturn(['test']);
  519. $this->groupManager->expects($this->any())->method('isAdmin')->willReturn(false);
  520. $subadmin = $this->createMock(SubAdmin::class);
  521. $subadmin->expects($this->any())->method('isSubAdmin')->with($user)->willReturn(false);
  522. $this->groupManager->expects($this->any())->method('getSubAdmin')->willReturn($subadmin);
  523. $this->navigationManager->clear();
  524. $entries = $this->navigationManager->getAll();
  525. $this->assertEquals($expected, $entries);
  526. }
  527. public static function provideDefaultEntries(): array {
  528. return [
  529. // none specified, default to files
  530. [
  531. '',
  532. '',
  533. '{}',
  534. true,
  535. 'files',
  536. ],
  537. // none specified, without fallback
  538. [
  539. '',
  540. '',
  541. '{}',
  542. false,
  543. '',
  544. ],
  545. // unexisting or inaccessible app specified, default to files
  546. [
  547. 'unexist',
  548. '',
  549. '{}',
  550. true,
  551. 'files',
  552. ],
  553. // unexisting or inaccessible app specified, without fallbacks
  554. [
  555. 'unexist',
  556. '',
  557. '{}',
  558. false,
  559. '',
  560. ],
  561. // non-standard app
  562. [
  563. 'settings',
  564. '',
  565. '{}',
  566. true,
  567. 'settings',
  568. ],
  569. // non-standard app, without fallback
  570. [
  571. 'settings',
  572. '',
  573. '{}',
  574. false,
  575. 'settings',
  576. ],
  577. // non-standard app with fallback
  578. [
  579. 'unexist,settings',
  580. '',
  581. '{}',
  582. true,
  583. 'settings',
  584. ],
  585. // system default app and user apporder
  586. [
  587. // system default is settings
  588. 'unexist,settings',
  589. '',
  590. // apporder says default app is files (order is lower)
  591. '{"files_id":{"app":"files","order":1},"settings_id":{"app":"settings","order":2}}',
  592. true,
  593. // system default should override apporder
  594. 'settings'
  595. ],
  596. // user-customized defaultapp
  597. [
  598. '',
  599. 'files',
  600. '',
  601. true,
  602. 'files',
  603. ],
  604. // user-customized defaultapp with systemwide
  605. [
  606. 'unexist,settings',
  607. 'files',
  608. '',
  609. true,
  610. 'files',
  611. ],
  612. // user-customized defaultapp with system wide and apporder
  613. [
  614. 'unexist,settings',
  615. 'files',
  616. '{"settings_id":{"app":"settings","order":1},"files_id":{"app":"files","order":2}}',
  617. true,
  618. 'files',
  619. ],
  620. // user-customized apporder fallback
  621. [
  622. '',
  623. '',
  624. '{"settings_id":{"app":"settings","order":1},"files":{"app":"files","order":2}}',
  625. true,
  626. 'settings',
  627. ],
  628. // user-customized apporder fallback with missing app key (entries added by closures does not always have an app key set (Nextcloud 27 spreed app for example))
  629. [
  630. '',
  631. '',
  632. '{"spreed":{"order":1},"files":{"app":"files","order":2}}',
  633. true,
  634. 'files',
  635. ],
  636. // user-customized apporder, but called without fallback
  637. [
  638. '',
  639. '',
  640. '{"settings":{"app":"settings","order":1},"files":{"app":"files","order":2}}',
  641. false,
  642. '',
  643. ],
  644. // user-customized apporder with an app that has multiple routes
  645. [
  646. '',
  647. '',
  648. '{"settings_id":{"app":"settings","order":1},"settings_id_2":{"app":"settings","order":3},"id_files":{"app":"files","order":2}}',
  649. true,
  650. 'settings',
  651. ],
  652. ];
  653. }
  654. /**
  655. * @dataProvider provideDefaultEntries
  656. */
  657. public function testGetDefaultEntryIdForUser($defaultApps, $userDefaultApps, $userApporder, $withFallbacks, $expectedApp): void {
  658. $this->navigationManager->add([
  659. 'id' => 'files',
  660. ]);
  661. $this->navigationManager->add([
  662. 'id' => 'settings',
  663. ]);
  664. $this->appManager->method('getInstalledApps')->willReturn([]);
  665. $user = $this->createMock(IUser::class);
  666. $user->method('getUID')->willReturn('user1');
  667. $this->userSession->expects($this->once())
  668. ->method('getUser')
  669. ->willReturn($user);
  670. $this->config->expects($this->once())
  671. ->method('getSystemValueString')
  672. ->with('defaultapp', $this->anything())
  673. ->willReturn($defaultApps);
  674. $this->config->expects($this->atLeastOnce())
  675. ->method('getUserValue')
  676. ->willReturnMap([
  677. ['user1', 'core', 'defaultapp', '', $userDefaultApps],
  678. ['user1', 'core', 'apporder', '[]', $userApporder],
  679. ]);
  680. $this->assertEquals($expectedApp, $this->navigationManager->getDefaultEntryIdForUser(null, $withFallbacks));
  681. }
  682. public function testDefaultEntryUpdated(): void {
  683. $this->appManager->method('getInstalledApps')->willReturn([]);
  684. $user = $this->createMock(IUser::class);
  685. $user->method('getUID')->willReturn('user1');
  686. $this->userSession
  687. ->method('getUser')
  688. ->willReturn($user);
  689. $this->config
  690. ->method('getSystemValueString')
  691. ->with('defaultapp', $this->anything())
  692. ->willReturn('app4,app3,app2,app1');
  693. $this->config
  694. ->method('getUserValue')
  695. ->willReturnMap([
  696. ['user1', 'core', 'defaultapp', '', ''],
  697. ['user1', 'core', 'apporder', '[]', ''],
  698. ]);
  699. $this->navigationManager->add([
  700. 'id' => 'app1',
  701. ]);
  702. $this->assertEquals('app1', $this->navigationManager->getDefaultEntryIdForUser(null, false));
  703. $this->assertEquals(true, $this->navigationManager->get('app1')['default']);
  704. $this->navigationManager->add([
  705. 'id' => 'app3',
  706. ]);
  707. $this->assertEquals('app3', $this->navigationManager->getDefaultEntryIdForUser(null, false));
  708. $this->assertEquals(false, $this->navigationManager->get('app1')['default']);
  709. $this->assertEquals(true, $this->navigationManager->get('app3')['default']);
  710. $this->navigationManager->add([
  711. 'id' => 'app2',
  712. ]);
  713. $this->assertEquals('app3', $this->navigationManager->getDefaultEntryIdForUser(null, false));
  714. $this->assertEquals(false, $this->navigationManager->get('app1')['default']);
  715. $this->assertEquals(false, $this->navigationManager->get('app2')['default']);
  716. $this->assertEquals(true, $this->navigationManager->get('app3')['default']);
  717. $this->navigationManager->add([
  718. 'id' => 'app4',
  719. ]);
  720. $this->assertEquals('app4', $this->navigationManager->getDefaultEntryIdForUser(null, false));
  721. $this->assertEquals(false, $this->navigationManager->get('app1')['default']);
  722. $this->assertEquals(false, $this->navigationManager->get('app2')['default']);
  723. $this->assertEquals(false, $this->navigationManager->get('app3')['default']);
  724. $this->assertEquals(true, $this->navigationManager->get('app4')['default']);
  725. }
  726. }