diff options
Diffstat (limited to 'apps/files/tests/Controller/ViewControllerTest.php')
-rw-r--r-- | apps/files/tests/Controller/ViewControllerTest.php | 564 |
1 files changed, 220 insertions, 344 deletions
diff --git a/apps/files/tests/Controller/ViewControllerTest.php b/apps/files/tests/Controller/ViewControllerTest.php index b4f07b65e76..01aa955a13e 100644 --- a/apps/files/tests/Controller/ViewControllerTest.php +++ b/apps/files/tests/Controller/ViewControllerTest.php @@ -1,437 +1,313 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Christoph Wurst <christoph@owncloud.com> - * @author Jan-Christoph Borchardt <hey@jancborchardt.net> - * @author Joas Schilling <coding@schilljs.com> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ - namespace OCA\Files\Tests\Controller; +use OC\Files\FilenameValidator; +use OC\Route\Router; +use OC\URLGenerator; use OCA\Files\Controller\ViewController; -use OCP\AppFramework\Http; +use OCA\Files\Service\UserConfig; +use OCA\Files\Service\ViewConfig; +use OCP\App\IAppManager; +use OCP\AppFramework\Http\ContentSecurityPolicy; +use OCP\AppFramework\Http\RedirectResponse; +use OCP\AppFramework\Http\TemplateResponse; +use OCP\AppFramework\Services\IInitialState; +use OCP\Authentication\TwoFactorAuth\IRegistry; +use OCP\Diagnostics\IEventLogger; +use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\File; use OCP\Files\Folder; use OCP\Files\IRootFolder; -use OCP\IUser; -use OCP\Template; -use Test\TestCase; +use OCP\Files\Template\ITemplateManager; +use OCP\ICacheFactory; +use OCP\IConfig; +use OCP\IL10N; use OCP\IRequest; use OCP\IURLGenerator; -use OCP\IL10N; -use OCP\IConfig; +use OCP\IUser; use OCP\IUserSession; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use OCP\App\IAppManager; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Container\ContainerInterface; +use Psr\Log\LoggerInterface; +use Test\TestCase; /** * Class ViewControllerTest * + * @group RoutingWeirdness + * * @package OCA\Files\Tests\Controller */ class ViewControllerTest extends TestCase { - /** @var IRequest|\PHPUnit_Framework_MockObject_MockObject */ - private $request; - /** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */ - private $urlGenerator; - /** @var IL10N */ - private $l10n; - /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ - private $config; - /** @var EventDispatcherInterface */ - private $eventDispatcher; - /** @var ViewController|\PHPUnit_Framework_MockObject_MockObject */ - private $viewController; - /** @var IUser */ - private $user; - /** @var IUserSession */ - private $userSession; - /** @var IAppManager|\PHPUnit_Framework_MockObject_MockObject */ - private $appManager; - /** @var IRootFolder|\PHPUnit_Framework_MockObject_MockObject */ - private $rootFolder; - - public function setUp() { + private ContainerInterface&MockObject $container; + private IAppManager&MockObject $appManager; + private ICacheFactory&MockObject $cacheFactory; + private IConfig&MockObject $config; + private IEventDispatcher $eventDispatcher; + private IEventLogger&MockObject $eventLogger; + private IInitialState&MockObject $initialState; + private IL10N&MockObject $l10n; + private IRequest&MockObject $request; + private IRootFolder&MockObject $rootFolder; + private ITemplateManager&MockObject $templateManager; + private IURLGenerator $urlGenerator; + private IUser&MockObject $user; + private IUserSession&MockObject $userSession; + private LoggerInterface&MockObject $logger; + private UserConfig&MockObject $userConfig; + private ViewConfig&MockObject $viewConfig; + private Router $router; + private IRegistry&MockObject $twoFactorRegistry; + + private ViewController&MockObject $viewController; + + protected function setUp(): void { parent::setUp(); - $this->request = $this->getMockBuilder(IRequest::class)->getMock(); - $this->urlGenerator = $this->getMockBuilder(IURLGenerator::class)->getMock(); - $this->l10n = $this->getMockBuilder(IL10N::class)->getMock(); - $this->config = $this->getMockBuilder(IConfig::class)->getMock(); - $this->eventDispatcher = $this->getMockBuilder('\Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); - $this->userSession = $this->getMockBuilder(IUserSession::class)->getMock(); - $this->appManager = $this->getMockBuilder('\OCP\App\IAppManager')->getMock(); + $this->appManager = $this->createMock(IAppManager::class); + $this->config = $this->createMock(IConfig::class); + $this->eventDispatcher = $this->createMock(IEventDispatcher::class); + $this->initialState = $this->createMock(IInitialState::class); + $this->l10n = $this->createMock(IL10N::class); + $this->request = $this->createMock(IRequest::class); + $this->rootFolder = $this->createMock(IRootFolder::class); + $this->templateManager = $this->createMock(ITemplateManager::class); + $this->userConfig = $this->createMock(UserConfig::class); + $this->userSession = $this->createMock(IUserSession::class); + $this->viewConfig = $this->createMock(ViewConfig::class); + $this->twoFactorRegistry = $this->createMock(IRegistry::class); + $this->user = $this->getMockBuilder(IUser::class)->getMock(); $this->user->expects($this->any()) ->method('getUID') - ->will($this->returnValue('testuser1')); + ->willReturn('testuser1'); $this->userSession->expects($this->any()) ->method('getUser') - ->will($this->returnValue($this->user)); - $this->rootFolder = $this->getMockBuilder('\OCP\Files\IRootFolder')->getMock(); - $this->viewController = $this->getMockBuilder('\OCA\Files\Controller\ViewController') - ->setConstructorArgs([ - 'files', + ->willReturn($this->user); + + // Make sure we know the app is enabled + $this->appManager->expects($this->any()) + ->method('cleanAppId') + ->willReturnArgument(0); + $this->appManager->expects($this->any()) + ->method('getAppPath') + ->willReturnCallback(fn (string $appid): string => \OC::$SERVERROOT . '/apps/' . $appid); + $this->appManager->expects($this->any()) + ->method('isAppLoaded') + ->willReturn(true); + + $this->cacheFactory = $this->createMock(ICacheFactory::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->eventLogger = $this->createMock(IEventLogger::class); + $this->container = $this->createMock(ContainerInterface::class); + $this->router = new Router( + $this->logger, $this->request, - $this->urlGenerator, - $this->l10n, $this->config, - $this->eventDispatcher, - $this->userSession, + $this->eventLogger, + $this->container, $this->appManager, - $this->rootFolder - ]) - ->setMethods([ - 'getStorageInfo', - 'renderScript' - ]) - ->getMock(); + ); + + // Create a real URLGenerator instance to generate URLs + $this->urlGenerator = new URLGenerator( + $this->config, + $this->userSession, + $this->cacheFactory, + $this->request, + $this->router + ); + + $filenameValidator = $this->createMock(FilenameValidator::class); + $this->viewController = $this->getMockBuilder(ViewController::class) + ->setConstructorArgs([ + 'files', + $this->request, + $this->urlGenerator, + $this->l10n, + $this->config, + $this->eventDispatcher, + $this->userSession, + $this->appManager, + $this->rootFolder, + $this->initialState, + $this->templateManager, + $this->userConfig, + $this->viewConfig, + $filenameValidator, + $this->twoFactorRegistry, + ]) + ->onlyMethods([ + 'getStorageInfo', + ]) + ->getMock(); } - public function testIndexWithRegularBrowser() { + public function testIndexWithRegularBrowser(): void { $this->viewController - ->expects($this->once()) + ->expects($this->any()) ->method('getStorageInfo') - ->will($this->returnValue([ + ->willReturn([ 'used' => 123, 'quota' => 100, 'total' => 100, 'relative' => 123, 'owner' => 'MyName', 'ownerDisplayName' => 'MyDisplayName', - ])); - $this->config->expects($this->exactly(3)) + ]); + + $this->config ->method('getUserValue') - ->will($this->returnValueMap([ + ->willReturnMap([ [$this->user->getUID(), 'files', 'file_sorting', 'name', 'name'], [$this->user->getUID(), 'files', 'file_sorting_direction', 'asc', 'asc'], + [$this->user->getUID(), 'files', 'files_sorting_configs', '{}', '{}'], [$this->user->getUID(), 'files', 'show_hidden', false, false], - ])); + [$this->user->getUID(), 'files', 'crop_image_previews', true, true], + [$this->user->getUID(), 'files', 'show_grid', true], + ]); + + $baseFolderFiles = $this->getMockBuilder(Folder::class)->getMock(); + + $this->rootFolder->expects($this->any()) + ->method('getUserFolder') + ->with('testuser1') + ->willReturn($baseFolderFiles); $this->config ->expects($this->any()) ->method('getAppValue') - ->will($this->returnArgument(2)); - - $nav = new Template('files', 'appnavigation'); - $nav->assign('usage_relative', 123); - $nav->assign('usage', '123 B'); - $nav->assign('quota', 100); - $nav->assign('total_space', '100 B'); - $nav->assign('navigationItems', [ - [ - 'id' => 'files', - 'appname' => 'files', - 'script' => 'list.php', - 'order' => 0, - 'name' => \OC::$server->getL10N('files')->t('All files'), - 'active' => false, - 'icon' => '', - 'type' => 'link', - 'classes' => '', - ], - [ - 'id' => 'recent', - 'appname' => 'files', - 'script' => 'recentlist.php', - 'order' => 2, - 'name' => \OC::$server->getL10N('files')->t('Recent'), - 'active' => false, - 'icon' => '', - 'type' => 'link', - 'classes' => '', - ], - [ - 'id' => 'favorites', - 'appname' => 'files', - 'script' => 'simplelist.php', - 'order' => 5, - 'name' => null, - 'active' => false, - 'icon' => '', - 'type' => 'link', - 'classes' => '', - ], - [ - 'id' => 'sharingin', - 'appname' => 'files_sharing', - 'script' => 'list.php', - 'order' => 15, - 'name' => \OC::$server->getL10N('files_sharing')->t('Shared with you'), - 'active' => false, - 'icon' => '', - 'type' => 'link', - 'classes' => '', - ], - [ - 'id' => 'sharingout', - 'appname' => 'files_sharing', - 'script' => 'list.php', - 'order' => 16, - 'name' => \OC::$server->getL10N('files_sharing')->t('Shared with others'), - 'active' => false, - 'icon' => '', - 'type' => 'link', - 'classes' => '', - ], - [ - 'id' => 'sharinglinks', - 'appname' => 'files_sharing', - 'script' => 'list.php', - 'order' => 17, - 'name' => \OC::$server->getL10N('files_sharing')->t('Shared by link', []), - 'active' => false, - 'icon' => '', - 'type' => 'link', - 'classes' => '', - ], - [ - 'id' => 'systemtagsfilter', - 'appname' => 'systemtags', - 'script' => 'list.php', - 'order' => 25, - 'name' => \OC::$server->getL10N('systemtags')->t('Tags'), - 'active' => false, - 'icon' => '', - 'type' => 'link', - 'classes' => '', - ], - [ - 'id' => 'trashbin', - 'appname' => 'files_trashbin', - 'script' => 'list.php', - 'order' => 50, - 'name' => \OC::$server->getL10N('files_trashbin')->t('Deleted files'), - 'active' => false, - 'icon' => '', - 'type' => 'link', - 'classes' => 'pinned', - ], - ]); - - $expected = new Http\TemplateResponse( + ->willReturnArgument(2); + + $expected = new TemplateResponse( 'files', 'index', - [ - 'usedSpacePercent' => 123, - 'owner' => 'MyName', - 'ownerDisplayName' => 'MyDisplayName', - 'isPublic' => false, - 'defaultFileSorting' => 'name', - 'defaultFileSortingDirection' => 'asc', - 'showHiddenFiles' => 0, - 'fileNotFound' => 0, - 'allowShareWithLink' => 'yes', - 'appNavigation' => $nav, - 'appContents' => [ - [ - 'id' => 'files', - 'content' => null, - ], - [ - 'id' => 'recent', - 'content' => null, - ], - [ - 'id' => 'favorites', - 'content' => null, - ], - [ - 'id' => 'sharingin', - 'content' => null, - ], - [ - 'id' => 'sharingout', - 'content' => null, - ], - [ - 'id' => 'sharinglinks', - 'content' => null, - ], - [ - 'id' => 'systemtagsfilter', - 'content' => null, - ], - [ - 'id' => 'trashbin', - 'content' => null, - ], - ], - 'hiddenFields' => [], - ] ); - $policy = new Http\ContentSecurityPolicy(); + $policy = new ContentSecurityPolicy(); + $policy->addAllowedWorkerSrcDomain('\'self\''); $policy->addAllowedFrameDomain('\'self\''); $expected->setContentSecurityPolicy($policy); + $this->assertEquals($expected, $this->viewController->index('MyDir', 'MyView')); } - public function testShowFileRouteWithFolder() { - $node = $this->getMockBuilder(Folder::class)->getMock(); - $node->expects($this->once()) - ->method('getPath') - ->will($this->returnValue('/testuser1/files/test/sub')); + public static function dataTestShortRedirect(): array { + // openfile is true by default + // opendetails is undefined by default + // both will be evaluated as truthy + return [ + [null, null, '/index.php/apps/files/files/123456?openfile=true'], + ['', null, '/index.php/apps/files/files/123456?openfile=true'], + [null, '', '/index.php/apps/files/files/123456?openfile=true&opendetails=true'], + ['', '', '/index.php/apps/files/files/123456?openfile=true&opendetails=true'], + ['false', '', '/index.php/apps/files/files/123456?openfile=false'], + [null, 'false', '/index.php/apps/files/files/123456?openfile=true&opendetails=false'], + ['true', 'false', '/index.php/apps/files/files/123456?openfile=true&opendetails=false'], + ['false', 'true', '/index.php/apps/files/files/123456?openfile=false&opendetails=true'], + ['false', 'false', '/index.php/apps/files/files/123456?openfile=false&opendetails=false'], + ]; + } - $baseFolder = $this->getMockBuilder(Folder::class)->getMock(); + #[\PHPUnit\Framework\Attributes\DataProvider('dataTestShortRedirect')] + public function testShortRedirect(?string $openfile, ?string $opendetails, string $result): void { + $this->appManager->expects($this->any()) + ->method('isEnabledForUser') + ->with('files') + ->willReturn(true); - $this->rootFolder->expects($this->once()) + $baseFolderFiles = $this->getMockBuilder(Folder::class)->getMock(); + $this->rootFolder->expects($this->any()) ->method('getUserFolder') ->with('testuser1') - ->will($this->returnValue($baseFolder)); - - $baseFolder->expects($this->at(0)) - ->method('getById') - ->with(123) - ->will($this->returnValue([$node])); - $baseFolder->expects($this->at(1)) - ->method('getRelativePath') - ->with('/testuser1/files/test/sub') - ->will($this->returnValue('/test/sub')); - - $this->urlGenerator - ->expects($this->once()) - ->method('linkToRoute') - ->with('files.view.index', ['dir' => '/test/sub']) - ->will($this->returnValue('/apps/files/?dir=/test/sub')); - - $expected = new Http\RedirectResponse('/apps/files/?dir=/test/sub'); - $this->assertEquals($expected, $this->viewController->index('/whatever', '', '123')); - } + ->willReturn($baseFolderFiles); - public function testShowFileRouteWithFile() { $parentNode = $this->getMockBuilder(Folder::class)->getMock(); $parentNode->expects($this->once()) ->method('getPath') - ->will($this->returnValue('testuser1/files/test')); - - $baseFolder = $this->getMockBuilder(Folder::class)->getMock(); - - $this->rootFolder->expects($this->once()) - ->method('getUserFolder') - ->with('testuser1') - ->will($this->returnValue($baseFolder)); + ->willReturn('testuser1/files/Folder'); $node = $this->getMockBuilder(File::class)->getMock(); $node->expects($this->once()) ->method('getParent') - ->will($this->returnValue($parentNode)); - $node->expects($this->once()) - ->method('getName') - ->will($this->returnValue('somefile.txt')); + ->willReturn($parentNode); - $baseFolder->expects($this->at(0)) - ->method('getById') - ->with(123) - ->will($this->returnValue([$node])); - $baseFolder->expects($this->at(1)) - ->method('getRelativePath') - ->with('testuser1/files/test') - ->will($this->returnValue('/test')); + $baseFolderFiles->expects($this->any()) + ->method('getFirstNodeById') + ->with(123456) + ->willReturn($node); - $this->urlGenerator - ->expects($this->once()) - ->method('linkToRoute') - ->with('files.view.index', ['dir' => '/test', 'scrollto' => 'somefile.txt']) - ->will($this->returnValue('/apps/files/?dir=/test/sub&scrollto=somefile.txt')); - - $expected = new Http\RedirectResponse('/apps/files/?dir=/test/sub&scrollto=somefile.txt'); - $this->assertEquals($expected, $this->viewController->index('/whatever', '', '123')); + $response = $this->viewController->showFile('123456', $opendetails, $openfile); + $this->assertStringContainsString($result, $response->getHeaders()['Location']); } - public function testShowFileRouteWithInvalidFileId() { - $baseFolder = $this->getMockBuilder(Folder::class)->getMock(); - $this->rootFolder->expects($this->once()) - ->method('getUserFolder') - ->with('testuser1') - ->will($this->returnValue($baseFolder)); - - $baseFolder->expects($this->at(0)) - ->method('getById') - ->with(123) - ->will($this->returnValue([])); - - $this->urlGenerator->expects($this->once()) - ->method('linkToRoute') - ->with('files.view.index', ['fileNotFound' => true]) - ->willReturn('redirect.url'); - - $response = $this->viewController->index('MyDir', 'MyView', '123'); - $this->assertInstanceOf('OCP\AppFramework\Http\RedirectResponse', $response); - $this->assertEquals('redirect.url', $response->getRedirectURL()); - } - - public function testShowFileRouteWithTrashedFile() { - $this->appManager->expects($this->once()) + public function testShowFileRouteWithTrashedFile(): void { + $this->appManager->expects($this->exactly(2)) ->method('isEnabledForUser') - ->with('files_trashbin') - ->will($this->returnValue(true)); + ->willReturn(true); - $parentNode = $this->getMockBuilder(Folder::class)->getMock(); + $parentNode = $this->createMock(Folder::class); $parentNode->expects($this->once()) ->method('getPath') - ->will($this->returnValue('testuser1/files_trashbin/files/test.d1462861890/sub')); + ->willReturn('testuser1/files_trashbin/files/test.d1462861890/sub'); - $baseFolderFiles = $this->getMockBuilder(Folder::class)->getMock(); - $baseFolderTrash = $this->getMockBuilder(Folder::class)->getMock(); + $baseFolderFiles = $this->createMock(Folder::class); + $baseFolderTrash = $this->createMock(Folder::class); - $this->rootFolder->expects($this->at(0)) + $this->rootFolder->expects($this->any()) ->method('getUserFolder') ->with('testuser1') - ->will($this->returnValue($baseFolderFiles)); - $this->rootFolder->expects($this->at(1)) + ->willReturn($baseFolderFiles); + $this->rootFolder->expects($this->once()) ->method('get') ->with('testuser1/files_trashbin/files/') - ->will($this->returnValue($baseFolderTrash)); + ->willReturn($baseFolderTrash); - $baseFolderFiles->expects($this->once()) - ->method('getById') + $baseFolderFiles->expects($this->any()) + ->method('getFirstNodeById') ->with(123) - ->will($this->returnValue([])); + ->willReturn(null); - $node = $this->getMockBuilder(File::class)->getMock(); + $node = $this->createMock(File::class); $node->expects($this->once()) ->method('getParent') - ->will($this->returnValue($parentNode)); - $node->expects($this->once()) - ->method('getName') - ->will($this->returnValue('somefile.txt')); + ->willReturn($parentNode); - $baseFolderTrash->expects($this->at(0)) - ->method('getById') + $baseFolderTrash->expects($this->once()) + ->method('getFirstNodeById') ->with(123) - ->will($this->returnValue([$node])); - $baseFolderTrash->expects($this->at(1)) + ->willReturn($node); + $baseFolderTrash->expects($this->once()) ->method('getRelativePath') ->with('testuser1/files_trashbin/files/test.d1462861890/sub') - ->will($this->returnValue('/test.d1462861890/sub')); + ->willReturn('/test.d1462861890/sub'); - $this->urlGenerator - ->expects($this->once()) - ->method('linkToRoute') - ->with('files.view.index', ['view' => 'trashbin', 'dir' => '/test.d1462861890/sub', 'scrollto' => 'somefile.txt']) - ->will($this->returnValue('/apps/files/?view=trashbin&dir=/test.d1462861890/sub&scrollto=somefile.txt')); + $expected = new RedirectResponse('/index.php/apps/files/trashbin/123?dir=/test.d1462861890/sub'); + $this->assertEquals($expected, $this->viewController->index('', '', '123')); + } - $expected = new Http\RedirectResponse('/apps/files/?view=trashbin&dir=/test.d1462861890/sub&scrollto=somefile.txt'); - $this->assertEquals($expected, $this->viewController->index('/whatever', '', '123')); + public function testTwoFactorAuthEnabled(): void { + $this->twoFactorRegistry->method('getProviderStates') + ->willReturn([ + 'totp' => true, + 'backup_codes' => true, + ]); + + $invokedCountProvideInitialState = $this->exactly(9); + $this->initialState->expects($invokedCountProvideInitialState) + ->method('provideInitialState') + ->willReturnCallback(function ($key, $data) use ($invokedCountProvideInitialState) { + if ($invokedCountProvideInitialState->numberOfInvocations() === 9) { + $this->assertEquals('isTwoFactorEnabled', $key); + $this->assertTrue($data); + } + }); + + $this->viewController->index('', '', null); } } |