aboutsummaryrefslogtreecommitdiffstats
path: root/tests/lib/NavigationManagerTest.php
diff options
context:
space:
mode:
Diffstat (limited to 'tests/lib/NavigationManagerTest.php')
-rw-r--r--tests/lib/NavigationManagerTest.php513
1 files changed, 459 insertions, 54 deletions
diff --git a/tests/lib/NavigationManagerTest.php b/tests/lib/NavigationManagerTest.php
index d5c827fe1cb..53d7e81302b 100644
--- a/tests/lib/NavigationManagerTest.php
+++ b/tests/lib/NavigationManagerTest.php
@@ -1,13 +1,9 @@
<?php
+
/**
- * ownCloud
- *
- * @author Joas Schilling
- * @copyright 2015 Joas Schilling nickvergessen@owncloud.com
- *
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace Test;
@@ -16,6 +12,7 @@ use OC\App\AppManager;
use OC\Group\Manager;
use OC\NavigationManager;
use OC\SubAdmin;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig;
use OCP\IGroupManager;
use OCP\IL10N;
@@ -23,6 +20,10 @@ use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserSession;
use OCP\L10N\IFactory;
+use OCP\Navigation\Events\LoadAdditionalEntriesEvent;
+use OCP\Util;
+use PHPUnit\Framework\MockObject\MockObject;
+use Psr\Log\LoggerInterface;
class NavigationManagerTest extends TestCase {
/** @var AppManager|\PHPUnit\Framework\MockObject\MockObject */
@@ -38,8 +39,11 @@ class NavigationManagerTest extends TestCase {
/** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
protected $config;
- /** @var \OC\NavigationManager */
+ protected IEVentDispatcher|MockObject $dispatcher;
+
+ /** @var NavigationManager */
protected $navigationManager;
+ protected LoggerInterface $logger;
protected function setUp(): void {
parent::setUp();
@@ -50,22 +54,26 @@ class NavigationManagerTest extends TestCase {
$this->userSession = $this->createMock(IUserSession::class);
$this->groupManager = $this->createMock(Manager::class);
$this->config = $this->createMock(IConfig::class);
+ $this->logger = $this->createMock(LoggerInterface::class);
+ $this->dispatcher = $this->createMock(IEventDispatcher::class);
$this->navigationManager = new NavigationManager(
$this->appManager,
$this->urlGenerator,
$this->l10nFac,
$this->userSession,
$this->groupManager,
- $this->config
+ $this->config,
+ $this->logger,
+ $this->dispatcher,
);
$this->navigationManager->clear(false);
}
- public function addArrayData() {
+ public static function addArrayData(): array {
return [
[
- 'entry id' => [
+ 'entry' => [
'id' => 'entry id',
'name' => 'link text',
'order' => 1,
@@ -75,7 +83,7 @@ class NavigationManagerTest extends TestCase {
'classes' => '',
'unread' => 0
],
- 'entry id2' => [
+ 'expectedEntry' => [
'id' => 'entry id',
'name' => 'link text',
'order' => 1,
@@ -88,16 +96,16 @@ class NavigationManagerTest extends TestCase {
]
],
[
- 'entry id' => [
+ 'entry' => [
'id' => 'entry id',
'name' => 'link text',
'order' => 1,
//'icon' => 'optional',
'href' => 'url',
'active' => true,
- 'unread' => 0
+ 'unread' => 0,
],
- 'entry id2' => [
+ 'expectedEntry' => [
'id' => 'entry id',
'name' => 'link text',
'order' => 1,
@@ -106,19 +114,20 @@ class NavigationManagerTest extends TestCase {
'active' => false,
'type' => 'link',
'classes' => '',
- 'unread' => 0
+ 'unread' => 0,
+ 'default' => true,
]
]
];
}
/**
- * @dataProvider addArrayData
*
* @param array $entry
* @param array $expectedEntry
*/
- public function testAddArray(array $entry, array $expectedEntry) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('addArrayData')]
+ public function testAddArray(array $entry, array $expectedEntry): void {
$this->assertEmpty($this->navigationManager->getAll('all'), 'Expected no navigation entry exists');
$this->navigationManager->add($entry);
@@ -131,12 +140,12 @@ class NavigationManagerTest extends TestCase {
}
/**
- * @dataProvider addArrayData
*
* @param array $entry
* @param array $expectedEntry
*/
- public function testAddClosure(array $entry, array $expectedEntry) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('addArrayData')]
+ public function testAddClosure(array $entry, array $expectedEntry): void {
global $testAddClosureNumberOfCalls;
$testAddClosureNumberOfCalls = 0;
@@ -163,7 +172,7 @@ class NavigationManagerTest extends TestCase {
$this->assertEmpty($this->navigationManager->getAll('all'), 'Expected no navigation entry exists after clear()');
}
- public function testAddArrayClearGetAll() {
+ public function testAddArrayClearGetAll(): void {
$entry = [
'id' => 'entry id',
'name' => 'link text',
@@ -178,7 +187,7 @@ class NavigationManagerTest extends TestCase {
$this->assertEmpty($this->navigationManager->getAll(), 'Expected no navigation entry exists after clear()');
}
- public function testAddClosureClearGetAll() {
+ public function testAddClosureClearGetAll(): void {
$this->assertEmpty($this->navigationManager->getAll(), 'Expected no navigation entry exists');
$entry = [
@@ -206,32 +215,34 @@ class NavigationManagerTest extends TestCase {
$this->assertEquals(0, $testAddClosureNumberOfCalls, 'Expected that the closure is not called by getAll()');
}
- /**
- * @dataProvider providesNavigationConfig
- */
- public function testWithAppManager($expected, $navigation, $isAdmin = false) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('providesNavigationConfig')]
+ public function testWithAppManager($expected, $navigation, $isAdmin = false): void {
$l = $this->createMock(IL10N::class);
$l->expects($this->any())->method('t')->willReturnCallback(function ($text, $parameters = []) {
return vsprintf($text, $parameters);
});
+ /* Return default value */
+ $this->config->method('getUserValue')
+ ->willReturnArgument(3);
+
$this->appManager->expects($this->any())
- ->method('isEnabledForUser')
- ->with('theming')
- ->willReturn(true);
- $this->appManager->expects($this->once())->method('getAppInfo')->with('test')->willReturn($navigation);
- /*
+ ->method('isEnabledForUser')
+ ->with('theming')
+ ->willReturn(true);
+ $this->appManager->expects($this->once())
+ ->method('getAppInfo')
+ ->with('test')
+ ->willReturn($navigation);
+ $this->urlGenerator->expects($this->any())
+ ->method('imagePath')
+ ->willReturnCallback(function ($appName, $file) {
+ return "/apps/$appName/img/$file";
+ });
$this->appManager->expects($this->any())
- ->method('getAppInfo')
- ->will($this->returnValueMap([
- ['test', null, null, $navigation],
- ['theming', null, null, null],
- ]));
- */
+ ->method('getAppIcon')
+ ->willReturnCallback(fn (string $appName) => "/apps/$appName/img/app.svg");
$this->l10nFac->expects($this->any())->method('get')->willReturn($l);
- $this->urlGenerator->expects($this->any())->method('imagePath')->willReturnCallback(function ($appName, $file) {
- return "/apps/$appName/img/$file";
- });
$this->urlGenerator->expects($this->any())->method('linkToRoute')->willReturnCallback(function ($route) {
if ($route === 'core.login.logout') {
return 'https://example.com/logout';
@@ -243,20 +254,25 @@ class NavigationManagerTest extends TestCase {
$this->userSession->expects($this->any())->method('getUser')->willReturn($user);
$this->userSession->expects($this->any())->method('isLoggedIn')->willReturn(true);
$this->appManager->expects($this->any())
- ->method('getEnabledAppsForUser')
- ->with($user)
- ->willReturn(['test']);
+ ->method('getEnabledAppsForUser')
+ ->with($user)
+ ->willReturn(['test']);
$this->groupManager->expects($this->any())->method('isAdmin')->willReturn($isAdmin);
$subadmin = $this->createMock(SubAdmin::class);
$subadmin->expects($this->any())->method('isSubAdmin')->with($user)->willReturn(false);
$this->groupManager->expects($this->any())->method('getSubAdmin')->willReturn($subadmin);
$this->navigationManager->clear();
+ $this->dispatcher->expects($this->once())
+ ->method('dispatchTyped')
+ ->willReturnCallback(function ($event): void {
+ $this->assertInstanceOf(LoadAdditionalEntriesEvent::class, $event);
+ });
$entries = $this->navigationManager->getAll('all');
$this->assertEquals($expected, $entries);
}
- public function providesNavigationConfig() {
+ public static function providesNavigationConfig(): array {
$apps = [
'core_apps' => [
'id' => 'core_apps',
@@ -271,6 +287,17 @@ class NavigationManagerTest extends TestCase {
]
];
$defaults = [
+ 'profile' => [
+ 'type' => 'settings',
+ 'id' => 'profile',
+ 'order' => 1,
+ 'href' => '/apps/test/',
+ 'name' => 'View profile',
+ 'icon' => '',
+ 'active' => false,
+ 'classes' => '',
+ 'unread' => 0,
+ ],
'accessibility_settings' => [
'type' => 'settings',
'id' => 'accessibility_settings',
@@ -296,7 +323,7 @@ class NavigationManagerTest extends TestCase {
'logout' => [
'id' => 'logout',
'order' => 99999,
- 'href' => 'https://example.com/logout?requesttoken='. urlencode(\OCP\Util::callRegister()),
+ 'href' => 'https://example.com/logout?requesttoken=' . urlencode(Util::callRegister()),
'icon' => '/apps/core/img/actions/logout.svg',
'name' => 'Log out',
'active' => false,
@@ -334,6 +361,7 @@ class NavigationManagerTest extends TestCase {
return [
'minimalistic' => [
array_merge(
+ ['profile' => $defaults['profile']],
['accessibility_settings' => $defaults['accessibility_settings']],
['settings' => $defaults['settings']],
['test' => [
@@ -345,7 +373,9 @@ class NavigationManagerTest extends TestCase {
'active' => false,
'type' => 'link',
'classes' => '',
- 'unread' => 0
+ 'unread' => 0,
+ 'default' => true,
+ 'app' => 'test',
]],
['logout' => $defaults['logout']]
),
@@ -357,6 +387,7 @@ class NavigationManagerTest extends TestCase {
],
'minimalistic-settings' => [
array_merge(
+ ['profile' => $defaults['profile']],
['accessibility_settings' => $defaults['accessibility_settings']],
['settings' => $defaults['settings']],
['test' => [
@@ -368,7 +399,7 @@ class NavigationManagerTest extends TestCase {
'active' => false,
'type' => 'settings',
'classes' => '',
- 'unread' => 0
+ 'unread' => 0,
]],
['logout' => $defaults['logout']]
),
@@ -378,8 +409,49 @@ class NavigationManagerTest extends TestCase {
],
]]
],
+ 'with-multiple' => [
+ array_merge(
+ ['profile' => $defaults['profile']],
+ ['accessibility_settings' => $defaults['accessibility_settings']],
+ ['settings' => $defaults['settings']],
+ ['test' => [
+ 'id' => 'test',
+ 'order' => 100,
+ 'href' => '/apps/test/',
+ 'icon' => '/apps/test/img/app.svg',
+ 'name' => 'Test',
+ 'active' => false,
+ 'type' => 'link',
+ 'classes' => '',
+ 'unread' => 0,
+ 'default' => false,
+ 'app' => 'test',
+ ],
+ 'test1' => [
+ 'id' => 'test1',
+ 'order' => 50,
+ 'href' => '/apps/test/',
+ 'icon' => '/apps/test/img/app.svg',
+ 'name' => 'Other test',
+ 'active' => false,
+ 'type' => 'link',
+ 'classes' => '',
+ 'unread' => 0,
+ 'default' => true, // because of order
+ 'app' => 'test',
+ ]],
+ ['logout' => $defaults['logout']]
+ ),
+ ['navigations' => [
+ 'navigation' => [
+ ['route' => 'test.page.index', 'name' => 'Test'],
+ ['route' => 'test.page.index', 'name' => 'Other test', 'order' => 50],
+ ]
+ ]]
+ ],
'admin' => [
array_merge(
+ ['profile' => $defaults['profile']],
$adminSettings,
$apps,
['test' => [
@@ -391,7 +463,9 @@ class NavigationManagerTest extends TestCase {
'active' => false,
'type' => 'link',
'classes' => '',
- 'unread' => 0
+ 'unread' => 0,
+ 'default' => true,
+ 'app' => 'test',
]],
['logout' => $defaults['logout']]
),
@@ -404,6 +478,7 @@ class NavigationManagerTest extends TestCase {
],
'no name' => [
array_merge(
+ ['profile' => $defaults['profile']],
$adminSettings,
$apps,
['logout' => $defaults['logout']]
@@ -417,12 +492,342 @@ class NavigationManagerTest extends TestCase {
],
'no admin' => [
$defaults,
- ['navigations' => [[
- '@attributes' => ['role' => 'admin'],
- 'route' => 'test.page.index',
- 'name' => 'Test'
- ]]]
+ ['navigations' => [
+ 'navigation' => [
+ ['@attributes' => ['role' => 'admin'], 'route' => 'test.page.index', 'name' => 'Test']
+ ],
+ ]],
]
];
}
+
+ public function testWithAppManagerAndApporder(): void {
+ $l = $this->createMock(IL10N::class);
+ $l->expects($this->any())->method('t')->willReturnCallback(function ($text, $parameters = []) {
+ return vsprintf($text, $parameters);
+ });
+
+ $testOrder = 12;
+ $expected = [
+ 'test' => [
+ 'type' => 'link',
+ 'id' => 'test',
+ 'order' => $testOrder,
+ 'href' => '/apps/test/',
+ 'name' => 'Test',
+ 'icon' => '/apps/test/img/app.svg',
+ 'active' => false,
+ 'classes' => '',
+ 'unread' => 0,
+ 'default' => true,
+ 'app' => 'test',
+ ],
+ ];
+ $navigation = ['navigations' => [
+ 'navigation' => [
+ ['route' => 'test.page.index', 'name' => 'Test']
+ ],
+ ]];
+
+ $this->config->method('getUserValue')
+ ->willReturnCallback(
+ function (string $userId, string $appName, string $key, mixed $default = '') use ($testOrder) {
+ $this->assertEquals('user001', $userId);
+ if ($key === 'apporder') {
+ return json_encode(['test' => ['app' => 'test', 'order' => $testOrder]]);
+ }
+ return $default;
+ }
+ );
+
+ $this->appManager->expects($this->any())
+ ->method('isEnabledForUser')
+ ->with('theming')
+ ->willReturn(true);
+ $this->appManager->expects($this->once())->method('getAppInfo')->with('test')->willReturn($navigation);
+ $this->appManager->expects($this->once())->method('getAppIcon')->with('test')->willReturn('/apps/test/img/app.svg');
+ $this->l10nFac->expects($this->any())->method('get')->willReturn($l);
+ $this->urlGenerator->expects($this->any())->method('imagePath')->willReturnCallback(function ($appName, $file) {
+ return "/apps/$appName/img/$file";
+ });
+ $this->urlGenerator->expects($this->any())->method('linkToRoute')->willReturnCallback(function ($route) {
+ if ($route === 'core.login.logout') {
+ return 'https://example.com/logout';
+ }
+ return '/apps/test/';
+ });
+ $user = $this->createMock(IUser::class);
+ $user->expects($this->any())->method('getUID')->willReturn('user001');
+ $this->userSession->expects($this->any())->method('getUser')->willReturn($user);
+ $this->userSession->expects($this->any())->method('isLoggedIn')->willReturn(true);
+ $this->appManager->expects($this->any())
+ ->method('getEnabledAppsForUser')
+ ->with($user)
+ ->willReturn(['test']);
+ $this->groupManager->expects($this->any())->method('isAdmin')->willReturn(false);
+ $subadmin = $this->createMock(SubAdmin::class);
+ $subadmin->expects($this->any())->method('isSubAdmin')->with($user)->willReturn(false);
+ $this->groupManager->expects($this->any())->method('getSubAdmin')->willReturn($subadmin);
+
+ $this->navigationManager->clear();
+ $this->dispatcher->expects($this->once())
+ ->method('dispatchTyped')
+ ->willReturnCallback(function ($event): void {
+ $this->assertInstanceOf(LoadAdditionalEntriesEvent::class, $event);
+ });
+ $entries = $this->navigationManager->getAll();
+ $this->assertEquals($expected, $entries);
+ }
+
+ public static function provideDefaultEntries(): array {
+ return [
+ // none specified, default to files
+ [
+ '',
+ '',
+ '{}',
+ true,
+ 'files',
+ ],
+ // none specified, without fallback
+ [
+ '',
+ '',
+ '{}',
+ false,
+ '',
+ ],
+ // unexisting or inaccessible app specified, default to files
+ [
+ 'unexist',
+ '',
+ '{}',
+ true,
+ 'files',
+ ],
+ // unexisting or inaccessible app specified, without fallbacks
+ [
+ 'unexist',
+ '',
+ '{}',
+ false,
+ '',
+ ],
+ // non-standard app
+ [
+ 'settings',
+ '',
+ '{}',
+ true,
+ 'settings',
+ ],
+ // non-standard app, without fallback
+ [
+ 'settings',
+ '',
+ '{}',
+ false,
+ 'settings',
+ ],
+ // non-standard app with fallback
+ [
+ 'unexist,settings',
+ '',
+ '{}',
+ true,
+ 'settings',
+ ],
+ // system default app and user apporder
+ [
+ // system default is settings
+ 'unexist,settings',
+ '',
+ // apporder says default app is files (order is lower)
+ '{"files_id":{"app":"files","order":1},"settings_id":{"app":"settings","order":2}}',
+ true,
+ // system default should override apporder
+ 'settings'
+ ],
+ // user-customized defaultapp
+ [
+ '',
+ 'files',
+ '',
+ true,
+ 'files',
+ ],
+ // user-customized defaultapp with systemwide
+ [
+ 'unexist,settings',
+ 'files',
+ '',
+ true,
+ 'files',
+ ],
+ // user-customized defaultapp with system wide and apporder
+ [
+ 'unexist,settings',
+ 'files',
+ '{"settings_id":{"app":"settings","order":1},"files_id":{"app":"files","order":2}}',
+ true,
+ 'files',
+ ],
+ // user-customized apporder fallback
+ [
+ '',
+ '',
+ '{"settings_id":{"app":"settings","order":1},"files":{"app":"files","order":2}}',
+ true,
+ 'settings',
+ ],
+ // 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))
+ [
+ '',
+ '',
+ '{"spreed":{"order":1},"files":{"app":"files","order":2}}',
+ true,
+ 'files',
+ ],
+ // user-customized apporder, but called without fallback
+ [
+ '',
+ '',
+ '{"settings":{"app":"settings","order":1},"files":{"app":"files","order":2}}',
+ false,
+ '',
+ ],
+ // user-customized apporder with an app that has multiple routes
+ [
+ '',
+ '',
+ '{"settings_id":{"app":"settings","order":1},"settings_id_2":{"app":"settings","order":3},"id_files":{"app":"files","order":2}}',
+ true,
+ 'settings',
+ ],
+ // closure navigation entries are also resolved
+ [
+ 'closure2',
+ '',
+ '',
+ true,
+ 'closure2',
+ ],
+ [
+ '',
+ 'closure2',
+ '',
+ true,
+ 'closure2',
+ ],
+ [
+ '',
+ '',
+ '{"closure2":{"order":1,"app":"closure2","href":"/closure2"}}',
+ true,
+ 'closure2',
+ ],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('provideDefaultEntries')]
+ public function testGetDefaultEntryIdForUser(string $defaultApps, string $userDefaultApps, string $userApporder, bool $withFallbacks, string $expectedApp): void {
+ $this->navigationManager->add([
+ 'id' => 'files',
+ ]);
+ $this->navigationManager->add([
+ 'id' => 'settings',
+ ]);
+ $this->navigationManager->add(static function (): array {
+ return [
+ 'id' => 'closure1',
+ 'href' => '/closure1',
+ ];
+ });
+ $this->navigationManager->add(static function (): array {
+ return [
+ 'id' => 'closure2',
+ 'href' => '/closure2',
+ ];
+ });
+
+ $this->appManager->method('getEnabledApps')->willReturn([]);
+
+ $user = $this->createMock(IUser::class);
+ $user->method('getUID')->willReturn('user1');
+
+ $this->userSession->expects($this->atLeastOnce())
+ ->method('getUser')
+ ->willReturn($user);
+
+ $this->config->expects($this->atLeastOnce())
+ ->method('getSystemValueString')
+ ->with('defaultapp', $this->anything())
+ ->willReturn($defaultApps);
+
+ $this->config->expects($this->atLeastOnce())
+ ->method('getUserValue')
+ ->willReturnMap([
+ ['user1', 'core', 'defaultapp', '', $userDefaultApps],
+ ['user1', 'core', 'apporder', '[]', $userApporder],
+ ]);
+
+ $this->assertEquals($expectedApp, $this->navigationManager->getDefaultEntryIdForUser(null, $withFallbacks));
+ }
+
+ public function testDefaultEntryUpdated(): void {
+ $this->appManager->method('getEnabledApps')->willReturn([]);
+
+ $user = $this->createMock(IUser::class);
+ $user->method('getUID')->willReturn('user1');
+
+ $this->userSession
+ ->method('getUser')
+ ->willReturn($user);
+
+ $this->config
+ ->method('getSystemValueString')
+ ->with('defaultapp', $this->anything())
+ ->willReturn('app4,app3,app2,app1');
+
+ $this->config
+ ->method('getUserValue')
+ ->willReturnMap([
+ ['user1', 'core', 'defaultapp', '', ''],
+ ['user1', 'core', 'apporder', '[]', ''],
+ ]);
+
+ $this->navigationManager->add([
+ 'id' => 'app1',
+ ]);
+
+ $this->assertEquals('app1', $this->navigationManager->getDefaultEntryIdForUser(null, false));
+ $this->assertEquals(true, $this->navigationManager->get('app1')['default']);
+
+ $this->navigationManager->add([
+ 'id' => 'app3',
+ ]);
+
+ $this->assertEquals('app3', $this->navigationManager->getDefaultEntryIdForUser(null, false));
+ $this->assertEquals(false, $this->navigationManager->get('app1')['default']);
+ $this->assertEquals(true, $this->navigationManager->get('app3')['default']);
+
+ $this->navigationManager->add([
+ 'id' => 'app2',
+ ]);
+
+ $this->assertEquals('app3', $this->navigationManager->getDefaultEntryIdForUser(null, false));
+ $this->assertEquals(false, $this->navigationManager->get('app1')['default']);
+ $this->assertEquals(false, $this->navigationManager->get('app2')['default']);
+ $this->assertEquals(true, $this->navigationManager->get('app3')['default']);
+
+ $this->navigationManager->add([
+ 'id' => 'app4',
+ ]);
+
+ $this->assertEquals('app4', $this->navigationManager->getDefaultEntryIdForUser(null, false));
+ $this->assertEquals(false, $this->navigationManager->get('app1')['default']);
+ $this->assertEquals(false, $this->navigationManager->get('app2')['default']);
+ $this->assertEquals(false, $this->navigationManager->get('app3')['default']);
+ $this->assertEquals(true, $this->navigationManager->get('app4')['default']);
+ }
}