diff options
Diffstat (limited to 'tests/Core/Controller')
21 files changed, 1076 insertions, 1144 deletions
diff --git a/tests/Core/Controller/AppPasswordControllerTest.php b/tests/Core/Controller/AppPasswordControllerTest.php index 7d81e0ec115..eb1566eca8b 100644 --- a/tests/Core/Controller/AppPasswordControllerTest.php +++ b/tests/Core/Controller/AppPasswordControllerTest.php @@ -2,25 +2,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2018, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Tests\Core\Controller; @@ -29,6 +12,7 @@ use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Token\IProvider; use OC\Authentication\Token\IToken; use OC\Core\Controller\AppPasswordController; +use OC\User\Session; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCS\OCSForbiddenException; use OCP\Authentication\Exceptions\CredentialsUnavailableException; @@ -38,12 +22,13 @@ use OCP\Authentication\LoginCredentials\IStore; use OCP\EventDispatcher\IEventDispatcher; use OCP\IRequest; use OCP\ISession; +use OCP\IUserManager; +use OCP\Security\Bruteforce\IThrottler; use OCP\Security\ISecureRandom; use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class AppPasswordControllerTest extends TestCase { - /** @var ISession|MockObject */ private $session; @@ -62,6 +47,15 @@ class AppPasswordControllerTest extends TestCase { /** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */ private $eventDispatcher; + /** @var Session|MockObject */ + private $userSession; + + /** @var IUserManager|MockObject */ + private $userManager; + + /** @var IThrottler|MockObject */ + private $throttler; + /** @var AppPasswordController */ private $controller; @@ -74,6 +68,9 @@ class AppPasswordControllerTest extends TestCase { $this->credentialStore = $this->createMock(IStore::class); $this->request = $this->createMock(IRequest::class); $this->eventDispatcher = $this->createMock(IEventDispatcher::class); + $this->userSession = $this->createMock(Session::class); + $this->userManager = $this->createMock(IUserManager::class); + $this->throttler = $this->createMock(IThrottler::class); $this->controller = new AppPasswordController( 'core', @@ -82,11 +79,14 @@ class AppPasswordControllerTest extends TestCase { $this->random, $this->tokenProvider, $this->credentialStore, - $this->eventDispatcher + $this->eventDispatcher, + $this->userSession, + $this->userManager, + $this->throttler ); } - public function testGetAppPasswordWithAppPassword() { + public function testGetAppPasswordWithAppPassword(): void { $this->session->method('exists') ->with('app_password') ->willReturn(true); @@ -96,7 +96,7 @@ class AppPasswordControllerTest extends TestCase { $this->controller->getAppPassword(); } - public function testGetAppPasswordNoLoginCreds() { + public function testGetAppPasswordNoLoginCreds(): void { $this->session->method('exists') ->with('app_password') ->willReturn(false); @@ -108,7 +108,7 @@ class AppPasswordControllerTest extends TestCase { $this->controller->getAppPassword(); } - public function testGetAppPassword() { + public function testGetAppPassword(): void { $credentials = $this->createMock(ICredentials::class); $this->session->method('exists') @@ -123,12 +123,12 @@ class AppPasswordControllerTest extends TestCase { $credentials->method('getLoginName') ->willReturn('myLoginName'); $this->request->method('getHeader') - ->with('USER_AGENT') + ->with('user-agent') ->willReturn('myUA'); $this->random->method('generate') ->with( 72, - ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS + ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS )->willReturn('myToken'); $this->tokenProvider->expects($this->once()) @@ -149,7 +149,7 @@ class AppPasswordControllerTest extends TestCase { $this->controller->getAppPassword(); } - public function testGetAppPasswordNoPassword() { + public function testGetAppPasswordNoPassword(): void { $credentials = $this->createMock(ICredentials::class); $this->session->method('exists') @@ -164,12 +164,12 @@ class AppPasswordControllerTest extends TestCase { $credentials->method('getLoginName') ->willReturn('myLoginName'); $this->request->method('getHeader') - ->with('USER_AGENT') + ->with('user-agent') ->willReturn('myUA'); $this->random->method('generate') ->with( 72, - ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS + ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS )->willReturn('myToken'); $this->tokenProvider->expects($this->once()) @@ -190,7 +190,7 @@ class AppPasswordControllerTest extends TestCase { $this->controller->getAppPassword(); } - public function testDeleteAppPasswordNoAppPassword() { + public function testDeleteAppPasswordNoAppPassword(): void { $this->session->method('exists') ->with('app_password') ->willReturn(false); @@ -200,7 +200,7 @@ class AppPasswordControllerTest extends TestCase { $this->controller->deleteAppPassword(); } - public function testDeleteAppPasswordFails() { + public function testDeleteAppPasswordFails(): void { $this->session->method('exists') ->with('app_password') ->willReturn(true); @@ -217,7 +217,7 @@ class AppPasswordControllerTest extends TestCase { $this->controller->deleteAppPassword(); } - public function testDeleteAppPasswordSuccess() { + public function testDeleteAppPasswordSuccess(): void { $this->session->method('exists') ->with('app_password') ->willReturn(true); diff --git a/tests/Core/Controller/AutoCompleteControllerTest.php b/tests/Core/Controller/AutoCompleteControllerTest.php index 61fc90e3c82..c5574f78fc1 100644 --- a/tests/Core/Controller/AutoCompleteControllerTest.php +++ b/tests/Core/Controller/AutoCompleteControllerTest.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Tests\Core\Controller; @@ -32,13 +16,13 @@ use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class AutoCompleteControllerTest extends TestCase { - /** @var ISearch|MockObject */ + /** @var ISearch|MockObject */ protected $collaboratorSearch; - /** @var IManager|MockObject */ + /** @var IManager|MockObject */ protected $autoCompleteManager; - /** @var IEventDispatcher|MockObject */ + /** @var IEventDispatcher|MockObject */ protected $dispatcher; - /** @var AutoCompleteController */ + /** @var AutoCompleteController */ protected $controller; protected function setUp(): void { @@ -59,7 +43,7 @@ class AutoCompleteControllerTest extends TestCase { ); } - public function searchDataProvider() { + public static function searchDataProvider(): array { return [ [ #0 – regular search // searchResults @@ -75,8 +59,8 @@ class AutoCompleteControllerTest extends TestCase { ], // expected [ - [ 'id' => 'alice', 'label' => 'Alice A.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => ''], - [ 'id' => 'bob', 'label' => 'Bob Y.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => ''], + [ 'id' => 'alice', 'label' => 'Alice A.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => '', 'shareWithDisplayNameUnique' => ''], + [ 'id' => 'bob', 'label' => 'Bob Y.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => '', 'shareWithDisplayNameUnique' => ''], ], '', 'files', @@ -96,8 +80,8 @@ class AutoCompleteControllerTest extends TestCase { ], // expected [ - [ 'id' => 'alice', 'label' => 'Alice A.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => ''], - [ 'id' => 'bob', 'label' => 'Bob Y.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => ''], + [ 'id' => 'alice', 'label' => 'Alice A.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => '', 'shareWithDisplayNameUnique' => ''], + [ 'id' => 'bob', 'label' => 'Bob Y.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => '', 'shareWithDisplayNameUnique' => ''], ], '', null, @@ -117,8 +101,8 @@ class AutoCompleteControllerTest extends TestCase { ], // expected [ - [ 'id' => 'alice', 'label' => 'Alice A.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => ''], - [ 'id' => 'bob', 'label' => 'Bob Y.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => ''], + [ 'id' => 'alice', 'label' => 'Alice A.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => '', 'shareWithDisplayNameUnique' => ''], + [ 'id' => 'bob', 'label' => 'Bob Y.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => '', 'shareWithDisplayNameUnique' => ''], ], '', 'files', @@ -138,27 +122,40 @@ class AutoCompleteControllerTest extends TestCase { ], ], [ - [ 'id' => 'bob', 'label' => 'Bob Y.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => ''], - [ 'id' => 'bobby', 'label' => 'Robert R.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => ''], + [ 'id' => 'bob', 'label' => 'Bob Y.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => '', 'shareWithDisplayNameUnique' => ''], + [ 'id' => 'bobby', 'label' => 'Robert R.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => '', 'shareWithDisplayNameUnique' => ''], ], 'bob', 'files', '42', null - ] + ], + [ #4 – with unique name + [ + 'exact' => [ + 'users' => [], + 'robots' => [], + ], + 'users' => [ + ['label' => 'Alice A.', 'value' => ['shareWith' => 'alice'], 'shareWithDisplayNameUnique' => 'alica@nextcloud.com'], + ['label' => 'Alice A.', 'value' => ['shareWith' => 'alicea'], 'shareWithDisplayNameUnique' => 'alicaa@nextcloud.com'], + ], + ], + // expected + [ + [ 'id' => 'alice', 'label' => 'Alice A.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => '', 'shareWithDisplayNameUnique' => 'alica@nextcloud.com'], + [ 'id' => 'alicea', 'label' => 'Alice A.', 'icon' => '', 'source' => 'users', 'status' => '', 'subline' => '', 'shareWithDisplayNameUnique' => 'alicaa@nextcloud.com'], + ], + '', + 'files', + '42', + 'karma|bus-factor' + ], ]; } - /** - * @param $searchResults - * @param $expected - * @param $searchTerm - * @param $itemType - * @param $itemId - * @param $sorter - * @dataProvider searchDataProvider - */ - public function testGet($searchResults, $expected, $searchTerm, $itemType, $itemId, $sorter) { + #[\PHPUnit\Framework\Attributes\DataProvider('searchDataProvider')] + public function testGet(array $searchResults, array $expected, string $searchTerm, ?string $itemType, ?string $itemId, ?string $sorter): void { $this->collaboratorSearch->expects($this->once()) ->method('search') ->willReturn([$searchResults, false]); diff --git a/tests/Core/Controller/AvatarControllerTest.php b/tests/Core/Controller/AvatarControllerTest.php index 8d3cd73a656..a78e2c1bb5c 100644 --- a/tests/Core/Controller/AvatarControllerTest.php +++ b/tests/Core/Controller/AvatarControllerTest.php @@ -1,22 +1,9 @@ <?php + /** - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @copyright Copyright (c) 2015, ownCloud, Inc. - * @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 OC\Core\Controller; @@ -33,19 +20,21 @@ namespace Tests\Core\Controller; use OC\AppFramework\Utility\TimeFactory; use OC\Core\Controller\AvatarController; +use OC\Core\Controller\GuestAvatarController; use OCP\AppFramework\Http; use OCP\Files\File; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; +use OCP\Files\SimpleFS\ISimpleFile; use OCP\IAvatar; use OCP\IAvatarManager; use OCP\ICache; use OCP\IL10N; -use OCP\ILogger; use OCP\IRequest; use OCP\IUser; use OCP\IUserManager; +use Psr\Log\LoggerInterface; /** * Class AvatarControllerTest @@ -55,13 +44,15 @@ use OCP\IUserManager; class AvatarControllerTest extends \Test\TestCase { /** @var AvatarController */ private $avatarController; + /** @var GuestAvatarController */ + private $guestAvatarController; + /** @var IAvatar|\PHPUnit\Framework\MockObject\MockObject */ private $avatarMock; /** @var IUser|\PHPUnit\Framework\MockObject\MockObject */ private $userMock; - /** @var File|\PHPUnit\Framework\MockObject\MockObject */ + /** @var ISimpleFile|\PHPUnit\Framework\MockObject\MockObject */ private $avatarFile; - /** @var IAvatarManager|\PHPUnit\Framework\MockObject\MockObject */ private $avatarManager; /** @var ICache|\PHPUnit\Framework\MockObject\MockObject */ @@ -72,7 +63,7 @@ class AvatarControllerTest extends \Test\TestCase { private $userManager; /** @var IRootFolder|\PHPUnit\Framework\MockObject\MockObject */ private $rootFolder; - /** @var ILogger|\PHPUnit\Framework\MockObject\MockObject */ + /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */ private $logger; /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */ private $request; @@ -90,12 +81,19 @@ class AvatarControllerTest extends \Test\TestCase { $this->userManager = $this->getMockBuilder(IUserManager::class)->getMock(); $this->request = $this->getMockBuilder(IRequest::class)->getMock(); $this->rootFolder = $this->getMockBuilder('OCP\Files\IRootFolder')->getMock(); - $this->logger = $this->getMockBuilder(ILogger::class)->getMock(); + $this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); $this->timeFactory = $this->getMockBuilder('OC\AppFramework\Utility\TimeFactory')->getMock(); $this->avatarMock = $this->getMockBuilder('OCP\IAvatar')->getMock(); $this->userMock = $this->getMockBuilder(IUser::class)->getMock(); + $this->guestAvatarController = new GuestAvatarController( + 'core', + $this->request, + $this->avatarManager, + $this->logger + ); + $this->avatarController = new AvatarController( 'core', $this->request, @@ -106,7 +104,8 @@ class AvatarControllerTest extends \Test\TestCase { $this->rootFolder, $this->logger, 'userid', - $this->timeFactory + $this->timeFactory, + $this->guestAvatarController, ); // Configure userMock @@ -115,7 +114,7 @@ class AvatarControllerTest extends \Test\TestCase { $this->userManager->method('get') ->willReturnMap([['userId', $this->userMock]]); - $this->avatarFile = $this->getMockBuilder('OCP\Files\File')->getMock(); + $this->avatarFile = $this->getMockBuilder(ISimpleFile::class)->getMock(); $this->avatarFile->method('getContent')->willReturn('image data'); $this->avatarFile->method('getMimeType')->willReturn('image type'); $this->avatarFile->method('getEtag')->willReturn('my etag'); @@ -130,9 +129,9 @@ class AvatarControllerTest extends \Test\TestCase { /** * Fetch an avatar if a user has no avatar */ - public function testGetAvatarNoAvatar() { + public function testGetAvatarNoAvatar(): void { $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); - $this->avatarMock->method('getFile')->will($this->throwException(new NotFoundException())); + $this->avatarMock->method('getFile')->willThrowException(new NotFoundException()); $response = $this->avatarController->getAvatar('userId', 32); //Comment out until JS is fixed @@ -142,7 +141,7 @@ class AvatarControllerTest extends \Test\TestCase { /** * Fetch the user's avatar */ - public function testGetAvatar() { + public function testGetAvatar(): void { $this->avatarMock->method('getFile')->willReturn($this->avatarFile); $this->avatarManager->method('getAvatar')->with('userId')->willReturn($this->avatarMock); $this->avatarMock->expects($this->once()) @@ -163,7 +162,7 @@ class AvatarControllerTest extends \Test\TestCase { /** * Fetch the user's avatar */ - public function testGetGeneratedAvatar() { + public function testGetGeneratedAvatar(): void { $this->avatarMock->method('getFile')->willReturn($this->avatarFile); $this->avatarManager->method('getAvatar')->with('userId')->willReturn($this->avatarMock); @@ -181,11 +180,11 @@ class AvatarControllerTest extends \Test\TestCase { /** * Fetch the avatar of a non-existing user */ - public function testGetAvatarNoUser() { + public function testGetAvatarNoUser(): void { $this->avatarManager ->method('getAvatar') ->with('userDoesNotExist') - ->will($this->throwException(new \Exception('user does not exist'))); + ->willThrowException(new \Exception('user does not exist')); $response = $this->avatarController->getAvatar('userDoesNotExist', 32); @@ -278,7 +277,7 @@ class AvatarControllerTest extends \Test\TestCase { /** * Remove an avatar */ - public function testDeleteAvatar() { + public function testDeleteAvatar(): void { $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); $response = $this->avatarController->deleteAvatar(); @@ -288,13 +287,13 @@ class AvatarControllerTest extends \Test\TestCase { /** * Test what happens if the removing of the avatar fails */ - public function testDeleteAvatarException() { - $this->avatarMock->method('remove')->will($this->throwException(new \Exception("foo"))); + public function testDeleteAvatarException(): void { + $this->avatarMock->method('remove')->willThrowException(new \Exception('foo')); $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); $this->logger->expects($this->once()) - ->method('logException') - ->with(new \Exception("foo")); + ->method('error') + ->with('foo', ['exception' => new \Exception('foo'), 'app' => 'core']); $expectedResponse = new Http\JSONResponse(['data' => ['message' => 'An error occurred. Please contact your admin.']], Http::STATUS_BAD_REQUEST); $this->assertEquals($expectedResponse, $this->avatarController->deleteAvatar()); } @@ -302,7 +301,7 @@ class AvatarControllerTest extends \Test\TestCase { /** * Trying to get a tmp avatar when it is not available. 404 */ - public function testTmpAvatarNoTmp() { + public function testTmpAvatarNoTmp(): void { $response = $this->avatarController->getTmpAvatar(); $this->assertEquals(Http::STATUS_NOT_FOUND, $response->getStatus()); } @@ -310,8 +309,8 @@ class AvatarControllerTest extends \Test\TestCase { /** * Fetch tmp avatar */ - public function testTmpAvatarValid() { - $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); + public function testTmpAvatarValid(): void { + $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT . '/tests/data/testimage.jpg')); $response = $this->avatarController->getTmpAvatar(); $this->assertEquals(Http::STATUS_OK, $response->getStatus()); @@ -321,7 +320,7 @@ class AvatarControllerTest extends \Test\TestCase { /** * When trying to post a new avatar a path or image should be posted. */ - public function testPostAvatarNoPathOrImage() { + public function testPostAvatarNoPathOrImage(): void { $response = $this->avatarController->postAvatar(null); $this->assertEquals(Http::STATUS_BAD_REQUEST, $response->getStatus()); @@ -330,17 +329,17 @@ class AvatarControllerTest extends \Test\TestCase { /** * Test a correct post of an avatar using POST */ - public function testPostAvatarFile() { + public function testPostAvatarFile(): void { //Create temp file - $fileName = tempnam('', "avatarTest"); - $copyRes = copy(\OC::$SERVERROOT.'/tests/data/testimage.jpg', $fileName); + $fileName = tempnam('', 'avatarTest'); + $copyRes = copy(\OC::$SERVERROOT . '/tests/data/testimage.jpg', $fileName); $this->assertTrue($copyRes); //Create file in cache - $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); + $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT . '/tests/data/testimage.jpg')); //Create request return - $reqRet = ['error' => [0], 'tmp_name' => [$fileName], 'size' => [filesize(\OC::$SERVERROOT.'/tests/data/testimage.jpg')]]; + $reqRet = ['error' => [0], 'tmp_name' => [$fileName], 'size' => [filesize(\OC::$SERVERROOT . '/tests/data/testimage.jpg')]]; $this->request->method('getUploadedFile')->willReturn($reqRet); $response = $this->avatarController->postAvatar(null); @@ -355,7 +354,7 @@ class AvatarControllerTest extends \Test\TestCase { /** * Test invalid post os an avatar using POST */ - public function testPostAvatarInvalidFile() { + public function testPostAvatarInvalidFile(): void { //Create request return $reqRet = ['error' => [1], 'tmp_name' => ['foo']]; $this->request->method('getUploadedFile')->willReturn($reqRet); @@ -368,17 +367,17 @@ class AvatarControllerTest extends \Test\TestCase { /** * Check what happens when we upload a GIF */ - public function testPostAvatarFileGif() { + public function testPostAvatarFileGif(): void { //Create temp file - $fileName = tempnam('', "avatarTest"); - $copyRes = copy(\OC::$SERVERROOT.'/tests/data/testimage.gif', $fileName); + $fileName = tempnam('', 'avatarTest'); + $copyRes = copy(\OC::$SERVERROOT . '/tests/data/testimage.gif', $fileName); $this->assertTrue($copyRes); //Create file in cache - $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.gif')); + $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT . '/tests/data/testimage.gif')); //Create request return - $reqRet = ['error' => [0], 'tmp_name' => [$fileName], 'size' => [filesize(\OC::$SERVERROOT.'/tests/data/testimage.gif')]]; + $reqRet = ['error' => [0], 'tmp_name' => [$fileName], 'size' => [filesize(\OC::$SERVERROOT . '/tests/data/testimage.gif')]]; $this->request->method('getUploadedFile')->willReturn($reqRet); $response = $this->avatarController->postAvatar(null); @@ -392,13 +391,13 @@ class AvatarControllerTest extends \Test\TestCase { /** * Test posting avatar from existing file */ - public function testPostAvatarFromFile() { + public function testPostAvatarFromFile(): void { //Mock node API call $file = $this->getMockBuilder('OCP\Files\File') ->disableOriginalConstructor()->getMock(); $file->expects($this->once()) ->method('getContent') - ->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); + ->willReturn(file_get_contents(\OC::$SERVERROOT . '/tests/data/testimage.jpg')); $file->expects($this->once()) ->method('getMimeType') ->willReturn('image/jpeg'); @@ -416,7 +415,7 @@ class AvatarControllerTest extends \Test\TestCase { /** * Test posting avatar from existing folder */ - public function testPostAvatarFromNoFile() { + public function testPostAvatarFromNoFile(): void { $file = $this->getMockBuilder('OCP\Files\Node')->getMock(); $userFolder = $this->getMockBuilder('OCP\Files\Folder')->getMock(); $this->rootFolder->method('getUserFolder')->with('userid')->willReturn($userFolder); @@ -432,7 +431,7 @@ class AvatarControllerTest extends \Test\TestCase { $this->assertEquals(['data' => ['message' => 'Please select a file.']], $response->getData()); } - public function testPostAvatarInvalidType() { + public function testPostAvatarInvalidType(): void { $file = $this->getMockBuilder('OCP\Files\File') ->disableOriginalConstructor()->getMock(); $file->expects($this->never()) @@ -448,7 +447,7 @@ class AvatarControllerTest extends \Test\TestCase { $this->assertEquals($expectedResponse, $this->avatarController->postAvatar('avatar.jpg')); } - public function testPostAvatarNotPermittedException() { + public function testPostAvatarNotPermittedException(): void { $file = $this->getMockBuilder('OCP\Files\File') ->disableOriginalConstructor()->getMock(); $file->expects($this->once()) @@ -468,15 +467,15 @@ class AvatarControllerTest extends \Test\TestCase { /** * Test what happens if the upload of the avatar fails */ - public function testPostAvatarException() { + public function testPostAvatarException(): void { $this->cache->expects($this->once()) ->method('set') - ->will($this->throwException(new \Exception("foo"))); + ->willThrowException(new \Exception('foo')); $file = $this->getMockBuilder('OCP\Files\File') ->disableOriginalConstructor()->getMock(); $file->expects($this->once()) ->method('getContent') - ->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); + ->willReturn(file_get_contents(\OC::$SERVERROOT . '/tests/data/testimage.jpg')); $file->expects($this->once()) ->method('getMimeType') ->willReturn('image/jpeg'); @@ -485,8 +484,8 @@ class AvatarControllerTest extends \Test\TestCase { $userFolder->method('get')->willReturn($file); $this->logger->expects($this->once()) - ->method('logException') - ->with(new \Exception("foo")); + ->method('error') + ->with('foo', ['exception' => new \Exception('foo'), 'app' => 'core']); $expectedResponse = new Http\JSONResponse(['data' => ['message' => 'An error occurred. Please contact your admin.']], Http::STATUS_OK); $this->assertEquals($expectedResponse, $this->avatarController->postAvatar('avatar.jpg')); } @@ -495,7 +494,7 @@ class AvatarControllerTest extends \Test\TestCase { /** * Test invalid crop argument */ - public function testPostCroppedAvatarInvalidCrop() { + public function testPostCroppedAvatarInvalidCrop(): void { $response = $this->avatarController->postCroppedAvatar([]); $this->assertEquals(Http::STATUS_BAD_REQUEST, $response->getStatus()); @@ -504,7 +503,7 @@ class AvatarControllerTest extends \Test\TestCase { /** * Test no tmp avatar to crop */ - public function testPostCroppedAvatarNoTmpAvatar() { + public function testPostCroppedAvatarNoTmpAvatar(): void { $response = $this->avatarController->postCroppedAvatar(['x' => 0, 'y' => 0, 'w' => 10, 'h' => 10]); $this->assertEquals(Http::STATUS_BAD_REQUEST, $response->getStatus()); @@ -513,10 +512,10 @@ class AvatarControllerTest extends \Test\TestCase { /** * Test with non square crop */ - public function testPostCroppedAvatarNoSquareCrop() { - $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); + public function testPostCroppedAvatarNoSquareCrop(): void { + $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT . '/tests/data/testimage.jpg')); - $this->avatarMock->method('set')->will($this->throwException(new \OC\NotSquareException)); + $this->avatarMock->method('set')->willThrowException(new \OC\NotSquareException); $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); $response = $this->avatarController->postCroppedAvatar(['x' => 0, 'y' => 0, 'w' => 10, 'h' => 11]); @@ -526,8 +525,8 @@ class AvatarControllerTest extends \Test\TestCase { /** * Check for proper reply on proper crop argument */ - public function testPostCroppedAvatarValidCrop() { - $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); + public function testPostCroppedAvatarValidCrop(): void { + $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT . '/tests/data/testimage.jpg')); $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); $response = $this->avatarController->postCroppedAvatar(['x' => 0, 'y' => 0, 'w' => 10, 'h' => 10]); @@ -538,15 +537,15 @@ class AvatarControllerTest extends \Test\TestCase { /** * Test what happens if the cropping of the avatar fails */ - public function testPostCroppedAvatarException() { - $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT.'/tests/data/testimage.jpg')); + public function testPostCroppedAvatarException(): void { + $this->cache->method('get')->willReturn(file_get_contents(\OC::$SERVERROOT . '/tests/data/testimage.jpg')); - $this->avatarMock->method('set')->will($this->throwException(new \Exception('foo'))); + $this->avatarMock->method('set')->willThrowException(new \Exception('foo')); $this->avatarManager->method('getAvatar')->willReturn($this->avatarMock); $this->logger->expects($this->once()) - ->method('logException') - ->with(new \Exception('foo')); + ->method('error') + ->with('foo', ['exception' => new \Exception('foo'), 'app' => 'core']); $expectedResponse = new Http\JSONResponse(['data' => ['message' => 'An error occurred. Please contact your admin.']], Http::STATUS_BAD_REQUEST); $this->assertEquals($expectedResponse, $this->avatarController->postCroppedAvatar(['x' => 0, 'y' => 0, 'w' => 10, 'h' => 11])); } @@ -555,8 +554,8 @@ class AvatarControllerTest extends \Test\TestCase { /** * Check for proper reply on proper crop argument */ - public function testFileTooBig() { - $fileName = \OC::$SERVERROOT.'/tests/data/testimage.jpg'; + public function testFileTooBig(): void { + $fileName = \OC::$SERVERROOT . '/tests/data/testimage.jpg'; //Create request return $reqRet = ['error' => [0], 'tmp_name' => [$fileName], 'size' => [21 * 1024 * 1024]]; $this->request->method('getUploadedFile')->willReturn($reqRet); diff --git a/tests/Core/Controller/CSRFTokenControllerTest.php b/tests/Core/Controller/CSRFTokenControllerTest.php index 875d5a79168..a401788be8d 100644 --- a/tests/Core/Controller/CSRFTokenControllerTest.php +++ b/tests/Core/Controller/CSRFTokenControllerTest.php @@ -1,25 +1,8 @@ <?php /** - * @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Tests\Core\Controller; @@ -33,7 +16,6 @@ use OCP\IRequest; use Test\TestCase; class CSRFTokenControllerTest extends TestCase { - /** @var CSRFTokenController */ private $controller; diff --git a/tests/Core/Controller/ChangePasswordControllerTest.php b/tests/Core/Controller/ChangePasswordControllerTest.php index 190afd3be47..aae36fb52b8 100644 --- a/tests/Core/Controller/ChangePasswordControllerTest.php +++ b/tests/Core/Controller/ChangePasswordControllerTest.php @@ -1,23 +1,8 @@ <?php + /** - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Tests\Core\Controller; @@ -76,7 +61,7 @@ class ChangePasswordControllerTest extends \Test\TestCase { ); } - public function testChangePersonalPasswordWrongPassword() { + public function testChangePersonalPasswordWrongPassword(): void { $this->userSession->expects($this->once()) ->method('getLoginName') ->willReturn($this->loginName); @@ -98,7 +83,7 @@ class ChangePasswordControllerTest extends \Test\TestCase { $this->assertEquals($expects, $actual); } - public function testChangePersonalPasswordCommonPassword() { + public function testChangePersonalPasswordCommonPassword(): void { $this->userSession->expects($this->once()) ->method('getLoginName') ->willReturn($this->loginName); @@ -112,7 +97,7 @@ class ChangePasswordControllerTest extends \Test\TestCase { $user->expects($this->once()) ->method('setPassword') ->with('new') - ->will($this->throwException(new HintException('Common password'))); + ->willThrowException(new HintException('Common password')); $expects = new JSONResponse([ 'status' => 'error', @@ -125,7 +110,7 @@ class ChangePasswordControllerTest extends \Test\TestCase { $this->assertEquals($expects, $actual); } - public function testChangePersonalPasswordNoNewPassword() { + public function testChangePersonalPasswordNoNewPassword(): void { $this->userSession->expects($this->once()) ->method('getLoginName') ->willReturn($this->loginName); @@ -138,6 +123,9 @@ class ChangePasswordControllerTest extends \Test\TestCase { $expects = [ 'status' => 'error', + 'data' => [ + 'message' => 'Unable to change personal password', + ], ]; $res = $this->controller->changePersonalPassword('old'); @@ -145,7 +133,7 @@ class ChangePasswordControllerTest extends \Test\TestCase { $this->assertEquals($expects, $res->getData()); } - public function testChangePersonalPasswordCantSetPassword() { + public function testChangePersonalPasswordCantSetPassword(): void { $this->userSession->expects($this->once()) ->method('getLoginName') ->willReturn($this->loginName); @@ -163,13 +151,16 @@ class ChangePasswordControllerTest extends \Test\TestCase { $expects = new JSONResponse([ 'status' => 'error', + 'data' => [ + 'message' => 'Unable to change personal password', + ], ]); $actual = $this->controller->changePersonalPassword('old', 'new'); $this->assertEquals($expects, $actual); } - public function testChangePersonalPassword() { + public function testChangePersonalPassword(): void { $this->userSession->expects($this->once()) ->method('getLoginName') ->willReturn($this->loginName); diff --git a/tests/Core/Controller/ClientFlowLoginControllerTest.php b/tests/Core/Controller/ClientFlowLoginControllerTest.php index dae42474f41..b182bb1bb39 100644 --- a/tests/Core/Controller/ClientFlowLoginControllerTest.php +++ b/tests/Core/Controller/ClientFlowLoginControllerTest.php @@ -1,22 +1,10 @@ <?php + +declare(strict_types=1); + /** - * @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Tests\Core\Controller; @@ -30,9 +18,14 @@ use OCA\OAuth2\Db\AccessTokenMapper; use OCA\OAuth2\Db\Client; use OCA\OAuth2\Db\ClientMapper; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\ContentSecurityPolicy; +use OCP\AppFramework\Http\RedirectResponse; +use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\StandaloneTemplateResponse; +use OCP\AppFramework\Utility\ITimeFactory; use OCP\Defaults; use OCP\EventDispatcher\IEventDispatcher; +use OCP\IConfig; use OCP\IL10N; use OCP\IRequest; use OCP\ISession; @@ -42,37 +35,26 @@ use OCP\IUserSession; use OCP\Security\ICrypto; use OCP\Security\ISecureRandom; use OCP\Session\Exceptions\SessionNotAvailableException; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class ClientFlowLoginControllerTest extends TestCase { - /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */ - private $request; - /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */ - private $userSession; - /** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */ - private $l10n; - /** @var Defaults|\PHPUnit\Framework\MockObject\MockObject */ - private $defaults; - /** @var ISession|\PHPUnit\Framework\MockObject\MockObject */ - private $session; - /** @var IProvider|\PHPUnit\Framework\MockObject\MockObject */ - private $tokenProvider; - /** @var ISecureRandom|\PHPUnit\Framework\MockObject\MockObject */ - private $random; - /** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */ - private $urlGenerator; - /** @var ClientMapper|\PHPUnit\Framework\MockObject\MockObject */ - private $clientMapper; - /** @var AccessTokenMapper|\PHPUnit\Framework\MockObject\MockObject */ - private $accessTokenMapper; - /** @var ICrypto|\PHPUnit\Framework\MockObject\MockObject */ - private $crypto; - /** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */ - private $eventDispatcher; - - - /** @var ClientFlowLoginController */ - private $clientFlowLoginController; + private IRequest&MockObject $request; + private IUserSession&MockObject $userSession; + private IL10N&MockObject $l10n; + private Defaults&MockObject $defaults; + private ISession&MockObject $session; + private IProvider&MockObject $tokenProvider; + private ISecureRandom&MockObject $random; + private IURLGenerator&MockObject $urlGenerator; + private ClientMapper&MockObject $clientMapper; + private AccessTokenMapper&MockObject $accessTokenMapper; + private ICrypto&MockObject $crypto; + private IEventDispatcher&MockObject $eventDispatcher; + private ITimeFactory&MockObject $timeFactory; + private IConfig&MockObject $config; + + private ClientFlowLoginController $clientFlowLoginController; protected function setUp(): void { parent::setUp(); @@ -95,6 +77,8 @@ class ClientFlowLoginControllerTest extends TestCase { $this->accessTokenMapper = $this->createMock(AccessTokenMapper::class); $this->crypto = $this->createMock(ICrypto::class); $this->eventDispatcher = $this->createMock(IEventDispatcher::class); + $this->timeFactory = $this->createMock(ITimeFactory::class); + $this->config = $this->createMock(IConfig::class); $this->clientFlowLoginController = new ClientFlowLoginController( 'core', @@ -109,17 +93,19 @@ class ClientFlowLoginControllerTest extends TestCase { $this->clientMapper, $this->accessTokenMapper, $this->crypto, - $this->eventDispatcher + $this->eventDispatcher, + $this->timeFactory, + $this->config, ); } - public function testShowAuthPickerPageNoClientOrOauthRequest() { + public function testShowAuthPickerPageNoClientOrOauthRequest(): void { $expected = new StandaloneTemplateResponse( 'core', 'error', [ - 'errors' => - [ + 'errors' + => [ [ 'error' => 'Access Forbidden', 'hint' => 'Invalid request', @@ -132,23 +118,19 @@ class ClientFlowLoginControllerTest extends TestCase { $this->assertEquals($expected, $this->clientFlowLoginController->showAuthPickerPage()); } - public function testShowAuthPickerPageWithOcsHeader() { + public function testShowAuthPickerPageWithOcsHeader(): void { $this->request - ->expects($this->at(0)) ->method('getHeader') - ->with('USER_AGENT') - ->willReturn('Mac OS X Sync Client'); - $this->request - ->expects($this->at(1)) - ->method('getHeader') - ->with('OCS-APIREQUEST') - ->willReturn('true'); + ->willReturnMap([ + ['user-agent', 'Mac OS X Sync Client'], + ['OCS-APIREQUEST', 'true'], + ]); $this->random ->expects($this->once()) ->method('generate') ->with( 64, - ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS + ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS ) ->willReturn('StateToken'); $this->session @@ -184,22 +166,24 @@ class ClientFlowLoginControllerTest extends TestCase { 'serverHost' => 'https://example.com', 'oauthState' => 'OauthStateToken', 'user' => '', - 'direct' => 0 + 'direct' => 0, + 'providedRedirectUri' => '', ], 'guest' ); - $csp = new Http\ContentSecurityPolicy(); + $csp = new ContentSecurityPolicy(); $csp->addAllowedFormActionDomain('nc://*'); $expected->setContentSecurityPolicy($csp); $this->assertEquals($expected, $this->clientFlowLoginController->showAuthPickerPage()); } - public function testShowAuthPickerPageWithOauth() { + public function testShowAuthPickerPageWithOauth(): void { $this->request - ->expects($this->at(0)) ->method('getHeader') - ->with('USER_AGENT') - ->willReturn('Mac OS X Sync Client'); + ->willReturnMap([ + ['user-agent', 'Mac OS X Sync Client'], + ['OCS-APIREQUEST', 'false'], + ]); $client = new Client(); $client->setName('My external service'); $client->setRedirectUri('https://example.com/redirect.php'); @@ -213,7 +197,7 @@ class ClientFlowLoginControllerTest extends TestCase { ->method('generate') ->with( 64, - ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS + ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS ) ->willReturn('StateToken'); $this->session @@ -249,17 +233,18 @@ class ClientFlowLoginControllerTest extends TestCase { 'serverHost' => 'https://example.com', 'oauthState' => 'OauthStateToken', 'user' => '', - 'direct' => 0 + 'direct' => 0, + 'providedRedirectUri' => '', ], 'guest' ); - $csp = new Http\ContentSecurityPolicy(); + $csp = new ContentSecurityPolicy(); $csp->addAllowedFormActionDomain('https://example.com/redirect.php'); $expected->setContentSecurityPolicy($csp); $this->assertEquals($expected, $this->clientFlowLoginController->showAuthPickerPage('MyClientIdentifier')); } - public function testGenerateAppPasswordWithInvalidToken() { + public function testGenerateAppPasswordWithInvalidToken(): void { $this->session ->expects($this->once()) ->method('get') @@ -282,7 +267,7 @@ class ClientFlowLoginControllerTest extends TestCase { $this->assertEquals($expected, $this->clientFlowLoginController->generateAppPassword('MyStateToken')); } - public function testGenerateAppPasswordWithSessionNotAvailableException() { + public function testGenerateAppPasswordWithSessionNotAvailableException(): void { $this->session ->expects($this->once()) ->method('get') @@ -297,12 +282,12 @@ class ClientFlowLoginControllerTest extends TestCase { ->method('getId') ->willThrowException(new SessionNotAvailableException()); - $expected = new Http\Response(); + $expected = new Response(); $expected->setStatus(Http::STATUS_FORBIDDEN); $this->assertEquals($expected, $this->clientFlowLoginController->generateAppPassword('MyStateToken')); } - public function testGenerateAppPasswordWithInvalidTokenException() { + public function testGenerateAppPasswordWithInvalidTokenException(): void { $this->session ->expects($this->once()) ->method('get') @@ -322,12 +307,12 @@ class ClientFlowLoginControllerTest extends TestCase { ->with('SessionId') ->willThrowException(new InvalidTokenException()); - $expected = new Http\Response(); + $expected = new Response(); $expected->setStatus(Http::STATUS_FORBIDDEN); $this->assertEquals($expected, $this->clientFlowLoginController->generateAppPassword('MyStateToken')); } - public function testGeneratePasswordWithPassword() { + public function testGeneratePasswordWithPassword(): void { $this->session ->expects($this->once()) ->method('get') @@ -398,7 +383,7 @@ class ClientFlowLoginControllerTest extends TestCase { $this->eventDispatcher->expects($this->once()) ->method('dispatchTyped'); - $expected = new Http\RedirectResponse('nc://login/server:http://example.com&user:MyLoginName&password:MyGeneratedToken'); + $expected = new RedirectResponse('nc://login/server:http://example.com&user:MyLoginName&password:MyGeneratedToken'); $this->assertEquals($expected, $this->clientFlowLoginController->generateAppPassword('MyStateToken')); } @@ -411,25 +396,23 @@ class ClientFlowLoginControllerTest extends TestCase { * ["https://example.com/redirect.php?hello=world", "https://example.com/redirect.php?hello=world&state=MyOauthState&code=MyAccessCode"] * */ - public function testGeneratePasswordWithPasswordForOauthClient($redirectUri, $redirectUrl) { - $this->session - ->expects($this->at(0)) - ->method('get') - ->with('client.flow.state.token') - ->willReturn('MyStateToken'); - $this->session - ->expects($this->at(1)) - ->method('remove') - ->with('client.flow.state.token'); + public function testGeneratePasswordWithPasswordForOauthClient($redirectUri, $redirectUrl): void { $this->session - ->expects($this->at(3)) ->method('get') - ->with('oauth.state') - ->willReturn('MyOauthState'); + ->willReturnMap([ + ['client.flow.state.token', 'MyStateToken'], + ['oauth.state', 'MyOauthState'], + ]); + $calls = [ + 'client.flow.state.token', + 'oauth.state', + ]; $this->session - ->expects($this->at(4)) ->method('remove') - ->with('oauth.state'); + ->willReturnCallback(function ($key) use (&$calls): void { + $expected = array_shift($calls); + $this->assertEquals($expected, $key); + }); $this->session ->expects($this->once()) ->method('getId') @@ -450,15 +433,11 @@ class ClientFlowLoginControllerTest extends TestCase { ->with($myToken, 'SessionId') ->willReturn('MyPassword'); $this->random - ->expects($this->at(0)) - ->method('generate') - ->with(72) - ->willReturn('MyGeneratedToken'); - $this->random - ->expects($this->at(1)) ->method('generate') - ->with(128) - ->willReturn('MyAccessCode'); + ->willReturnMap([ + [72, ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS, 'MyGeneratedToken'], + [128, ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS, 'MyAccessCode'], + ]); $user = $this->createMock(IUser::class); $user ->expects($this->once()) @@ -494,11 +473,11 @@ class ClientFlowLoginControllerTest extends TestCase { $this->eventDispatcher->expects($this->once()) ->method('dispatchTyped'); - $expected = new Http\RedirectResponse($redirectUrl); + $expected = new RedirectResponse($redirectUrl); $this->assertEquals($expected, $this->clientFlowLoginController->generateAppPassword('MyStateToken', 'MyClientIdentifier')); } - public function testGeneratePasswordWithoutPassword() { + public function testGeneratePasswordWithoutPassword(): void { $this->session ->expects($this->once()) ->method('get') @@ -569,17 +548,17 @@ class ClientFlowLoginControllerTest extends TestCase { $this->eventDispatcher->expects($this->once()) ->method('dispatchTyped'); - $expected = new Http\RedirectResponse('nc://login/server:http://example.com&user:MyLoginName&password:MyGeneratedToken'); + $expected = new RedirectResponse('nc://login/server:http://example.com&user:MyLoginName&password:MyGeneratedToken'); $this->assertEquals($expected, $this->clientFlowLoginController->generateAppPassword('MyStateToken')); } - public function dataGeneratePasswordWithHttpsProxy() { + public static function dataGeneratePasswordWithHttpsProxy(): array { return [ [ [ ['X-Forwarded-Proto', 'http'], ['X-Forwarded-Ssl', 'off'], - ['USER_AGENT', ''], + ['user-agent', ''], ], 'http', 'http', @@ -588,7 +567,7 @@ class ClientFlowLoginControllerTest extends TestCase { [ ['X-Forwarded-Proto', 'http'], ['X-Forwarded-Ssl', 'off'], - ['USER_AGENT', ''], + ['user-agent', ''], ], 'https', 'https', @@ -597,7 +576,7 @@ class ClientFlowLoginControllerTest extends TestCase { [ ['X-Forwarded-Proto', 'https'], ['X-Forwarded-Ssl', 'off'], - ['USER_AGENT', ''], + ['user-agent', ''], ], 'http', 'https', @@ -606,7 +585,7 @@ class ClientFlowLoginControllerTest extends TestCase { [ ['X-Forwarded-Proto', 'https'], ['X-Forwarded-Ssl', 'on'], - ['USER_AGENT', ''], + ['user-agent', ''], ], 'http', 'https', @@ -615,7 +594,7 @@ class ClientFlowLoginControllerTest extends TestCase { [ ['X-Forwarded-Proto', 'http'], ['X-Forwarded-Ssl', 'on'], - ['USER_AGENT', ''], + ['user-agent', ''], ], 'http', 'https', @@ -624,12 +603,12 @@ class ClientFlowLoginControllerTest extends TestCase { } /** - * @dataProvider dataGeneratePasswordWithHttpsProxy * @param array $headers * @param string $protocol * @param string $expected */ - public function testGeneratePasswordWithHttpsProxy(array $headers, $protocol, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGeneratePasswordWithHttpsProxy')] + public function testGeneratePasswordWithHttpsProxy(array $headers, $protocol, $expected): void { $this->session ->expects($this->once()) ->method('get') @@ -700,7 +679,7 @@ class ClientFlowLoginControllerTest extends TestCase { $this->eventDispatcher->expects($this->once()) ->method('dispatchTyped'); - $expected = new Http\RedirectResponse('nc://login/server:' . $expected . '://example.com&user:MyLoginName&password:MyGeneratedToken'); + $expected = new RedirectResponse('nc://login/server:' . $expected . '://example.com&user:MyLoginName&password:MyGeneratedToken'); $this->assertEquals($expected, $this->clientFlowLoginController->generateAppPassword('MyStateToken')); } } diff --git a/tests/Core/Controller/ClientFlowLoginV2ControllerTest.php b/tests/Core/Controller/ClientFlowLoginV2ControllerTest.php index 1e35dc71c3f..d130eb75c1a 100644 --- a/tests/Core/Controller/ClientFlowLoginV2ControllerTest.php +++ b/tests/Core/Controller/ClientFlowLoginV2ControllerTest.php @@ -2,25 +2,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\Core\Controller; @@ -28,20 +11,24 @@ namespace Test\Core\Controller; use OC\Core\Controller\ClientFlowLoginV2Controller; use OC\Core\Data\LoginFlowV2Credentials; use OC\Core\Db\LoginFlowV2; +use OC\Core\Exception\LoginFlowV2ClientForbiddenException; use OC\Core\Exception\LoginFlowV2NotFoundException; use OC\Core\Service\LoginFlowV2Service; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\RedirectResponse; +use OCP\AppFramework\Http\StandaloneTemplateResponse; use OCP\Defaults; use OCP\IL10N; use OCP\IRequest; use OCP\ISession; use OCP\IURLGenerator; +use OCP\IUser; +use OCP\IUserSession; use OCP\Security\ISecureRandom; use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class ClientFlowLoginV2ControllerTest extends TestCase { - /** @var IRequest|MockObject */ private $request; /** @var LoginFlowV2Service|MockObject */ @@ -50,6 +37,8 @@ class ClientFlowLoginV2ControllerTest extends TestCase { private $urlGenerator; /** @var ISession|MockObject */ private $session; + /** @var IUserSession|MockObject */ + private $userSession; /** @var ISecureRandom|MockObject */ private $random; /** @var Defaults|MockObject */ @@ -66,15 +55,23 @@ class ClientFlowLoginV2ControllerTest extends TestCase { $this->loginFlowV2Service = $this->createMock(LoginFlowV2Service::class); $this->urlGenerator = $this->createMock(IURLGenerator::class); $this->session = $this->createMock(ISession::class); + $this->userSession = $this->createMock(IUserSession::class); $this->random = $this->createMock(ISecureRandom::class); $this->defaults = $this->createMock(Defaults::class); $this->l = $this->createMock(IL10N::class); + $this->l + ->expects($this->any()) + ->method('t') + ->willReturnCallback(function ($text, $parameters = []) { + return vsprintf($text, $parameters); + }); $this->controller = new ClientFlowLoginV2Controller( 'core', $this->request, $this->loginFlowV2Service, $this->urlGenerator, $this->session, + $this->userSession, $this->random, $this->defaults, 'user', @@ -82,7 +79,7 @@ class ClientFlowLoginV2ControllerTest extends TestCase { ); } - public function testPollInvalid() { + public function testPollInvalid(): void { $this->loginFlowV2Service->method('poll') ->with('token') ->willThrowException(new LoginFlowV2NotFoundException()); @@ -93,7 +90,7 @@ class ClientFlowLoginV2ControllerTest extends TestCase { $this->assertSame(Http::STATUS_NOT_FOUND, $result->getStatus()); } - public function testPollValid() { + public function testPollValid(): void { $creds = new LoginFlowV2Credentials('server', 'login', 'pass'); $this->loginFlowV2Service->method('poll') ->with('token') @@ -101,11 +98,11 @@ class ClientFlowLoginV2ControllerTest extends TestCase { $result = $this->controller->poll('token'); - $this->assertSame($creds, $result->getData()); + $this->assertSame($creds->jsonSerialize(), $result->getData()); $this->assertSame(Http::STATUS_OK, $result->getStatus()); } - public function testLandingInvalid() { + public function testLandingInvalid(): void { $this->session->expects($this->never()) ->method($this->anything()); @@ -116,10 +113,10 @@ class ClientFlowLoginV2ControllerTest extends TestCase { $result = $this->controller->landing('token'); $this->assertSame(Http::STATUS_FORBIDDEN, $result->getStatus()); - $this->assertInstanceOf(Http\StandaloneTemplateResponse::class, $result); + $this->assertInstanceOf(StandaloneTemplateResponse::class, $result); } - public function testLandingValid() { + public function testLandingValid(): void { $this->session->expects($this->once()) ->method('set') ->with('client.flow.v2.login.token', 'token'); @@ -134,12 +131,12 @@ class ClientFlowLoginV2ControllerTest extends TestCase { $result = $this->controller->landing('token'); - $this->assertInstanceOf(Http\RedirectResponse::class, $result); + $this->assertInstanceOf(RedirectResponse::class, $result); $this->assertSame(Http::STATUS_SEE_OTHER, $result->getStatus()); $this->assertSame('https://server/path', $result->getRedirectURL()); } - public function testShowAuthPickerNoLoginToken() { + public function testShowAuthPickerNoLoginToken(): void { $this->session->method('get') ->willReturn(null); @@ -148,7 +145,7 @@ class ClientFlowLoginV2ControllerTest extends TestCase { $this->assertSame(Http::STATUS_FORBIDDEN, $result->getStatus()); } - public function testShowAuthPickerInvalidLoginToken() { + public function testShowAuthPickerInvalidLoginToken(): void { $this->session->method('get') ->with('client.flow.v2.login.token') ->willReturn('loginToken'); @@ -162,7 +159,23 @@ class ClientFlowLoginV2ControllerTest extends TestCase { $this->assertSame(Http::STATUS_FORBIDDEN, $result->getStatus()); } - public function testShowAuthPickerValidLoginToken() { + public function testShowAuthPickerForbiddenUserClient() { + $this->session->method('get') + ->with('client.flow.v2.login.token') + ->willReturn('loginToken'); + + $this->loginFlowV2Service->method('getByLoginToken') + ->with('loginToken') + ->willThrowException(new LoginFlowV2ClientForbiddenException()); + + $result = $this->controller->showAuthPickerPage(); + + $this->assertInstanceOf(StandaloneTemplateResponse::class, $result); + $this->assertSame(Http::STATUS_FORBIDDEN, $result->getStatus()); + $this->assertSame('Please use original client', $result->getParams()['message']); + } + + public function testShowAuthPickerValidLoginToken(): void { $this->session->method('get') ->with('client.flow.v2.login.token') ->willReturn('loginToken'); @@ -173,7 +186,7 @@ class ClientFlowLoginV2ControllerTest extends TestCase { ->willReturn($flow); $this->random->method('generate') - ->with(64, ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS) + ->with(64, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS) ->willReturn('random'); $this->session->expects($this->once()) ->method('set') @@ -182,7 +195,13 @@ class ClientFlowLoginV2ControllerTest extends TestCase { $this->controller->showAuthPickerPage(); } - public function testGrantPageInvalidStateToken() { + public function testGrantPageNoStateToken(): void { + $result = $this->controller->grantPage(null); + + $this->assertSame(Http::STATUS_FORBIDDEN, $result->getStatus()); + } + + public function testGrantPageInvalidStateToken(): void { $this->session->method('get') ->willReturnCallback(function ($name) { return null; @@ -192,7 +211,7 @@ class ClientFlowLoginV2ControllerTest extends TestCase { $this->assertSame(Http::STATUS_FORBIDDEN, $result->getStatus()); } - public function testGrantPageInvalidLoginToken() { + public function testGrantPageInvalidLoginToken(): void { $this->session->method('get') ->willReturnCallback(function ($name) { if ($name === 'client.flow.v2.state.token') { @@ -212,7 +231,7 @@ class ClientFlowLoginV2ControllerTest extends TestCase { $this->assertSame(Http::STATUS_FORBIDDEN, $result->getStatus()); } - public function testGrantPageValid() { + public function testGrantPageForbiddenUserClient() { $this->session->method('get') ->willReturnCallback(function ($name) { if ($name === 'client.flow.v2.state.token') { @@ -224,6 +243,37 @@ class ClientFlowLoginV2ControllerTest extends TestCase { return null; }); + $this->loginFlowV2Service->method('getByLoginToken') + ->with('loginToken') + ->willThrowException(new LoginFlowV2ClientForbiddenException()); + + $result = $this->controller->grantPage('stateToken'); + + $this->assertInstanceOf(StandaloneTemplateResponse::class, $result); + $this->assertSame(Http::STATUS_FORBIDDEN, $result->getStatus()); + $this->assertSame('Please use original client', $result->getParams()['message']); + } + + public function testGrantPageValid(): void { + $this->session->method('get') + ->willReturnCallback(function ($name) { + if ($name === 'client.flow.v2.state.token') { + return 'stateToken'; + } + if ($name === 'client.flow.v2.login.token') { + return 'loginToken'; + } + return null; + }); + + $user = $this->createMock(IUser::class); + $user->method('getUID') + ->willReturn('uid'); + $user->method('getDisplayName') + ->willReturn('display name'); + $this->userSession->method('getUser') + ->willReturn($user); + $flow = new LoginFlowV2(); $this->loginFlowV2Service->method('getByLoginToken') ->with('loginToken') @@ -234,7 +284,7 @@ class ClientFlowLoginV2ControllerTest extends TestCase { } - public function testGenerateAppPasswordInvalidStateToken() { + public function testGenerateAppPasswordInvalidStateToken(): void { $this->session->method('get') ->willReturnCallback(function ($name) { return null; @@ -244,7 +294,7 @@ class ClientFlowLoginV2ControllerTest extends TestCase { $this->assertSame(Http::STATUS_FORBIDDEN, $result->getStatus()); } - public function testGenerateAppPassworInvalidLoginToken() { + public function testGenerateAppPassworInvalidLoginToken(): void { $this->session->method('get') ->willReturnCallback(function ($name) { if ($name === 'client.flow.v2.state.token') { @@ -264,7 +314,30 @@ class ClientFlowLoginV2ControllerTest extends TestCase { $this->assertSame(Http::STATUS_FORBIDDEN, $result->getStatus()); } - public function testGenerateAppPassworValid() { + public function testGenerateAppPasswordForbiddenUserClient() { + $this->session->method('get') + ->willReturnCallback(function ($name) { + if ($name === 'client.flow.v2.state.token') { + return 'stateToken'; + } + if ($name === 'client.flow.v2.login.token') { + return 'loginToken'; + } + return null; + }); + + $this->loginFlowV2Service->method('getByLoginToken') + ->with('loginToken') + ->willThrowException(new LoginFlowV2ClientForbiddenException()); + + $result = $this->controller->generateAppPassword('stateToken'); + + $this->assertInstanceOf(StandaloneTemplateResponse::class, $result); + $this->assertSame(Http::STATUS_FORBIDDEN, $result->getStatus()); + $this->assertSame('Please use original client', $result->getParams()['message']); + } + + public function testGenerateAppPassworValid(): void { $this->session->method('get') ->willReturnCallback(function ($name) { if ($name === 'client.flow.v2.state.token') { @@ -284,7 +357,7 @@ class ClientFlowLoginV2ControllerTest extends TestCase { $clearedState = false; $clearedLogin = false; $this->session->method('remove') - ->willReturnCallback(function ($name) use (&$clearedLogin, &$clearedState) { + ->willReturnCallback(function ($name) use (&$clearedLogin, &$clearedState): void { if ($name === 'client.flow.v2.state.token') { $clearedState = true; } diff --git a/tests/Core/Controller/ContactsMenuControllerTest.php b/tests/Core/Controller/ContactsMenuControllerTest.php index a702a155860..aa20e6726e2 100644 --- a/tests/Core/Controller/ContactsMenuControllerTest.php +++ b/tests/Core/Controller/ContactsMenuControllerTest.php @@ -1,25 +1,8 @@ <?php /** - * @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Tests\Controller; @@ -30,33 +13,29 @@ use OCP\Contacts\ContactsMenu\IEntry; use OCP\IRequest; use OCP\IUser; use OCP\IUserSession; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class ContactsMenuControllerTest extends TestCase { - - /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */ - private $request; - - /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IUserSession|MockObject */ private $userSession; - /** @var Manager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var Manager|MockObject */ private $contactsManager; - /** @var ContactsMenuController */ - private $controller; + private ContactsMenuController $controller; protected function setUp(): void { parent::setUp(); - $this->request = $this->createMock(IRequest::class); + $request = $this->createMock(IRequest::class); $this->userSession = $this->createMock(IUserSession::class); $this->contactsManager = $this->createMock(Manager::class); - $this->controller = new ContactsMenuController($this->request, $this->userSession, $this->contactsManager); + $this->controller = new ContactsMenuController($request, $this->userSession, $this->contactsManager); } - public function testIndex() { + public function testIndex(): void { $user = $this->createMock(IUser::class); $entries = [ $this->createMock(IEntry::class), @@ -75,7 +54,7 @@ class ContactsMenuControllerTest extends TestCase { $this->assertEquals($entries, $response); } - public function testFindOne() { + public function testFindOne(): void { $user = $this->createMock(IUser::class); $entry = $this->createMock(IEntry::class); $this->userSession->expects($this->once()) @@ -91,7 +70,7 @@ class ContactsMenuControllerTest extends TestCase { $this->assertEquals($entry, $response); } - public function testFindOne404() { + public function testFindOne404(): void { $user = $this->createMock(IUser::class); $this->userSession->expects($this->once()) ->method('getUser') diff --git a/tests/Core/Controller/CssControllerTest.php b/tests/Core/Controller/CssControllerTest.php index d2a791ec1b0..b4764d6ea3a 100644 --- a/tests/Core/Controller/CssControllerTest.php +++ b/tests/Core/Controller/CssControllerTest.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright 2017, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Tests\Core\Controller; @@ -38,7 +22,6 @@ use OCP\IRequest; use Test\TestCase; class CssControllerTest extends TestCase { - /** @var IAppData|\PHPUnit\Framework\MockObject\MockObject */ private $appData; @@ -74,7 +57,7 @@ class CssControllerTest extends TestCase { ); } - public function testNoCssFolderForApp() { + public function testNoCssFolderForApp(): void { $this->appData->method('getFolder') ->with('myapp') ->willThrowException(new NotFoundException()); @@ -85,7 +68,7 @@ class CssControllerTest extends TestCase { } - public function testNoCssFile() { + public function testNoCssFile(): void { $folder = $this->createMock(ISimpleFolder::class); $this->appData->method('getFolder') ->with('myapp') @@ -99,7 +82,7 @@ class CssControllerTest extends TestCase { $this->assertInstanceOf(NotFoundResponse::class, $result); } - public function testGetFile() { + public function testGetFile(): void { $folder = $this->createMock(ISimpleFolder::class); $file = $this->createMock(ISimpleFile::class); $file->method('getName')->willReturn('my name'); @@ -118,13 +101,12 @@ class CssControllerTest extends TestCase { $expires->setTimestamp(1337); $expires->add(new \DateInterval('PT31536000S')); $expected->addHeader('Expires', $expires->format(\DateTime::RFC1123)); - $expected->addHeader('Pragma', 'cache'); $result = $this->controller->getCss('file.css', 'myapp'); $this->assertEquals($expected, $result); } - public function testGetGzipFile() { + public function testGetGzipFile(): void { $folder = $this->createMock(ISimpleFolder::class); $gzipFile = $this->createMock(ISimpleFile::class); $gzipFile->method('getName')->willReturn('my name'); @@ -148,13 +130,12 @@ class CssControllerTest extends TestCase { $expires->setTimestamp(1337); $expires->add(new \DateInterval('PT31536000S')); $expected->addHeader('Expires', $expires->format(\DateTime::RFC1123)); - $expected->addHeader('Pragma', 'cache'); $result = $this->controller->getCss('file.css', 'myapp'); $this->assertEquals($expected, $result); } - public function testGetGzipFileNotFound() { + public function testGetGzipFileNotFound(): void { $folder = $this->createMock(ISimpleFolder::class); $file = $this->createMock(ISimpleFile::class); $file->method('getName')->willReturn('my name'); @@ -183,7 +164,6 @@ class CssControllerTest extends TestCase { $expires->setTimestamp(1337); $expires->add(new \DateInterval('PT31536000S')); $expected->addHeader('Expires', $expires->format(\DateTime::RFC1123)); - $expected->addHeader('Pragma', 'cache'); $result = $this->controller->getCss('file.css', 'myapp'); $this->assertEquals($expected, $result); diff --git a/tests/Core/Controller/GuestAvatarControllerTest.php b/tests/Core/Controller/GuestAvatarControllerTest.php index b5682d2d716..66a83098130 100644 --- a/tests/Core/Controller/GuestAvatarControllerTest.php +++ b/tests/Core/Controller/GuestAvatarControllerTest.php @@ -1,20 +1,24 @@ <?php +/** + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ namespace Core\Controller; use OC\Core\Controller\GuestAvatarController; use OCP\AppFramework\Http\FileDisplayResponse; +use OCP\Files\File; use OCP\Files\SimpleFS\ISimpleFile; use OCP\IAvatar; use OCP\IAvatarManager; -use OCP\ILogger; use OCP\IRequest; +use Psr\Log\LoggerInterface; /** * This class provides tests for the guest avatar controller. */ class GuestAvatarControllerTest extends \Test\TestCase { - /** * @var GuestAvatarController */ @@ -36,12 +40,12 @@ class GuestAvatarControllerTest extends \Test\TestCase { private $avatar; /** - * @var \OCP\Files\File|\PHPUnit\Framework\MockObject\MockObject + * @var File|\PHPUnit\Framework\MockObject\MockObject */ private $file; /** - * @var ILogger|\PHPUnit\Framework\MockObject\MockObject + * @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */ private $logger; @@ -51,7 +55,7 @@ class GuestAvatarControllerTest extends \Test\TestCase { protected function setUp(): void { parent::setUp(); - $this->logger = $this->getMockBuilder(ILogger::class)->getMock(); + $this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); $this->request = $this->getMockBuilder(IRequest::class)->getMock(); $this->avatar = $this->getMockBuilder(IAvatar::class)->getMock(); $this->avatarManager = $this->getMockBuilder(IAvatarManager::class)->getMock(); @@ -69,7 +73,7 @@ class GuestAvatarControllerTest extends \Test\TestCase { /** * Tests getAvatar returns the guest avatar. */ - public function testGetAvatar() { + public function testGetAvatar(): void { $this->avatarManager->expects($this->once()) ->method('getGuestAvatar') ->with('Peter') diff --git a/tests/Core/Controller/JsControllerTest.php b/tests/Core/Controller/JsControllerTest.php index 3f76e19efc9..30bc02e8625 100644 --- a/tests/Core/Controller/JsControllerTest.php +++ b/tests/Core/Controller/JsControllerTest.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright 2017, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Tests\Core\Controller; @@ -38,7 +22,6 @@ use OCP\IRequest; use Test\TestCase; class JsControllerTest extends TestCase { - /** @var IAppData|\PHPUnit\Framework\MockObject\MockObject */ private $appData; @@ -74,7 +57,7 @@ class JsControllerTest extends TestCase { ); } - public function testNoCssFolderForApp() { + public function testNoCssFolderForApp(): void { $this->appData->method('getFolder') ->with('myapp') ->willThrowException(new NotFoundException()); @@ -85,7 +68,7 @@ class JsControllerTest extends TestCase { } - public function testNoCssFile() { + public function testNoCssFile(): void { $folder = $this->createMock(ISimpleFolder::class); $this->appData->method('getFolder') ->with('myapp') @@ -99,7 +82,7 @@ class JsControllerTest extends TestCase { $this->assertInstanceOf(NotFoundResponse::class, $result); } - public function testGetFile() { + public function testGetFile(): void { $folder = $this->createMock(ISimpleFolder::class); $file = $this->createMock(ISimpleFile::class); $file->method('getName')->willReturn('my name'); @@ -118,13 +101,12 @@ class JsControllerTest extends TestCase { $expires->setTimestamp(1337); $expires->add(new \DateInterval('PT31536000S')); $expected->addHeader('Expires', $expires->format(\DateTime::RFC1123)); - $expected->addHeader('Pragma', 'cache'); $result = $this->controller->getJs('file.js', 'myapp'); $this->assertEquals($expected, $result); } - public function testGetGzipFile() { + public function testGetGzipFile(): void { $folder = $this->createMock(ISimpleFolder::class); $gzipFile = $this->createMock(ISimpleFile::class); $gzipFile->method('getName')->willReturn('my name'); @@ -148,13 +130,12 @@ class JsControllerTest extends TestCase { $expires->setTimestamp(1337); $expires->add(new \DateInterval('PT31536000S')); $expected->addHeader('Expires', $expires->format(\DateTime::RFC1123)); - $expected->addHeader('Pragma', 'cache'); $result = $this->controller->getJs('file.js', 'myapp'); $this->assertEquals($expected, $result); } - public function testGetGzipFileNotFound() { + public function testGetGzipFileNotFound(): void { $folder = $this->createMock(ISimpleFolder::class); $file = $this->createMock(ISimpleFile::class); $file->method('getName')->willReturn('my name'); @@ -183,7 +164,6 @@ class JsControllerTest extends TestCase { $expires->setTimestamp(1337); $expires->add(new \DateInterval('PT31536000S')); $expected->addHeader('Expires', $expires->format(\DateTime::RFC1123)); - $expected->addHeader('Pragma', 'cache'); $result = $this->controller->getJs('file.js', 'myapp'); $this->assertEquals($expected, $result); diff --git a/tests/Core/Controller/LoginControllerTest.php b/tests/Core/Controller/LoginControllerTest.php index 30a625a612b..18baaf5b08c 100644 --- a/tests/Core/Controller/LoginControllerTest.php +++ b/tests/Core/Controller/LoginControllerTest.php @@ -1,22 +1,11 @@ <?php + +declare(strict_types=1); + /** - * @author Lukas Reschke <lukas@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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 Tests\Core\Controller; @@ -26,26 +15,26 @@ use OC\Authentication\Login\LoginData; use OC\Authentication\Login\LoginResult; use OC\Authentication\TwoFactorAuth\Manager; use OC\Core\Controller\LoginController; -use OC\Security\Bruteforce\Throttler; use OC\User\Session; +use OCP\App\IAppManager; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\TemplateResponse; +use OCP\AppFramework\Services\IInitialState; use OCP\Defaults; use OCP\IConfig; -use OCP\IInitialStateService; use OCP\IL10N; -use OCP\ILogger; use OCP\IRequest; use OCP\ISession; use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserManager; use OCP\Notification\IManager; +use OCP\Security\Bruteforce\IThrottler; +use OCP\Security\ITrustedDomainHelper; use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class LoginControllerTest extends TestCase { - /** @var LoginController */ private $loginController; @@ -67,23 +56,17 @@ class LoginControllerTest extends TestCase { /** @var IURLGenerator|MockObject */ private $urlGenerator; - /** @var ILogger|MockObject */ - private $logger; - /** @var Manager|MockObject */ private $twoFactorManager; /** @var Defaults|MockObject */ private $defaults; - /** @var Throttler|MockObject */ + /** @var IThrottler|MockObject */ private $throttler; - /** @var LoginChain|MockObject */ - private $chain; - - /** @var IInitialStateService|MockObject */ - private $initialStateService; + /** @var IInitialState|MockObject */ + private $initialState; /** @var \OC\Authentication\WebAuthn\Manager|MockObject */ private $webAuthnManager; @@ -94,6 +77,9 @@ class LoginControllerTest extends TestCase { /** @var IL10N|MockObject */ private $l; + /** @var IAppManager|MockObject */ + private $appManager; + protected function setUp(): void { parent::setUp(); $this->request = $this->createMock(IRequest::class); @@ -102,15 +88,15 @@ class LoginControllerTest extends TestCase { $this->session = $this->createMock(ISession::class); $this->userSession = $this->createMock(Session::class); $this->urlGenerator = $this->createMock(IURLGenerator::class); - $this->logger = $this->createMock(ILogger::class); $this->twoFactorManager = $this->createMock(Manager::class); $this->defaults = $this->createMock(Defaults::class); - $this->throttler = $this->createMock(Throttler::class); - $this->chain = $this->createMock(LoginChain::class); - $this->initialStateService = $this->createMock(IInitialStateService::class); + $this->throttler = $this->createMock(IThrottler::class); + $this->initialState = $this->createMock(IInitialState::class); $this->webAuthnManager = $this->createMock(\OC\Authentication\WebAuthn\Manager::class); $this->notificationManager = $this->createMock(IManager::class); $this->l = $this->createMock(IL10N::class); + $this->appManager = $this->createMock(IAppManager::class); + $this->l->expects($this->any()) ->method('t') ->willReturnCallback(function ($text, $parameters = []) { @@ -120,6 +106,9 @@ class LoginControllerTest extends TestCase { $this->request->method('getRemoteAddress') ->willReturn('1.2.3.4'); + $this->request->method('getHeader') + ->with('Origin') + ->willReturn('domain.example.com'); $this->throttler->method('getDelay') ->with( $this->equalTo('1.2.3.4'), @@ -134,24 +123,26 @@ class LoginControllerTest extends TestCase { $this->session, $this->userSession, $this->urlGenerator, - $this->logger, $this->defaults, $this->throttler, - $this->chain, - $this->initialStateService, + $this->initialState, $this->webAuthnManager, $this->notificationManager, - $this->l + $this->l, + $this->appManager, ); } - public function testLogoutWithoutToken() { + public function testLogoutWithoutToken(): void { $this->request ->expects($this->once()) ->method('getCookie') ->with('nc_token') ->willReturn(null); $this->request + ->method('getServerProtocol') + ->willReturn('https'); + $this->request ->expects($this->once()) ->method('isUserAgent') ->willReturn(false); @@ -169,13 +160,16 @@ class LoginControllerTest extends TestCase { $this->assertEquals($expected, $this->loginController->logout()); } - public function testLogoutNoClearSiteData() { + public function testLogoutNoClearSiteData(): void { $this->request ->expects($this->once()) ->method('getCookie') ->with('nc_token') ->willReturn(null); $this->request + ->method('getServerProtocol') + ->willReturn('https'); + $this->request ->expects($this->once()) ->method('isUserAgent') ->willReturn(true); @@ -189,13 +183,16 @@ class LoginControllerTest extends TestCase { $this->assertEquals($expected, $this->loginController->logout()); } - public function testLogoutWithToken() { + public function testLogoutWithToken(): void { $this->request ->expects($this->once()) ->method('getCookie') ->with('nc_token') ->willReturn('MyLoginToken'); $this->request + ->method('getServerProtocol') + ->willReturn('https'); + $this->request ->expects($this->once()) ->method('isUserAgent') ->willReturn(false); @@ -223,7 +220,7 @@ class LoginControllerTest extends TestCase { $this->assertEquals($expected, $this->loginController->logout()); } - public function testShowLoginFormForLoggedInUsers() { + public function testShowLoginFormForLoggedInUsers(): void { $this->userSession ->expects($this->once()) ->method('isLoggedIn') @@ -234,10 +231,10 @@ class LoginControllerTest extends TestCase { ->willReturn('/default/foo'); $expectedResponse = new RedirectResponse('/default/foo'); - $this->assertEquals($expectedResponse, $this->loginController->showLoginForm('', '', '')); + $this->assertEquals($expectedResponse, $this->loginController->showLoginForm('', '')); } - public function testShowLoginFormWithErrorsInSession() { + public function testShowLoginFormWithErrorsInSession(): void { $this->userSession ->expects($this->once()) ->method('isLoggedIn') @@ -258,67 +255,90 @@ class LoginControllerTest extends TestCase { ], ] ); - $this->initialStateService->expects($this->at(0)) - ->method('provideInitialState') - ->with( - 'core', + + $calls = [ + [ 'loginMessages', [ 'MessageArray1', 'MessageArray2', - 'This community release of Nextcloud is unsupported and instant notifications are unavailable.', - ] - ); - $this->initialStateService->expects($this->at(1)) - ->method('provideInitialState') - ->with( - 'core', + 'This community release of Nextcloud is unsupported and push notifications are limited.', + ], + ], + [ 'loginErrors', [ 'ErrorArray1', 'ErrorArray2', - ] - ); + ], + ], + [ + 'loginUsername', + '', + ] + ]; + $this->initialState->expects($this->exactly(13)) + ->method('provideInitialState') + ->willReturnCallback(function () use (&$calls): void { + $expected = array_shift($calls); + if (!empty($expected)) { + $this->assertEquals($expected, func_get_args()); + } + }); $expectedResponse = new TemplateResponse( 'core', 'login', [ 'alt_login' => [], + 'pageTitle' => 'Login' ], 'guest' ); - $this->assertEquals($expectedResponse, $this->loginController->showLoginForm('', '', '')); + $this->assertEquals($expectedResponse, $this->loginController->showLoginForm('', '')); } - public function testShowLoginFormForFlowAuth() { + public function testShowLoginFormForFlowAuth(): void { $this->userSession ->expects($this->once()) ->method('isLoggedIn') ->willReturn(false); - $this->initialStateService->expects($this->at(4)) - ->method('provideInitialState') - ->with( - 'core', + $calls = [ + [], [], [], + [ + 'loginAutocomplete', + false + ], + [ 'loginRedirectUrl', 'login/flow' - ); + ], + ]; + $this->initialState->expects($this->exactly(14)) + ->method('provideInitialState') + ->willReturnCallback(function () use (&$calls): void { + $expected = array_shift($calls); + if (!empty($expected)) { + $this->assertEquals($expected, func_get_args()); + } + }); $expectedResponse = new TemplateResponse( 'core', 'login', [ 'alt_login' => [], + 'pageTitle' => 'Login' ], 'guest' ); - $this->assertEquals($expectedResponse, $this->loginController->showLoginForm('', 'login/flow', '')); + $this->assertEquals($expectedResponse, $this->loginController->showLoginForm('', 'login/flow')); } /** * @return array */ - public function passwordResetDataProvider() { + public static function passwordResetDataProvider(): array { return [ [ true, @@ -331,21 +351,24 @@ class LoginControllerTest extends TestCase { ]; } - /** - * @dataProvider passwordResetDataProvider - */ + #[\PHPUnit\Framework\Attributes\DataProvider('passwordResetDataProvider')] public function testShowLoginFormWithPasswordResetOption($canChangePassword, - $expectedResult) { + $expectedResult): void { $this->userSession ->expects($this->once()) ->method('isLoggedIn') ->willReturn(false); $this->config - ->expects($this->exactly(2)) + ->expects(self::once()) ->method('getSystemValue') ->willReturnMap([ ['login_form_autocomplete', true, true], - ['lost_password_link', '', false], + ]); + $this->config + ->expects(self::once()) + ->method('getSystemValueString') + ->willReturnMap([ + ['lost_password_link', '', ''], ]); $user = $this->createMock(IUser::class); $user @@ -357,43 +380,55 @@ class LoginControllerTest extends TestCase { ->method('get') ->with('LdapUser') ->willReturn($user); - $this->initialStateService->expects($this->at(2)) - ->method('provideInitialState') - ->with( - 'core', + $calls = [ + [], [], + [ 'loginUsername', 'LdapUser' - ); - $this->initialStateService->expects($this->at(6)) - ->method('provideInitialState') - ->with( - 'core', + ], + [], [], [], + [ 'loginCanResetPassword', $expectedResult - ); + ], + ]; + $this->initialState->expects($this->exactly(13)) + ->method('provideInitialState') + ->willReturnCallback(function () use (&$calls): void { + $expected = array_shift($calls); + if (!empty($expected)) { + $this->assertEquals($expected, func_get_args()); + } + }); $expectedResponse = new TemplateResponse( 'core', 'login', [ 'alt_login' => [], + 'pageTitle' => 'Login' ], 'guest' ); - $this->assertEquals($expectedResponse, $this->loginController->showLoginForm('LdapUser', '', '')); + $this->assertEquals($expectedResponse, $this->loginController->showLoginForm('LdapUser', '')); } - public function testShowLoginFormForUserNamed0() { + public function testShowLoginFormForUserNamed0(): void { $this->userSession ->expects($this->once()) ->method('isLoggedIn') ->willReturn(false); $this->config - ->expects($this->exactly(2)) + ->expects(self::once()) ->method('getSystemValue') ->willReturnMap([ ['login_form_autocomplete', true, true], - ['lost_password_link', '', false], + ]); + $this->config + ->expects(self::once()) + ->method('getSystemValueString') + ->willReturnMap([ + ['lost_password_link', '', ''], ]); $user = $this->createMock(IUser::class); $user->expects($this->once()) @@ -404,44 +439,50 @@ class LoginControllerTest extends TestCase { ->method('get') ->with('0') ->willReturn($user); - $this->initialStateService->expects($this->at(3)) - ->method('provideInitialState') - ->with( - 'core', + $calls = [ + [], [], [], + [ 'loginAutocomplete', true - ); - $this->initialStateService->expects($this->at(5)) - ->method('provideInitialState') - ->with( - 'core', + ], + [], + [ 'loginResetPasswordLink', false - ); - $this->initialStateService->expects($this->at(6)) - ->method('provideInitialState') - ->with( - 'core', + ], + [ 'loginCanResetPassword', false - ); + ], + ]; + $this->initialState->expects($this->exactly(13)) + ->method('provideInitialState') + ->willReturnCallback(function () use (&$calls): void { + $expected = array_shift($calls); + if (!empty($expected)) { + $this->assertEquals($expected, func_get_args()); + } + }); $expectedResponse = new TemplateResponse( 'core', 'login', [ 'alt_login' => [], + 'pageTitle' => 'Login' ], 'guest' ); - $this->assertEquals($expectedResponse, $this->loginController->showLoginForm('0', '', '')); + $this->assertEquals($expectedResponse, $this->loginController->showLoginForm('0', '')); } - public function testLoginWithInvalidCredentials() { + public function testLoginWithInvalidCredentials(): void { $user = 'MyUserName'; $password = 'secret'; $loginPageUrl = '/login?redirect_url=/apps/files'; - + $loginChain = $this->createMock(LoginChain::class); + $trustedDomainHelper = $this->createMock(ITrustedDomainHelper::class); + $trustedDomainHelper->method('isTrustedUrl')->willReturn(true); $this->request ->expects($this->once()) ->method('passesCSRFCheck') @@ -453,7 +494,7 @@ class LoginControllerTest extends TestCase { '/apps/files' ); $loginResult = LoginResult::failure($loginData, LoginController::LOGIN_MSG_INVALIDPASSWORD); - $this->chain->expects($this->once()) + $loginChain->expects($this->once()) ->method('process') ->with($this->equalTo($loginData)) ->willReturn($loginResult); @@ -468,15 +509,17 @@ class LoginControllerTest extends TestCase { $expected = new RedirectResponse($loginPageUrl); $expected->throttle(['user' => 'MyUserName']); - $response = $this->loginController->tryLogin($user, $password, '/apps/files'); + $response = $this->loginController->tryLogin($loginChain, $trustedDomainHelper, $user, $password, '/apps/files'); $this->assertEquals($expected, $response); } - public function testLoginWithValidCredentials() { + public function testLoginWithValidCredentials(): void { $user = 'MyUserName'; $password = 'secret'; - + $loginChain = $this->createMock(LoginChain::class); + $trustedDomainHelper = $this->createMock(ITrustedDomainHelper::class); + $trustedDomainHelper->method('isTrustedUrl')->willReturn(true); $this->request ->expects($this->once()) ->method('passesCSRFCheck') @@ -487,7 +530,7 @@ class LoginControllerTest extends TestCase { $password ); $loginResult = LoginResult::success($loginData); - $this->chain->expects($this->once()) + $loginChain->expects($this->once()) ->method('process') ->with($this->equalTo($loginData)) ->willReturn($loginResult); @@ -497,10 +540,10 @@ class LoginControllerTest extends TestCase { ->willReturn('/default/foo'); $expected = new RedirectResponse('/default/foo'); - $this->assertEquals($expected, $this->loginController->tryLogin($user, $password)); + $this->assertEquals($expected, $this->loginController->tryLogin($loginChain, $trustedDomainHelper, $user, $password)); } - public function testLoginWithoutPassedCsrfCheckAndNotLoggedIn() { + public function testLoginWithoutPassedCsrfCheckAndNotLoggedIn(): void { /** @var IUser|MockObject $user */ $user = $this->createMock(IUser::class); $user->expects($this->any()) @@ -508,12 +551,14 @@ class LoginControllerTest extends TestCase { ->willReturn('jane'); $password = 'secret'; $originalUrl = 'another%20url'; - + $loginChain = $this->createMock(LoginChain::class); + $trustedDomainHelper = $this->createMock(ITrustedDomainHelper::class); + $trustedDomainHelper->method('isTrustedUrl')->willReturn(true); $this->request ->expects($this->once()) ->method('passesCSRFCheck') ->willReturn(false); - $this->userSession->expects($this->once()) + $this->userSession ->method('isLoggedIn') ->with() ->willReturn(false); @@ -521,16 +566,15 @@ class LoginControllerTest extends TestCase { ->method('deleteUserValue'); $this->userSession->expects($this->never()) ->method('createRememberMeToken'); - $this->urlGenerator - ->expects($this->once()) - ->method('linkToDefaultPageUrl') - ->willReturn('/default/foo'); - $expected = new RedirectResponse('/default/foo'); - $this->assertEquals($expected, $this->loginController->tryLogin('Jane', $password, $originalUrl)); + $response = $this->loginController->tryLogin($loginChain, $trustedDomainHelper, 'Jane', $password, $originalUrl); + + $expected = new RedirectResponse(''); + $expected->throttle(['user' => 'Jane']); + $this->assertEquals($expected, $response); } - public function testLoginWithoutPassedCsrfCheckAndLoggedIn() { + public function testLoginWithoutPassedCsrfCheckAndLoggedIn(): void { /** @var IUser|MockObject $user */ $user = $this->createMock(IUser::class); $user->expects($this->any()) @@ -539,12 +583,14 @@ class LoginControllerTest extends TestCase { $password = 'secret'; $originalUrl = 'another url'; $redirectUrl = 'http://localhost/another url'; - + $loginChain = $this->createMock(LoginChain::class); + $trustedDomainHelper = $this->createMock(ITrustedDomainHelper::class); + $trustedDomainHelper->method('isTrustedUrl')->willReturn(true); $this->request ->expects($this->once()) ->method('passesCSRFCheck') ->willReturn(false); - $this->userSession->expects($this->once()) + $this->userSession ->method('isLoggedIn') ->with() ->willReturn(true); @@ -561,15 +607,19 @@ class LoginControllerTest extends TestCase { ->with('remember_login_cookie_lifetime') ->willReturn(1234); + $response = $this->loginController->tryLogin($loginChain, $trustedDomainHelper, 'Jane', $password, $originalUrl); + $expected = new RedirectResponse($redirectUrl); - $this->assertEquals($expected, $this->loginController->tryLogin('Jane', $password, $originalUrl)); + $this->assertEquals($expected, $response); } - public function testLoginWithValidCredentialsAndRedirectUrl() { + public function testLoginWithValidCredentialsAndRedirectUrl(): void { $user = 'MyUserName'; $password = 'secret'; $redirectUrl = 'https://next.cloud/apps/mail'; - + $loginChain = $this->createMock(LoginChain::class); + $trustedDomainHelper = $this->createMock(ITrustedDomainHelper::class); + $trustedDomainHelper->method('isTrustedUrl')->willReturn(true); $this->request ->expects($this->once()) ->method('passesCSRFCheck') @@ -581,7 +631,7 @@ class LoginControllerTest extends TestCase { '/apps/mail' ); $loginResult = LoginResult::success($loginData); - $this->chain->expects($this->once()) + $loginChain->expects($this->once()) ->method('process') ->with($this->equalTo($loginData)) ->willReturn($loginResult); @@ -594,12 +644,15 @@ class LoginControllerTest extends TestCase { ->willReturn($redirectUrl); $expected = new RedirectResponse($redirectUrl); - $response = $this->loginController->tryLogin($user, $password, '/apps/mail'); + $response = $this->loginController->tryLogin($loginChain, $trustedDomainHelper, $user, $password, '/apps/mail'); $this->assertEquals($expected, $response); } - public function testToNotLeakLoginName() { + public function testToNotLeakLoginName(): void { + $loginChain = $this->createMock(LoginChain::class); + $trustedDomainHelper = $this->createMock(ITrustedDomainHelper::class); + $trustedDomainHelper->method('isTrustedUrl')->willReturn(true); $this->request ->expects($this->once()) ->method('passesCSRFCheck') @@ -612,7 +665,7 @@ class LoginControllerTest extends TestCase { '/apps/files' ); $loginResult = LoginResult::failure($loginData, LoginController::LOGIN_MSG_INVALIDPASSWORD); - $this->chain->expects($this->once()) + $loginChain->expects($this->once()) ->method('process') ->with($this->equalTo($loginData)) ->willReturnCallback(function (LoginData $data) use ($loginResult) { @@ -631,6 +684,8 @@ class LoginControllerTest extends TestCase { $expected->throttle(['user' => 'john']); $response = $this->loginController->tryLogin( + $loginChain, + $trustedDomainHelper, 'john@doe.com', 'just wrong', '/apps/files' diff --git a/tests/Core/Controller/LostControllerTest.php b/tests/Core/Controller/LostControllerTest.php index e860c808014..bbb5f2c2e54 100644 --- a/tests/Core/Controller/LostControllerTest.php +++ b/tests/Core/Controller/LostControllerTest.php @@ -1,38 +1,27 @@ <?php + /** - * @author Lukas Reschke <lukas@owncloud.com> - * - * @copyright Copyright (c) 2015, ownCloud, Inc. - * @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: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-only */ namespace Tests\Core\Controller; use OC\Authentication\TwoFactorAuth\Manager; use OC\Core\Controller\LostController; +use OC\Core\Events\BeforePasswordResetEvent; +use OC\Core\Events\PasswordResetEvent; use OC\Mail\Message; +use OC\Security\RateLimiting\Limiter; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\TemplateResponse; +use OCP\AppFramework\Services\IInitialState; use OCP\Defaults; use OCP\Encryption\IEncryptionModule; use OCP\Encryption\IManager; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; -use OCP\IInitialStateService; use OCP\IL10N; -use OCP\ILogger; use OCP\IRequest; use OCP\IURLGenerator; use OCP\IUser; @@ -41,42 +30,47 @@ use OCP\Mail\IEMailTemplate; use OCP\Mail\IMailer; use OCP\Security\VerificationToken\InvalidTokenException; use OCP\Security\VerificationToken\IVerificationToken; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; +use Test\TestCase; /** * Class LostControllerTest * * @package OC\Core\Controller */ -class LostControllerTest extends \Test\TestCase { - - /** @var LostController */ - private $lostController; +class LostControllerTest extends TestCase { + private LostController $lostController; /** @var IUser */ private $existingUser; - /** @var IURLGenerator | \PHPUnit\Framework\MockObject\MockObject */ + /** @var IURLGenerator | MockObject */ private $urlGenerator; /** @var IL10N */ private $l10n; - /** @var IUserManager | \PHPUnit\Framework\MockObject\MockObject */ + /** @var IUserManager | MockObject */ private $userManager; /** @var Defaults */ private $defaults; - /** @var IConfig | \PHPUnit\Framework\MockObject\MockObject */ + /** @var IConfig | MockObject */ private $config; - /** @var IMailer | \PHPUnit\Framework\MockObject\MockObject */ + /** @var IMailer | MockObject */ private $mailer; - /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IManager|MockObject */ private $encryptionManager; - /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IRequest|MockObject */ private $request; - /** @var ILogger|\PHPUnit\Framework\MockObject\MockObject */ + /** @var LoggerInterface|MockObject */ private $logger; - /** @var Manager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var Manager|MockObject */ private $twofactorManager; - /** @var IInitialStateService|\PHPUnit\Framework\MockObject\MockObject */ - private $initialStateService; - /** @var IVerificationToken|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IInitialState|MockObject */ + private $initialState; + /** @var IVerificationToken|MockObject */ private $verificationToken; + /** @var IEventDispatcher|MockObject */ + private $eventDispatcher; + /** @var Limiter|MockObject */ + private $limiter; protected function setUp(): void { parent::setUp(); @@ -110,25 +104,21 @@ class LostControllerTest extends \Test\TestCase { ->willReturnCallback(function ($text, $parameters = []) { return vsprintf($text, $parameters); }); - $this->defaults = $this->getMockBuilder('\OCP\Defaults') - ->disableOriginalConstructor()->getMock(); - $this->userManager = $this->getMockBuilder(IUserManager::class) - ->disableOriginalConstructor()->getMock(); - $this->urlGenerator = $this->getMockBuilder(IURLGenerator::class) - ->disableOriginalConstructor()->getMock(); - $this->mailer = $this->getMockBuilder('\OCP\Mail\IMailer') - ->disableOriginalConstructor()->getMock(); - $this->request = $this->getMockBuilder(IRequest::class) - ->disableOriginalConstructor()->getMock(); - $this->encryptionManager = $this->getMockBuilder(IManager::class) - ->disableOriginalConstructor()->getMock(); + $this->defaults = $this->createMock(Defaults::class); + $this->userManager = $this->createMock(IUserManager::class); + $this->urlGenerator = $this->createMock(IURLGenerator::class); + $this->mailer = $this->createMock(IMailer::class); + $this->request = $this->createMock(IRequest::class); + $this->encryptionManager = $this->createMock(IManager::class); $this->encryptionManager->expects($this->any()) ->method('isEnabled') ->willReturn(true); - $this->logger = $this->createMock(ILogger::class); + $this->logger = $this->createMock(LoggerInterface::class); $this->twofactorManager = $this->createMock(Manager::class); - $this->initialStateService = $this->createMock(IInitialStateService::class); + $this->initialState = $this->createMock(IInitialState::class); $this->verificationToken = $this->createMock(IVerificationToken::class); + $this->eventDispatcher = $this->createMock(IEventDispatcher::class); + $this->limiter = $this->createMock(Limiter::class); $this->lostController = new LostController( 'Core', $this->request, @@ -142,12 +132,14 @@ class LostControllerTest extends \Test\TestCase { $this->mailer, $this->logger, $this->twofactorManager, - $this->initialStateService, - $this->verificationToken + $this->initialState, + $this->verificationToken, + $this->eventDispatcher, + $this->limiter ); } - public function testResetFormTokenError() { + public function testResetFormTokenError(): void { $this->userManager->method('get') ->with('ValidTokenUser') ->willReturn($this->existingUser); @@ -165,16 +157,34 @@ class LostControllerTest extends \Test\TestCase { ] ], 'guest'); + $expectedResponse->throttle(); $this->assertEquals($expectedResponse, $response); } - public function testResetFormValidToken() { + public function testResetFormValidToken(): void { $this->userManager->method('get') ->with('ValidTokenUser') ->willReturn($this->existingUser); $this->verificationToken->expects($this->once()) ->method('check') ->with('MySecretToken', $this->existingUser, 'lostpassword', 'test@example.com'); + $this->urlGenerator + ->expects($this->once()) + ->method('linkToRouteAbsolute') + ->with('core.lost.setPassword', ['userId' => 'ValidTokenUser', 'token' => 'MySecretToken']) + ->willReturn('https://example.tld/index.php/lostpassword/set/sometoken/someuser'); + + $calls = [ + ['resetPasswordUser', 'ValidTokenUser'], + ['resetPasswordTarget', 'https://example.tld/index.php/lostpassword/set/sometoken/someuser'], + ]; + $this->initialState + ->expects($this->exactly(2)) + ->method('provideInitialState') + ->willReturnCallback(function () use (&$calls): void { + $expected = array_shift($calls); + $this->assertEquals($expected, func_get_args()); + }); $response = $this->lostController->resetform('MySecretToken', 'ValidTokenUser'); $expectedResponse = new TemplateResponse('core', @@ -184,7 +194,7 @@ class LostControllerTest extends \Test\TestCase { $this->assertEquals($expectedResponse, $response); } - public function testEmailUnsuccessful() { + public function testEmailUnsuccessful(): void { $existingUser = 'ExistingUser'; $nonExistingUser = 'NonExistingUser'; $this->userManager @@ -196,7 +206,7 @@ class LostControllerTest extends \Test\TestCase { ]); $this->logger->expects($this->exactly(0)) - ->method('logException'); + ->method('error'); $this->logger->expects($this->exactly(2)) ->method('warning'); @@ -226,12 +236,12 @@ class LostControllerTest extends \Test\TestCase { $this->assertEquals($expectedResponse, $response); } - public function testEmailSuccessful() { + public function testEmailSuccessful(): void { $this->userManager - ->expects($this->any()) - ->method('get') - ->with('ExistingUser') - ->willReturn($this->existingUser); + ->expects($this->any()) + ->method('get') + ->with('ExistingUser') + ->willReturn($this->existingUser); $this->verificationToken->expects($this->once()) ->method('create') ->willReturn('ThisIsMaybeANotSoSecretToken!'); @@ -243,11 +253,11 @@ class LostControllerTest extends \Test\TestCase { $message = $this->getMockBuilder('\OC\Mail\Message') ->disableOriginalConstructor()->getMock(); $message - ->expects($this->at(0)) + ->expects($this->once()) ->method('setTo') ->with(['test@example.com' => 'Existing User']); $message - ->expects($this->at(1)) + ->expects($this->once()) ->method('setFrom') ->with(['lostpassword-noreply@localhost' => null]); @@ -260,20 +270,20 @@ class LostControllerTest extends \Test\TestCase { ->willReturn('text body'); $message - ->expects($this->at(2)) + ->expects($this->once()) ->method('useTemplate') ->with($emailTemplate); $this->mailer - ->expects($this->at(0)) + ->expects($this->once()) ->method('createEMailTemplate') ->willReturn($emailTemplate); $this->mailer - ->expects($this->at(1)) + ->expects($this->once()) ->method('createMessage') ->willReturn($message); $this->mailer - ->expects($this->at(2)) + ->expects($this->once()) ->method('send') ->with($message); @@ -283,17 +293,17 @@ class LostControllerTest extends \Test\TestCase { $this->assertEquals($expectedResponse, $response); } - public function testEmailWithMailSuccessful() { + public function testEmailWithMailSuccessful(): void { $this->userManager - ->expects($this->any()) - ->method('get') - ->with('test@example.com') - ->willReturn(null); + ->expects($this->any()) + ->method('get') + ->with('test@example.com') + ->willReturn(null); $this->userManager - ->expects($this->any()) - ->method('getByEmail') - ->with('test@example.com') - ->willReturn([$this->existingUser]); + ->expects($this->any()) + ->method('getByEmail') + ->with('test@example.com') + ->willReturn([$this->existingUser]); $this->verificationToken->expects($this->once()) ->method('create') ->willReturn('ThisIsMaybeANotSoSecretToken!'); @@ -305,11 +315,11 @@ class LostControllerTest extends \Test\TestCase { $message = $this->getMockBuilder('\OC\Mail\Message') ->disableOriginalConstructor()->getMock(); $message - ->expects($this->at(0)) + ->expects($this->once()) ->method('setTo') ->with(['test@example.com' => 'Existing User']); $message - ->expects($this->at(1)) + ->expects($this->once()) ->method('setFrom') ->with(['lostpassword-noreply@localhost' => null]); @@ -322,20 +332,20 @@ class LostControllerTest extends \Test\TestCase { ->willReturn('text body'); $message - ->expects($this->at(2)) + ->expects($this->once()) ->method('useTemplate') ->with($emailTemplate); $this->mailer - ->expects($this->at(0)) + ->expects($this->once()) ->method('createEMailTemplate') ->willReturn($emailTemplate); $this->mailer - ->expects($this->at(1)) + ->expects($this->once()) ->method('createMessage') ->willReturn($message); $this->mailer - ->expects($this->at(2)) + ->expects($this->once()) ->method('send') ->with($message); @@ -345,12 +355,12 @@ class LostControllerTest extends \Test\TestCase { $this->assertEquals($expectedResponse, $response); } - public function testEmailCantSendException() { + public function testEmailCantSendException(): void { $this->userManager - ->expects($this->any()) - ->method('get') - ->with('ExistingUser') - ->willReturn($this->existingUser); + ->expects($this->any()) + ->method('get') + ->with('ExistingUser') + ->willReturn($this->existingUser); $this->verificationToken->expects($this->once()) ->method('create') ->willReturn('ThisIsMaybeANotSoSecretToken!'); @@ -361,11 +371,11 @@ class LostControllerTest extends \Test\TestCase { ->willReturn('https://example.tld/index.php/lostpassword/'); $message = $this->createMock(Message::class); $message - ->expects($this->at(0)) + ->expects($this->once()) ->method('setTo') ->with(['test@example.com' => 'Existing User']); $message - ->expects($this->at(1)) + ->expects($this->once()) ->method('setFrom') ->with(['lostpassword-noreply@localhost' => null]); @@ -378,26 +388,26 @@ class LostControllerTest extends \Test\TestCase { ->willReturn('text body'); $message - ->expects($this->at(2)) + ->expects($this->once()) ->method('useTemplate') ->with($emailTemplate); $this->mailer - ->expects($this->at(0)) + ->expects($this->once()) ->method('createEMailTemplate') ->willReturn($emailTemplate); $this->mailer - ->expects($this->at(1)) + ->expects($this->once()) ->method('createMessage') ->willReturn($message); $this->mailer - ->expects($this->at(2)) + ->expects($this->once()) ->method('send') ->with($message) - ->will($this->throwException(new \Exception())); + ->willThrowException(new \Exception()); $this->logger->expects($this->exactly(1)) - ->method('logException'); + ->method('error'); $response = $this->lostController->email('ExistingUser'); $expectedResponse = new JSONResponse(['status' => 'success']); @@ -405,7 +415,7 @@ class LostControllerTest extends \Test\TestCase { $this->assertEquals($expectedResponse, $response); } - public function testSetPasswordUnsuccessful() { + public function testSetPasswordUnsuccessful(): void { $this->config->method('getUserValue') ->with('ValidTokenUser', 'core', 'lostpassword', null) ->willReturn('encryptedData'); @@ -418,15 +428,20 @@ class LostControllerTest extends \Test\TestCase { $this->userManager->method('get') ->with('ValidTokenUser') ->willReturn($this->existingUser); + $beforePasswordResetEvent = new BeforePasswordResetEvent($this->existingUser, 'NewPassword'); + $this->eventDispatcher + ->expects($this->once()) + ->method('dispatchTyped') + ->with($beforePasswordResetEvent); $this->config->expects($this->never()) ->method('deleteUserValue'); $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser', 'NewPassword', true); $expectedResponse = ['status' => 'error', 'msg' => '']; - $this->assertSame($expectedResponse, $response); + $this->assertSame($expectedResponse, $response->getData()); } - public function testSetPasswordSuccessful() { + public function testSetPasswordSuccessful(): void { $this->config->method('getUserValue') ->with('ValidTokenUser', 'core', 'lostpassword', null) ->willReturn('encryptedData'); @@ -439,16 +454,29 @@ class LostControllerTest extends \Test\TestCase { $this->userManager->method('get') ->with('ValidTokenUser') ->willReturn($this->existingUser); + + $calls = [ + [new BeforePasswordResetEvent($this->existingUser, 'NewPassword')], + [new PasswordResetEvent($this->existingUser, 'NewPassword')], + ]; + $this->eventDispatcher + ->expects($this->exactly(2)) + ->method('dispatchTyped') + ->willReturnCallback(function () use (&$calls): void { + $expected = array_shift($calls); + $this->assertEquals($expected, func_get_args()); + }); + $this->config->expects($this->once()) ->method('deleteUserValue') ->with('ValidTokenUser', 'core', 'lostpassword'); $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser', 'NewPassword', true); $expectedResponse = ['user' => 'ValidTokenUser', 'status' => 'success']; - $this->assertSame($expectedResponse, $response); + $this->assertSame($expectedResponse, $response->getData()); } - public function testSetPasswordExpiredToken() { + public function testSetPasswordExpiredToken(): void { $this->config->method('getUserValue') ->with('ValidTokenUser', 'core', 'lostpassword', null) ->willReturn('encryptedData'); @@ -464,10 +492,10 @@ class LostControllerTest extends \Test\TestCase { 'status' => 'error', 'msg' => 'Could not reset password because the token is expired', ]; - $this->assertSame($expectedResponse, $response); + $this->assertSame($expectedResponse, $response->getData()); } - public function testSetPasswordInvalidDataInDb() { + public function testSetPasswordInvalidDataInDb(): void { $this->config->method('getUserValue') ->with('ValidTokenUser', 'core', 'lostpassword', null) ->willReturn('invalidEncryptedData'); @@ -484,10 +512,10 @@ class LostControllerTest extends \Test\TestCase { 'status' => 'error', 'msg' => 'Could not reset password because the token is invalid', ]; - $this->assertSame($expectedResponse, $response); + $this->assertSame($expectedResponse, $response->getData()); } - public function testIsSetPasswordWithoutTokenFailing() { + public function testIsSetPasswordWithoutTokenFailing(): void { $this->config->method('getUserValue') ->with('ValidTokenUser', 'core', 'lostpassword', null) ->willReturn('aValidtoken'); @@ -503,10 +531,10 @@ class LostControllerTest extends \Test\TestCase { 'status' => 'error', 'msg' => 'Could not reset password because the token is invalid' ]; - $this->assertSame($expectedResponse, $response); + $this->assertSame($expectedResponse, $response->getData()); } - public function testSetPasswordForDisabledUser() { + public function testSetPasswordForDisabledUser(): void { $user = $this->createMock(IUser::class); $user->expects($this->any()) ->method('isEnabled') @@ -533,10 +561,10 @@ class LostControllerTest extends \Test\TestCase { 'status' => 'error', 'msg' => 'Could not reset password because the token is invalid' ]; - $this->assertSame($expectedResponse, $response); + $this->assertSame($expectedResponse, $response->getData()); } - public function testSendEmailNoEmail() { + public function testSendEmailNoEmail(): void { $user = $this->createMock(IUser::class); $user->expects($this->any()) ->method('isEnabled') @@ -549,7 +577,7 @@ class LostControllerTest extends \Test\TestCase { ->willReturn($user); $this->logger->expects($this->exactly(0)) - ->method('logException'); + ->method('error'); $this->logger->expects($this->once()) ->method('warning'); @@ -559,8 +587,8 @@ class LostControllerTest extends \Test\TestCase { $this->assertEquals($expectedResponse, $response); } - public function testSetPasswordEncryptionDontProceedPerUserKey() { - /** @var IEncryptionModule|\PHPUnit\Framework\MockObject\MockObject $encryptionModule */ + public function testSetPasswordEncryptionDontProceedPerUserKey(): void { + /** @var IEncryptionModule|MockObject $encryptionModule */ $encryptionModule = $this->createMock(IEncryptionModule::class); $encryptionModule->expects($this->once())->method('needDetailedAccessList')->willReturn(true); $this->encryptionManager->expects($this->once())->method('getEncryptionModules') @@ -569,10 +597,10 @@ class LostControllerTest extends \Test\TestCase { }]]); $response = $this->lostController->setPassword('myToken', 'user', 'newpass', false); $expectedResponse = ['status' => 'error', 'msg' => '', 'encryption' => true]; - $this->assertSame($expectedResponse, $response); + $this->assertSame($expectedResponse, $response->getData()); } - public function testSetPasswordDontProceedMasterKey() { + public function testSetPasswordDontProceedMasterKey(): void { $encryptionModule = $this->createMock(IEncryptionModule::class); $encryptionModule->expects($this->once())->method('needDetailedAccessList')->willReturn(false); $this->encryptionManager->expects($this->once())->method('getEncryptionModules') @@ -597,10 +625,10 @@ class LostControllerTest extends \Test\TestCase { $response = $this->lostController->setPassword('TheOnlyAndOnlyOneTokenToResetThePassword', 'ValidTokenUser', 'NewPassword', false); $expectedResponse = ['user' => 'ValidTokenUser', 'status' => 'success']; - $this->assertSame($expectedResponse, $response); + $this->assertSame($expectedResponse, $response->getData()); } - public function testTwoUsersWithSameEmail() { + public function testTwoUsersWithSameEmail(): void { $user1 = $this->createMock(IUser::class); $user1->expects($this->any()) ->method('getEMailAddress') @@ -632,7 +660,7 @@ class LostControllerTest extends \Test\TestCase { ->willReturn([$user1, $user2]); $this->logger->expects($this->exactly(0)) - ->method('logException'); + ->method('error'); $this->logger->expects($this->once()) ->method('warning'); @@ -651,18 +679,18 @@ class LostControllerTest extends \Test\TestCase { /** * @return array */ - public function dataTwoUserswithSameEmailOneDisabled(): array { + public static function dataTwoUsersWithSameEmailOneDisabled(): array { return [ - ['user1' => true, 'user2' => false], - ['user1' => false, 'user2' => true] + ['userEnabled1' => true, 'userEnabled2' => false], + ['userEnabled1' => false, 'userEnabled2' => true] ]; } /** - * @dataProvider dataTwoUserswithSameEmailOneDisabled * @param bool $userEnabled1 * @param bool $userEnabled2 */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataTwoUsersWithSameEmailOneDisabled')] public function testTwoUsersWithSameEmailOneDisabled(bool $userEnabled1, bool $userEnabled2): void { $user1 = $this->createMock(IUser::class); $user1->method('getEMailAddress') @@ -691,4 +719,38 @@ class LostControllerTest extends \Test\TestCase { $result = self::invokePrivate($this->lostController, 'findUserByIdOrMail', ['test@example.com']); $this->assertInstanceOf(IUser::class, $result); } + + public function testTrimEmailInput(): void { + $this->userManager + ->expects($this->once()) + ->method('getByEmail') + ->with('test@example.com') + ->willReturn([$this->existingUser]); + + $this->mailer + ->expects($this->once()) + ->method('send'); + + $response = $this->lostController->email(' test@example.com '); + $expectedResponse = new JSONResponse(['status' => 'success']); + $expectedResponse->throttle(); + $this->assertEquals($expectedResponse, $response); + } + + public function testUsernameInput(): void { + $this->userManager + ->expects($this->once()) + ->method('get') + ->with('ExistingUser') + ->willReturn($this->existingUser); + + $this->mailer + ->expects($this->once()) + ->method('send'); + + $response = $this->lostController->email(' ExistingUser '); + $expectedResponse = new JSONResponse(['status' => 'success']); + $expectedResponse->throttle(); + $this->assertEquals($expectedResponse, $response); + } } diff --git a/tests/Core/Controller/NavigationControllerTest.php b/tests/Core/Controller/NavigationControllerTest.php index e98d0e8ed40..d00976f18ec 100644 --- a/tests/Core/Controller/NavigationControllerTest.php +++ b/tests/Core/Controller/NavigationControllerTest.php @@ -1,30 +1,13 @@ <?php + /** - * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net> - * - * @author Julius Härtl <jus@bitgrid.net> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Tests\Core\Controller; use OC\Core\Controller\NavigationController; -use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\INavigationManager; use OCP\IRequest; @@ -32,7 +15,6 @@ use OCP\IURLGenerator; use Test\TestCase; class NavigationControllerTest extends TestCase { - /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */ private $request; @@ -60,13 +42,14 @@ class NavigationControllerTest extends TestCase { ); } - public function dataGetNavigation() { + public static function dataGetNavigation(): array { return [ - [false], [true] + [false], + [true], ]; } - /** @dataProvider dataGetNavigation */ - public function testGetAppNavigation($absolute) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGetNavigation')] + public function testGetAppNavigation(bool $absolute): void { $this->navigationManager->expects($this->once()) ->method('getAll') ->with('link') @@ -75,14 +58,12 @@ class NavigationControllerTest extends TestCase { $this->urlGenerator->expects($this->any()) ->method('getBaseURL') ->willReturn('http://localhost/'); - $this->urlGenerator->expects($this->at(1)) + $this->urlGenerator->expects($this->exactly(2)) ->method('getAbsoluteURL') - ->with('/index.php/apps/files') - ->willReturn('http://localhost/index.php/apps/files'); - $this->urlGenerator->expects($this->at(3)) - ->method('getAbsoluteURL') - ->with('icon') - ->willReturn('http://localhost/icon'); + ->willReturnMap([ + ['/index.php/apps/files', 'http://localhost/index.php/apps/files'], + ['icon', 'http://localhost/icon'], + ]); $actual = $this->controller->getAppsNavigation($absolute); $this->assertInstanceOf(DataResponse::class, $actual); $this->assertEquals('http://localhost/index.php/apps/files', $actual->getData()[0]['href']); @@ -95,8 +76,8 @@ class NavigationControllerTest extends TestCase { } } - /** @dataProvider dataGetNavigation */ - public function testGetSettingsNavigation($absolute) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGetNavigation')] + public function testGetSettingsNavigation(bool $absolute): void { $this->navigationManager->expects($this->once()) ->method('getAll') ->with('settings') @@ -105,14 +86,12 @@ class NavigationControllerTest extends TestCase { $this->urlGenerator->expects($this->any()) ->method('getBaseURL') ->willReturn('http://localhost/'); - $this->urlGenerator->expects($this->at(1)) - ->method('getAbsoluteURL') - ->with('/index.php/settings/user') - ->willReturn('http://localhost/index.php/settings/user'); - $this->urlGenerator->expects($this->at(3)) + $this->urlGenerator->expects($this->exactly(2)) ->method('getAbsoluteURL') - ->with('/core/img/settings.svg') - ->willReturn('http://localhost/core/img/settings.svg'); + ->willReturnMap([ + ['/index.php/settings/user', 'http://localhost/index.php/settings/user'], + ['/core/img/settings.svg', 'http://localhost/core/img/settings.svg'] + ]); $actual = $this->controller->getSettingsNavigation($absolute); $this->assertInstanceOf(DataResponse::class, $actual); $this->assertEquals('http://localhost/index.php/settings/user', $actual->getData()[0]['href']); @@ -125,33 +104,35 @@ class NavigationControllerTest extends TestCase { } } - public function testGetAppNavigationEtagMatch() { - $navigation = [ ['id' => 'files', 'href' => '/index.php/apps/files', 'icon' => 'icon' ] ]; - $this->request->expects($this->once()) - ->method('getHeader') - ->with('If-None-Match') - ->willReturn(md5(json_encode($navigation))); - $this->navigationManager->expects($this->once()) + public function testEtagIgnoresLogout(): void { + $navigation1 = [ + ['id' => 'files', 'href' => '/index.php/apps/files', 'icon' => 'icon' ], + ['id' => 'logout', 'href' => '/index.php/logout?requesttoken=abcd', 'icon' => 'icon' ], + ]; + $navigation2 = [ + ['id' => 'files', 'href' => '/index.php/apps/files', 'icon' => 'icon' ], + ['id' => 'logout', 'href' => '/index.php/logout?requesttoken=1234', 'icon' => 'icon' ], + ]; + $navigation3 = [ + ['id' => 'files', 'href' => '/index.php/apps/files/test', 'icon' => 'icon' ], + ['id' => 'logout', 'href' => '/index.php/logout?requesttoken=1234', 'icon' => 'icon' ], + ]; + $this->navigationManager->expects($this->exactly(3)) ->method('getAll') ->with('link') - ->willReturn($navigation); - $actual = $this->controller->getAppsNavigation(); - $this->assertInstanceOf(DataResponse::class, $actual); - $this->assertEquals(Http::STATUS_NOT_MODIFIED, $actual->getStatus()); - } + ->willReturnOnConsecutiveCalls( + $navigation1, + $navigation2, + $navigation3, + ); - public function testGetSettingsNavigationEtagMatch() { - $navigation = [ ['id' => 'logout', 'href' => '/index.php/apps/files', 'icon' => 'icon' ] ]; - $this->request->expects($this->once()) - ->method('getHeader') - ->with('If-None-Match') - ->willReturn(md5(json_encode([ ['id' => 'logout', 'href' => 'logout', 'icon' => 'icon' ] ]))); - $this->navigationManager->expects($this->once()) - ->method('getAll') - ->with('settings') - ->willReturn($navigation); - $actual = $this->controller->getSettingsNavigation(); - $this->assertInstanceOf(DataResponse::class, $actual); - $this->assertEquals(Http::STATUS_NOT_MODIFIED, $actual->getStatus()); + // Changes in the logout url should not change the ETag + $request1 = $this->controller->getAppsNavigation(); + $request2 = $this->controller->getAppsNavigation(); + $this->assertEquals($request1->getETag(), $request2->getETag()); + + // Changes in non-logout urls should result in a different ETag + $request3 = $this->controller->getAppsNavigation(); + $this->assertNotEquals($request2->getETag(), $request3->getETag()); } } diff --git a/tests/Core/Controller/OCSControllerTest.php b/tests/Core/Controller/OCSControllerTest.php index 61ed4a50d62..bd7e26d5e8f 100644 --- a/tests/Core/Controller/OCSControllerTest.php +++ b/tests/Core/Controller/OCSControllerTest.php @@ -1,24 +1,9 @@ <?php + /** - * @copyright 2016, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * 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-or-later */ namespace OC\Core\Controller; @@ -31,6 +16,8 @@ use OCP\IRequest; use OCP\IUser; use OCP\IUserManager; use OCP\IUserSession; +use OCP\Server; +use OCP\ServerVersion; use Test\TestCase; class OCSControllerTest extends TestCase { @@ -44,6 +31,8 @@ class OCSControllerTest extends TestCase { private $userManager; /** @var Manager|\PHPUnit\Framework\MockObject\MockObject */ private $keyManager; + /** @var ServerVersion|\PHPUnit\Framework\MockObject\MockObject */ + private $serverVersion; /** @var OCSController */ private $controller; @@ -55,6 +44,7 @@ class OCSControllerTest extends TestCase { $this->userSession = $this->createMock(IUserSession::class); $this->userManager = $this->createMock(IUserManager::class); $this->keyManager = $this->createMock(Manager::class); + $serverVersion = Server::get(ServerVersion::class); $this->controller = new OCSController( 'core', @@ -62,7 +52,8 @@ class OCSControllerTest extends TestCase { $this->capabilitiesManager, $this->userSession, $this->userManager, - $this->keyManager + $this->keyManager, + $serverVersion ); } @@ -84,18 +75,19 @@ class OCSControllerTest extends TestCase { return new DataResponse($data); } - public function testGetCapabilities() { + public function testGetCapabilities(): void { $this->userSession->expects($this->once()) ->method('isLoggedIn') ->willReturn(true); - [$major, $minor, $micro] = \OCP\Util::getVersion(); + + $serverVersion = Server::get(ServerVersion::class); $result = []; $result['version'] = [ - 'major' => $major, - 'minor' => $minor, - 'micro' => $micro, - 'string' => \OC_Util::getVersionString(), + 'major' => $serverVersion->getMajorVersion(), + 'minor' => $serverVersion->getMinorVersion(), + 'micro' => $serverVersion->getPatchVersion(), + 'string' => $serverVersion->getVersionString(), 'edition' => '', 'extendedSupport' => false ]; @@ -117,18 +109,18 @@ class OCSControllerTest extends TestCase { $this->assertEquals($expected, $this->controller->getCapabilities()); } - public function testGetCapabilitiesPublic() { + public function testGetCapabilitiesPublic(): void { $this->userSession->expects($this->once()) ->method('isLoggedIn') ->willReturn(false); - [$major, $minor, $micro] = \OCP\Util::getVersion(); + $serverVersion = Server::get(ServerVersion::class); $result = []; $result['version'] = [ - 'major' => $major, - 'minor' => $minor, - 'micro' => $micro, - 'string' => \OC_Util::getVersionString(), + 'major' => $serverVersion->getMajorVersion(), + 'minor' => $serverVersion->getMinorVersion(), + 'micro' => $serverVersion->getPatchVersion(), + 'string' => $serverVersion->getVersionString(), 'edition' => '', 'extendedSupport' => false ]; @@ -151,7 +143,7 @@ class OCSControllerTest extends TestCase { $this->assertEquals($expected, $this->controller->getCapabilities()); } - public function testPersonCheckValid() { + public function testPersonCheckValid(): void { $this->userManager->method('checkPassword') ->with( $this->equalTo('user'), @@ -166,7 +158,7 @@ class OCSControllerTest extends TestCase { $this->assertEquals($expected, $this->controller->personCheck('user', 'pass')); } - public function testPersonInvalid() { + public function testPersonInvalid(): void { $this->userManager->method('checkPassword') ->with( $this->equalTo('user'), @@ -178,7 +170,7 @@ class OCSControllerTest extends TestCase { $this->assertEquals($expected, $this->controller->personCheck('user', 'wrongpass')); } - public function testPersonNoLogin() { + public function testPersonNoLogin(): void { $this->userManager->method('checkPassword') ->with( $this->equalTo('user'), @@ -189,18 +181,18 @@ class OCSControllerTest extends TestCase { $this->assertEquals($expected, $this->controller->personCheck('', '')); } - public function testGetIdentityProofWithNotExistingUser() { + public function testGetIdentityProofWithNotExistingUser(): void { $this->userManager ->expects($this->once()) ->method('get') ->with('NotExistingUser') ->willReturn(null); - $expected = new DataResponse(['User not found'], 404); + $expected = new DataResponse(['Account not found'], 404); $this->assertEquals($expected, $this->controller->getIdentityProof('NotExistingUser')); } - public function testGetIdentityProof() { + public function testGetIdentityProof(): void { $user = $this->createMock(IUser::class); $key = $this->createMock(Key::class); $this->userManager diff --git a/tests/Core/Controller/PreviewControllerTest.php b/tests/Core/Controller/PreviewControllerTest.php index 704ddade7a4..5a6cd1fba0a 100644 --- a/tests/Core/Controller/PreviewControllerTest.php +++ b/tests/Core/Controller/PreviewControllerTest.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Tests\Core\Controller; @@ -26,68 +10,68 @@ namespace Tests\Core\Controller; use OC\Core\Controller\PreviewController; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; -use OCP\AppFramework\Utility\ITimeFactory; use OCP\Files\File; use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; use OCP\Files\SimpleFS\ISimpleFile; +use OCP\Files\Storage\ISharedStorage; +use OCP\Files\Storage\IStorage; use OCP\IPreview; use OCP\IRequest; +use OCP\Preview\IMimeIconProvider; +use OCP\Share\IShare; +use PHPUnit\Framework\MockObject\MockObject; class PreviewControllerTest extends \Test\TestCase { - /** @var IRootFolder|\PHPUnit\Framework\MockObject\MockObject */ - private $rootFolder; - - /** @var string */ - private $userId; + private string $userId; + private PreviewController $controller; - /** @var IPreview|\PHPUnit\Framework\MockObject\MockObject */ - private $previewManager; - - /** @var PreviewController|\PHPUnit\Framework\MockObject\MockObject */ - private $controller; + private IRootFolder&MockObject $rootFolder; + private IPreview&MockObject $previewManager; + private IRequest&MockObject $request; protected function setUp(): void { parent::setUp(); - $this->rootFolder = $this->createMock(IRootFolder::class); $this->userId = 'user'; + $this->rootFolder = $this->createMock(IRootFolder::class); $this->previewManager = $this->createMock(IPreview::class); + $this->request = $this->createMock(IRequest::class); $this->controller = new PreviewController( 'core', - $this->createMock(IRequest::class), + $this->request, $this->previewManager, $this->rootFolder, $this->userId, - $this->createMock(ITimeFactory::class) + $this->createMock(IMimeIconProvider::class) ); } - public function testInvalidFile() { + public function testInvalidFile(): void { $res = $this->controller->getPreview(''); $expected = new DataResponse([], Http::STATUS_BAD_REQUEST); $this->assertEquals($expected, $res); } - public function testInvalidWidth() { + public function testInvalidWidth(): void { $res = $this->controller->getPreview('file', 0); $expected = new DataResponse([], Http::STATUS_BAD_REQUEST); $this->assertEquals($expected, $res); } - public function testInvalidHeight() { + public function testInvalidHeight(): void { $res = $this->controller->getPreview('file', 10, 0); $expected = new DataResponse([], Http::STATUS_BAD_REQUEST); $this->assertEquals($expected, $res); } - public function testFileNotFound() { + public function testFileNotFound(): void { $userFolder = $this->createMock(Folder::class); $this->rootFolder->method('getUserFolder') ->with($this->equalTo($this->userId)) @@ -103,7 +87,7 @@ class PreviewControllerTest extends \Test\TestCase { $this->assertEquals($expected, $res); } - public function testNotAFile() { + public function testNotAFile(): void { $userFolder = $this->createMock(Folder::class); $this->rootFolder->method('getUserFolder') ->with($this->equalTo($this->userId)) @@ -120,7 +104,7 @@ class PreviewControllerTest extends \Test\TestCase { $this->assertEquals($expected, $res); } - public function testNoPreviewAndNoIcon() { + public function testNoPreviewAndNoIcon(): void { $userFolder = $this->createMock(Folder::class); $this->rootFolder->method('getUserFolder') ->with($this->equalTo($this->userId)) @@ -141,7 +125,38 @@ class PreviewControllerTest extends \Test\TestCase { $this->assertEquals($expected, $res); } - public function testForbiddenFile() { + public function testNoPreview() { + $userFolder = $this->createMock(Folder::class); + $this->rootFolder->method('getUserFolder') + ->with($this->equalTo($this->userId)) + ->willReturn($userFolder); + + $file = $this->createMock(File::class); + $userFolder->method('get') + ->with($this->equalTo('file')) + ->willReturn($file); + + $storage = $this->createMock(IStorage::class); + $file->method('getStorage') + ->willReturn($storage); + + $this->previewManager->method('isAvailable') + ->with($this->equalTo($file)) + ->willReturn(true); + + $file->method('isReadable') + ->willReturn(true); + + $this->previewManager->method('getPreview') + ->with($this->equalTo($file), 10, 10, false, $this->equalTo('myMode')) + ->willThrowException(new NotFoundException()); + + $res = $this->controller->getPreview('file', 10, 10, true, true, 'myMode'); + $expected = new DataResponse([], Http::STATUS_NOT_FOUND); + + $this->assertEquals($expected, $res); + } + public function testFileWithoutReadPermission() { $userFolder = $this->createMock(Folder::class); $this->rootFolder->method('getUserFolder') ->with($this->equalTo($this->userId)) @@ -165,13 +180,54 @@ class PreviewControllerTest extends \Test\TestCase { $this->assertEquals($expected, $res); } - public function testNoPreview() { + public function testFileWithoutDownloadPermission() { + $userFolder = $this->createMock(Folder::class); + $this->rootFolder->method('getUserFolder') + ->with($this->equalTo($this->userId)) + ->willReturn($userFolder); + + $file = $this->createMock(File::class); + $file->method('getId')->willReturn(123); + $userFolder->method('get') + ->with($this->equalTo('file')) + ->willReturn($file); + + $this->previewManager->method('isAvailable') + ->with($this->equalTo($file)) + ->willReturn(true); + + $share = $this->createMock(IShare::class); + $share->method('canSeeContent') + ->willReturn(false); + + $storage = $this->createMock(ISharedStorage::class); + $storage->method('instanceOfStorage') + ->with(ISharedStorage::class) + ->willReturn(true); + $storage->method('getShare') + ->willReturn($share); + + $file->method('getStorage') + ->willReturn($storage); + $file->method('isReadable') + ->willReturn(true); + + $this->request->method('getHeader')->willReturn(''); + + $res = $this->controller->getPreview('file', 10, 10, true, true); + $expected = new DataResponse([], Http::STATUS_FORBIDDEN); + + $this->assertEquals($expected, $res); + } + + public function testFileWithoutDownloadPermissionButHeader() { $userFolder = $this->createMock(Folder::class); $this->rootFolder->method('getUserFolder') ->with($this->equalTo($this->userId)) ->willReturn($userFolder); $file = $this->createMock(File::class); + $file->method('getId')->willReturn(123); $userFolder->method('get') ->with($this->equalTo('file')) ->willReturn($file); @@ -180,26 +236,51 @@ class PreviewControllerTest extends \Test\TestCase { ->with($this->equalTo($file)) ->willReturn(true); + $share = $this->createMock(IShare::class); + $share->method('canSeeContent') + ->willReturn(false); + + $storage = $this->createMock(ISharedStorage::class); + $storage->method('instanceOfStorage') + ->with(ISharedStorage::class) + ->willReturn(true); + $storage->method('getShare') + ->willReturn($share); + + $file->method('getStorage') + ->willReturn($storage); $file->method('isReadable') ->willReturn(true); + $this->request + ->method('getHeader') + ->with('x-nc-preview') + ->willReturn('true'); + + $preview = $this->createMock(ISimpleFile::class); + $preview->method('getName')->willReturn('my name'); + $preview->method('getMTime')->willReturn(42); $this->previewManager->method('getPreview') ->with($this->equalTo($file), 10, 10, false, $this->equalTo('myMode')) - ->willThrowException(new NotFoundException()); + ->willReturn($preview); + $preview->method('getMimeType') + ->willReturn('myMime'); $res = $this->controller->getPreview('file', 10, 10, true, true, 'myMode'); - $expected = new DataResponse([], Http::STATUS_NOT_FOUND); - $this->assertEquals($expected, $res); + $this->assertEquals('myMime', $res->getHeaders()['Content-Type']); + $this->assertEquals(Http::STATUS_OK, $res->getStatus()); + $this->assertEquals($preview, $this->invokePrivate($res, 'file')); } - public function testValidPreview() { + public function testValidPreview(): void { $userFolder = $this->createMock(Folder::class); $this->rootFolder->method('getUserFolder') ->with($this->equalTo($this->userId)) ->willReturn($userFolder); $file = $this->createMock(File::class); + $file->method('getId')->willReturn(123); $userFolder->method('get') ->with($this->equalTo('file')) ->willReturn($file); @@ -211,6 +292,63 @@ class PreviewControllerTest extends \Test\TestCase { $file->method('isReadable') ->willReturn(true); + $storage = $this->createMock(IStorage::class); + $file->method('getStorage') + ->willReturn($storage); + + $preview = $this->createMock(ISimpleFile::class); + $preview->method('getName')->willReturn('my name'); + $preview->method('getMTime')->willReturn(42); + $this->previewManager->method('getPreview') + ->with($this->equalTo($file), 10, 10, false, $this->equalTo('myMode')) + ->willReturn($preview); + $preview->method('getMimeType') + ->willReturn('myMime'); + + $res = $this->controller->getPreview('file', 10, 10, true, true, 'myMode'); + + $this->assertEquals('myMime', $res->getHeaders()['Content-Type']); + $this->assertEquals(Http::STATUS_OK, $res->getStatus()); + $this->assertEquals($preview, $this->invokePrivate($res, 'file')); + } + + public function testValidPreviewOfShare() { + $userFolder = $this->createMock(Folder::class); + $this->rootFolder->method('getUserFolder') + ->with($this->equalTo($this->userId)) + ->willReturn($userFolder); + + $file = $this->createMock(File::class); + $file->method('getId')->willReturn(123); + $userFolder->method('get') + ->with($this->equalTo('file')) + ->willReturn($file); + + $this->previewManager->method('isAvailable') + ->with($this->equalTo($file)) + ->willReturn(true); + + // No attributes set -> download permitted + $share = $this->createMock(IShare::class); + $share->method('canSeeContent') + ->willReturn(true); + + $storage = $this->createMock(ISharedStorage::class); + $storage->method('instanceOfStorage') + ->with(ISharedStorage::class) + ->willReturn(true); + $storage->method('getShare') + ->willReturn($share); + + $file->method('getStorage') + ->willReturn($storage); + $file->method('isReadable') + ->willReturn(true); + + $this->request + ->method('getHeader') + ->willReturn(''); + $preview = $this->createMock(ISimpleFile::class); $preview->method('getName')->willReturn('my name'); $preview->method('getMTime')->willReturn(42); diff --git a/tests/Core/Controller/SvgControllerTest.php b/tests/Core/Controller/SvgControllerTest.php deleted file mode 100644 index f44440389ff..00000000000 --- a/tests/Core/Controller/SvgControllerTest.php +++ /dev/null @@ -1,198 +0,0 @@ -<?php - -declare(strict_types = 1); -/** - * @copyright Copyright (c) 2018 Michael Weimann <mail@michael-weimann.eu> - * - * @author Michael Weimann <mail@michael-weimann.eu> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -namespace Tests\Core\Controller; - -use OC\AppFramework\Http; -use OC\Core\Controller\SvgController; -use OC\Template\IconsCacher; -use OCP\App\AppPathNotFoundException; -use OCP\App\IAppManager; -use OCP\AppFramework\Utility\ITimeFactory; -use OCP\IRequest; -use Test\TestCase; - -/** - * This class provides test cases for the svg controller - */ -class SvgControllerTest extends TestCase { - public const TEST_IMAGES_SOURCE_PATH = __DIR__ . '/../../data/svg'; - public const TEST_IMAGES_PATH = __DIR__ . '/../../../core/img/testImages'; - public const TEST_IMAGE_MIXED = 'mixed-source.svg'; - public const TEST_IMAGE_RECT = 'rect-black.svg'; - public const TEST_IMAGES = [ - self::TEST_IMAGE_MIXED, - self::TEST_IMAGE_RECT, - ]; - - /** @var IAppManager|\PHPUnit\Framework\MockObject\MockObject */ - private $appManager; - - /** - * @var SvgController - */ - private $svgController; - - /** - * Copy test svgs into the core img "test" directory. - * - * @beforeClass - * @return void - */ - public static function copyTestImagesIntoPlace() { - mkdir(self::TEST_IMAGES_PATH); - foreach (self::TEST_IMAGES as $testImage) { - copy( - self::TEST_IMAGES_SOURCE_PATH .'/' . $testImage, - self::TEST_IMAGES_PATH . '/' . $testImage - ); - } - } - - /** - * Removes the test svgs from the core img "test" directory. - * - * @afterClass - * @return void - */ - public static function removeTestImages() { - foreach (self::TEST_IMAGES as $testImage) { - unlink(self::TEST_IMAGES_PATH . '/' . $testImage); - } - rmdir(self::TEST_IMAGES_PATH); - } - - /** - * Setups a SVG controller instance for tests. - * - * @before - * @return void - */ - public function setupSvgController() { - /** @var IRequest */ - $request = $this->getMockBuilder(IRequest::class)->getMock(); - /** @var ITimeFactory $timeFactory */ - $timeFactory = $this->getMockBuilder(ITimeFactory::class)->getMock(); - /** @var IAppManager */ - $this->appManager = $this->getMockBuilder(IAppManager::class)->getMock(); - /** @var IconsCacher $iconsCacher */ - $iconsCacher = $this->getMockBuilder(IconsCacher::class)->disableOriginalConstructor()->setMethods(['__construct'])->getMock(); - $this->svgController = new SvgController('core', $request, $timeFactory, $this->appManager, $iconsCacher); - } - - /** - * Checks that requesting an unknown image results in a 404. - * - * @return void - */ - public function testGetSvgFromCoreNotFound() { - $response = $this->svgController->getSvgFromCore('huhuu', '2342', '#ff0000'); - self::assertEquals(Http::STATUS_NOT_FOUND, $response->getStatus()); - } - - /** - * Provides svg coloring test data. - * - * @return array - */ - public function provideGetSvgFromCoreTestData(): array { - return [ - 'mixed' => ['mixed-source', 'f00', file_get_contents(self::TEST_IMAGES_SOURCE_PATH . '/mixed-red.svg')], - 'black rect' => ['rect-black', 'f00', file_get_contents(self::TEST_IMAGES_SOURCE_PATH . '/rect-red.svg')], - ]; - } - - /** - * Tests that retrieving a colored SVG works. - * - * @dataProvider provideGetSvgFromCoreTestData - * @param string $name The requested svg name - * @param string $color The requested color - * @param string $expected The expected svg - * @return void - */ - public function testGetSvgFromCore(string $name, string $color, string $expected) { - $response = $this->svgController->getSvgFromCore('testImages', $name, $color); - - self::assertEquals(Http::STATUS_OK, $response->getStatus()); - - $headers = $response->getHeaders(); - self::assertArrayHasKey('Content-Type', $headers); - self::assertEquals($headers['Content-Type'], 'image/svg+xml'); - - self::assertEquals($expected, $response->getData()); - } - - /** - * Checks that requesting an unknown image results in a 404. - */ - public function testGetSvgFromAppNotFound(): void { - $this->appManager->expects($this->once()) - ->method('getAppPath') - ->with('invalid_app') - ->willThrowException(new AppPathNotFoundException('Could not find path for invalid_app')); - - $response = $this->svgController->getSvgFromApp('invalid_app', 'some-icon', '#ff0000'); - self::assertEquals(Http::STATUS_NOT_FOUND, $response->getStatus()); - } - - /** - * Provides svg coloring test data. - * - * @return array - */ - public function provideGetSvgFromAppTestData(): array { - return [ - 'settings admin' => ['settings', 'admin', 'f00', file_get_contents(self::TEST_IMAGES_SOURCE_PATH . '/settings-admin-red.svg')], - 'files app' => ['files', 'app', 'f00', file_get_contents(self::TEST_IMAGES_SOURCE_PATH . '/files-app-red.svg')], - ]; - } - - /** - * Tests that retrieving a colored SVG works. - * - * @dataProvider provideGetSvgFromAppTestData - * @param string $appName - * @param string $name The requested svg name - * @param string $color The requested color - * @param string $expected - */ - public function testGetSvgFromApp(string $appName, string $name, string $color, string $expected): void { - $this->appManager->expects($this->once()) - ->method('getAppPath') - ->with($appName) - ->willReturn(realpath(__DIR__ . '/../../../apps/') . '/' . $appName); - - $response = $this->svgController->getSvgFromApp($appName, $name, $color); - - self::assertEquals(Http::STATUS_OK, $response->getStatus()); - - $headers = $response->getHeaders(); - self::assertArrayHasKey('Content-Type', $headers); - self::assertEquals($headers['Content-Type'], 'image/svg+xml'); - - self::assertEquals($expected, $response->getData()); - } -} diff --git a/tests/Core/Controller/TwoFactorChallengeControllerTest.php b/tests/Core/Controller/TwoFactorChallengeControllerTest.php index 561f243eb4b..d9ea1ca263f 100644 --- a/tests/Core/Controller/TwoFactorChallengeControllerTest.php +++ b/tests/Core/Controller/TwoFactorChallengeControllerTest.php @@ -1,23 +1,9 @@ <?php /** - * @author Christoph Wurst <christoph@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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 Test\Core\Controller; @@ -31,17 +17,16 @@ use OCP\Authentication\TwoFactorAuth\IActivatableAtLogin; use OCP\Authentication\TwoFactorAuth\ILoginSetupProvider; use OCP\Authentication\TwoFactorAuth\IProvider; use OCP\Authentication\TwoFactorAuth\TwoFactorException; -use OCP\ILogger; use OCP\IRequest; use OCP\ISession; use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserSession; -use OCP\Template; +use OCP\Template\ITemplate; +use Psr\Log\LoggerInterface; use Test\TestCase; class TwoFactorChallengeControllerTest extends TestCase { - /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */ private $request; @@ -57,7 +42,7 @@ class TwoFactorChallengeControllerTest extends TestCase { /** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */ private $urlGenerator; - /** @var ILogger|\PHPUnit\Framework\MockObject\MockObject */ + /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */ private $logger; /** @var TwoFactorChallengeController|\PHPUnit\Framework\MockObject\MockObject */ @@ -71,7 +56,7 @@ class TwoFactorChallengeControllerTest extends TestCase { $this->userSession = $this->createMock(IUserSession::class); $this->session = $this->createMock(ISession::class); $this->urlGenerator = $this->createMock(IURLGenerator::class); - $this->logger = $this->createMock(ILogger::class); + $this->logger = $this->createMock(LoggerInterface::class); $this->controller = $this->getMockBuilder(TwoFactorChallengeController::class) ->setConstructorArgs([ @@ -83,14 +68,14 @@ class TwoFactorChallengeControllerTest extends TestCase { $this->urlGenerator, $this->logger, ]) - ->setMethods(['getLogoutUrl']) + ->onlyMethods(['getLogoutUrl']) ->getMock(); $this->controller->expects($this->any()) ->method('getLogoutUrl') ->willReturn('logoutAttribute'); } - public function testSelectChallenge() { + public function testSelectChallenge(): void { $user = $this->getMockBuilder(IUser::class)->getMock(); $p1 = $this->createMock(IActivatableAtLogin::class); $p1->method('getId')->willReturn('p1'); @@ -124,13 +109,13 @@ class TwoFactorChallengeControllerTest extends TestCase { $this->assertEquals($expected, $this->controller->selectChallenge('/some/url')); } - public function testShowChallenge() { + public function testShowChallenge(): void { $user = $this->createMock(IUser::class); $provider = $this->createMock(IProvider::class); $provider->method('getId')->willReturn('myprovider'); $backupProvider = $this->createMock(IProvider::class); $backupProvider->method('getId')->willReturn('backup_codes'); - $tmpl = $this->createMock(Template::class); + $tmpl = $this->createMock(ITemplate::class); $providerSet = new ProviderSet([$provider, $backupProvider], true); $this->userSession->expects($this->once()) @@ -175,7 +160,7 @@ class TwoFactorChallengeControllerTest extends TestCase { $this->assertEquals($expected, $this->controller->showChallenge('myprovider', '/re/dir/ect/url')); } - public function testShowInvalidChallenge() { + public function testShowInvalidChallenge(): void { $user = $this->createMock(IUser::class); $providerSet = new ProviderSet([], false); @@ -196,7 +181,7 @@ class TwoFactorChallengeControllerTest extends TestCase { $this->assertEquals($expected, $this->controller->showChallenge('myprovider', 'redirect/url')); } - public function testSolveChallenge() { + public function testSolveChallenge(): void { $user = $this->createMock(IUser::class); $provider = $this->createMock(IProvider::class); @@ -221,7 +206,7 @@ class TwoFactorChallengeControllerTest extends TestCase { $this->assertEquals($expected, $this->controller->solveChallenge('myprovider', 'token')); } - public function testSolveValidChallengeAndRedirect() { + public function testSolveValidChallengeAndRedirect(): void { $user = $this->createMock(IUser::class); $provider = $this->createMock(IProvider::class); @@ -246,7 +231,7 @@ class TwoFactorChallengeControllerTest extends TestCase { $this->assertEquals($expected, $this->controller->solveChallenge('myprovider', 'token', 'redirect%20url')); } - public function testSolveChallengeInvalidProvider() { + public function testSolveChallengeInvalidProvider(): void { $user = $this->getMockBuilder(IUser::class)->getMock(); $this->userSession->expects($this->once()) @@ -266,7 +251,7 @@ class TwoFactorChallengeControllerTest extends TestCase { $this->assertEquals($expected, $this->controller->solveChallenge('myprovider', 'token')); } - public function testSolveInvalidChallenge() { + public function testSolveInvalidChallenge(): void { $user = $this->createMock(IUser::class); $provider = $this->createMock(IProvider::class); @@ -300,10 +285,10 @@ class TwoFactorChallengeControllerTest extends TestCase { $this->assertEquals($expected, $this->controller->solveChallenge('myprovider', 'token', '/url')); } - public function testSolveChallengeTwoFactorException() { + public function testSolveChallengeTwoFactorException(): void { $user = $this->createMock(IUser::class); $provider = $this->createMock(IProvider::class); - $exception = new TwoFactorException("2FA failed"); + $exception = new TwoFactorException('2FA failed'); $this->userSession->expects($this->once()) ->method('getUser') @@ -316,13 +301,17 @@ class TwoFactorChallengeControllerTest extends TestCase { $this->twoFactorManager->expects($this->once()) ->method('verifyChallenge') ->with('myprovider', $user, 'token') - ->will($this->throwException($exception)); - $this->session->expects($this->at(0)) - ->method('set') - ->with('two_factor_auth_error_message', "2FA failed"); - $this->session->expects($this->at(1)) + ->willThrowException($exception); + $calls = [ + ['two_factor_auth_error_message', '2FA failed'], + ['two_factor_auth_error', true], + ]; + $this->session->expects($this->exactly(2)) ->method('set') - ->with('two_factor_auth_error', true); + ->willReturnCallback(function () use (&$calls): void { + $expected = array_shift($calls); + $this->assertEquals($expected, func_get_args()); + }); $this->urlGenerator->expects($this->once()) ->method('linkToRoute') ->with('core.TwoFactorChallenge.showChallenge', [ @@ -338,7 +327,7 @@ class TwoFactorChallengeControllerTest extends TestCase { $this->assertEquals($expected, $this->controller->solveChallenge('myprovider', 'token', '/url')); } - public function testSetUpProviders() { + public function testSetUpProviders(): void { $user = $this->createMock(IUser::class); $this->userSession->expects($this->once()) ->method('getUser') @@ -358,6 +347,7 @@ class TwoFactorChallengeControllerTest extends TestCase { $provider, ], 'logout_url' => 'logoutAttribute', + 'redirect_url' => null, ], 'guest' ); @@ -367,7 +357,7 @@ class TwoFactorChallengeControllerTest extends TestCase { $this->assertEquals($expected, $response); } - public function testSetUpInvalidProvider() { + public function testSetUpInvalidProvider(): void { $user = $this->createMock(IUser::class); $this->userSession->expects($this->once()) ->method('getUser') @@ -393,7 +383,7 @@ class TwoFactorChallengeControllerTest extends TestCase { $this->assertEquals($expected, $response); } - public function testSetUpProvider() { + public function testSetUpProvider(): void { $user = $this->createMock(IUser::class); $this->userSession->expects($this->once()) ->method('getUser') @@ -413,7 +403,7 @@ class TwoFactorChallengeControllerTest extends TestCase { ->method('getLoginSetup') ->with($user) ->willReturn($loginSetup); - $tmpl = $this->createMock(Template::class); + $tmpl = $this->createMock(ITemplate::class); $loginSetup->expects($this->once()) ->method('getBody') ->willReturn($tmpl); @@ -427,6 +417,7 @@ class TwoFactorChallengeControllerTest extends TestCase { 'provider' => $provider, 'logout_url' => 'logoutAttribute', 'template' => 'tmpl', + 'redirect_url' => null, ], 'guest' ); @@ -436,13 +427,14 @@ class TwoFactorChallengeControllerTest extends TestCase { $this->assertEquals($expected, $response); } - public function testConfirmProviderSetup() { + public function testConfirmProviderSetup(): void { $this->urlGenerator->expects($this->once()) ->method('linkToRoute') ->with( 'core.TwoFactorChallenge.showChallenge', [ 'challengeProviderId' => 'totp', + 'redirect_url' => null, ]) ->willReturn('2fa/select/page'); $expected = new RedirectResponse('2fa/select/page'); diff --git a/tests/Core/Controller/UserControllerTest.php b/tests/Core/Controller/UserControllerTest.php index 8b9c11ad4b1..2473f280580 100644 --- a/tests/Core/Controller/UserControllerTest.php +++ b/tests/Core/Controller/UserControllerTest.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright 2016, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\Core\Controller; @@ -31,7 +15,6 @@ use OCP\IUserManager; use Test\TestCase; class UserControllerTest extends TestCase { - /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */ private $userManager; @@ -49,7 +32,7 @@ class UserControllerTest extends TestCase { ); } - public function testGetDisplayNames() { + public function testGetDisplayNames(): void { $user = $this->createMock(IUser::class); $user->method('getDisplayName') ->willReturn('FooDisplay Name'); diff --git a/tests/Core/Controller/WellKnownControllerTest.php b/tests/Core/Controller/WellKnownControllerTest.php index 2a35ed5ac85..35606dc6384 100644 --- a/tests/Core/Controller/WellKnownControllerTest.php +++ b/tests/Core/Controller/WellKnownControllerTest.php @@ -2,25 +2,9 @@ declare(strict_types=1); -/* - * @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. +/** + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Tests\Core\Controller; @@ -34,7 +18,6 @@ use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class WellKnownControllerTest extends TestCase { - /** @var IRequest|MockObject */ private $request; @@ -57,7 +40,7 @@ class WellKnownControllerTest extends TestCase { } public function testHandleNotProcessed(): void { - $httpResponse = $this->controller->handle("nodeinfo"); + $httpResponse = $this->controller->handle('nodeinfo'); self::assertInstanceOf(JSONResponse::class, $httpResponse); self::assertArrayHasKey('X-NEXTCLOUD-WELL-KNOWN', $httpResponse->getHeaders()); @@ -72,14 +55,14 @@ class WellKnownControllerTest extends TestCase { $this->manager->expects(self::once()) ->method('process') ->with( - "nodeinfo", + 'nodeinfo', $this->request )->willReturn($response); $jsonResponse->expects(self::once()) ->method('addHeader') ->willReturnSelf(); - $httpResponse = $this->controller->handle("nodeinfo"); + $httpResponse = $this->controller->handle('nodeinfo'); self::assertInstanceOf(JSONResponse::class, $httpResponse); } diff --git a/tests/Core/Controller/WipeControllerTest.php b/tests/Core/Controller/WipeControllerTest.php index 298d11848b8..5330eb599e6 100644 --- a/tests/Core/Controller/WipeControllerTest.php +++ b/tests/Core/Controller/WipeControllerTest.php @@ -2,25 +2,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Tests\Core\Controller; @@ -34,7 +17,6 @@ use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class WipeControllerTest extends TestCase { - /** @var RemoteWipe|MockObject */ private $remoteWipe; @@ -51,7 +33,7 @@ class WipeControllerTest extends TestCase { $this->remoteWipe); } - public function dataTest() { + public static function dataTest(): array { return [ // valid token, could perform operation, valid result [ true, true, true], @@ -65,10 +47,9 @@ class WipeControllerTest extends TestCase { * @param bool $valid * @param bool $couldPerform * @param bool $result - * - * @dataProvider dataTest */ - public function testCheckWipe(bool $valid, bool $couldPerform, bool $result) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataTest')] + public function testCheckWipe(bool $valid, bool $couldPerform, bool $result): void { if (!$valid) { $this->remoteWipe->method('start') ->with('mytoken') @@ -94,10 +75,9 @@ class WipeControllerTest extends TestCase { * @param bool $valid * @param bool $couldPerform * @param bool $result - * - * @dataProvider dataTest */ - public function testWipeDone(bool $valid, bool $couldPerform, bool $result) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataTest')] + public function testWipeDone(bool $valid, bool $couldPerform, bool $result): void { if (!$valid) { $this->remoteWipe->method('finish') ->with('mytoken') |