diff options
Diffstat (limited to 'tests/lib/AppFramework')
64 files changed, 4431 insertions, 3356 deletions
diff --git a/tests/lib/AppFramework/AppTest.php b/tests/lib/AppFramework/AppTest.php index 3dc62246e97..f9b7cf50675 100644 --- a/tests/lib/AppFramework/AppTest.php +++ b/tests/lib/AppFramework/AppTest.php @@ -1,32 +1,18 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework; use OC\AppFramework\App; +use OC\AppFramework\DependencyInjection\DIContainer; use OC\AppFramework\Http\Dispatcher; use OCP\AppFramework\Controller; -use OCP\AppFramework\Http; +use OCP\AppFramework\Http\IOutput; use OCP\AppFramework\Http\Response; function rrmdir($directory) { @@ -43,7 +29,7 @@ function rrmdir($directory) { class AppTest extends \Test\TestCase { - private $container; + private DIContainer $container; private $io; private $api; private $controller; @@ -58,10 +44,10 @@ class AppTest extends \Test\TestCase { protected function setUp(): void { parent::setUp(); - $this->container = new \OC\AppFramework\DependencyInjection\DIContainer('test', []); + $this->container = new DIContainer('test', []); $this->controller = $this->createMock(Controller::class); $this->dispatcher = $this->createMock(Dispatcher::class); - $this->io = $this->createMock(Http\IOutput::class); + $this->io = $this->createMock(IOutput::class); $this->headers = ['key' => 'value']; $this->output = 'hi'; @@ -69,24 +55,24 @@ class AppTest extends \Test\TestCase { $this->controllerMethod = 'method'; $this->container[$this->controllerName] = $this->controller; - $this->container['Dispatcher'] = $this->dispatcher; - $this->container['OCP\\AppFramework\\Http\\IOutput'] = $this->io; + $this->container[Dispatcher::class] = $this->dispatcher; + $this->container[IOutput::class] = $this->io; $this->container['urlParams'] = ['_route' => 'not-profiler']; $this->appPath = __DIR__ . '/../../../apps/namespacetestapp'; $infoXmlPath = $this->appPath . '/appinfo/info.xml'; mkdir($this->appPath . '/appinfo', 0777, true); - $xml = '<?xml version="1.0" encoding="UTF-8"?>' . - '<info>' . - '<id>namespacetestapp</id>' . - '<namespace>NameSpaceTestApp</namespace>' . - '</info>'; + $xml = '<?xml version="1.0" encoding="UTF-8"?>' + . '<info>' + . '<id>namespacetestapp</id>' + . '<namespace>NameSpaceTestApp</namespace>' + . '</info>'; file_put_contents($infoXmlPath, $xml); } - public function testControllerNameAndMethodAreBeingPassed() { + public function testControllerNameAndMethodAreBeingPassed(): void { $return = ['HTTP/2.0 200 OK', [], [], null, new Response()]; $this->dispatcher->expects($this->once()) ->method('dispatch') @@ -102,19 +88,19 @@ class AppTest extends \Test\TestCase { } - public function testBuildAppNamespace() { + public function testBuildAppNamespace(): void { $ns = App::buildAppNamespace('someapp'); $this->assertEquals('OCA\Someapp', $ns); } - public function testBuildAppNamespaceCore() { + public function testBuildAppNamespaceCore(): void { $ns = App::buildAppNamespace('someapp', 'OC\\'); $this->assertEquals('OC\Someapp', $ns); } - public function testBuildAppNamespaceInfoXml() { + public function testBuildAppNamespaceInfoXml(): void { $ns = App::buildAppNamespace('namespacetestapp', 'OCA\\'); $this->assertEquals('OCA\NameSpaceTestApp', $ns); } @@ -126,7 +112,7 @@ class AppTest extends \Test\TestCase { } - public function testOutputIsPrinted() { + public function testOutputIsPrinted(): void { $return = ['HTTP/2.0 200 OK', [], [], $this->output, new Response()]; $this->dispatcher->expects($this->once()) ->method('dispatch') @@ -139,17 +125,15 @@ class AppTest extends \Test\TestCase { App::main($this->controllerName, $this->controllerMethod, $this->container, []); } - public function dataNoOutput() { + public static function dataNoOutput(): array { return [ ['HTTP/2.0 204 No content'], ['HTTP/2.0 304 Not modified'], ]; } - /** - * @dataProvider dataNoOutput - */ - public function testNoOutput(string $statusCode) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoOutput')] + public function testNoOutput(string $statusCode): void { $return = [$statusCode, [], [], $this->output, new Response()]; $this->dispatcher->expects($this->once()) ->method('dispatch') @@ -165,7 +149,7 @@ class AppTest extends \Test\TestCase { } - public function testCallbackIsCalled() { + public function testCallbackIsCalled(): void { $mock = $this->getMockBuilder('OCP\AppFramework\Http\ICallbackResponse') ->getMock(); @@ -180,8 +164,8 @@ class AppTest extends \Test\TestCase { App::main($this->controllerName, $this->controllerMethod, $this->container, []); } - public function testCoreApp() { - $this->container['AppName'] = 'core'; + public function testCoreApp(): void { + $this->container['appName'] = 'core'; $this->container['OC\Core\Controller\Foo'] = $this->controller; $this->container['urlParams'] = ['_route' => 'not-profiler']; @@ -198,8 +182,8 @@ class AppTest extends \Test\TestCase { App::main('Foo', $this->controllerMethod, $this->container); } - public function testSettingsApp() { - $this->container['AppName'] = 'settings'; + public function testSettingsApp(): void { + $this->container['appName'] = 'settings'; $this->container['OCA\Settings\Controller\Foo'] = $this->controller; $this->container['urlParams'] = ['_route' => 'not-profiler']; @@ -216,8 +200,8 @@ class AppTest extends \Test\TestCase { App::main('Foo', $this->controllerMethod, $this->container); } - public function testApp() { - $this->container['AppName'] = 'bar'; + public function testApp(): void { + $this->container['appName'] = 'bar'; $this->container['OCA\Bar\Controller\Foo'] = $this->controller; $this->container['urlParams'] = ['_route' => 'not-profiler']; diff --git a/tests/lib/AppFramework/Bootstrap/BootContextTest.php b/tests/lib/AppFramework/Bootstrap/BootContextTest.php index 86f653604a9..3a97ff2bbfc 100644 --- a/tests/lib/AppFramework/Bootstrap/BootContextTest.php +++ b/tests/lib/AppFramework/Bootstrap/BootContextTest.php @@ -3,24 +3,8 @@ 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 lib\AppFramework\Bootstrap; diff --git a/tests/lib/AppFramework/Bootstrap/CoordinatorTest.php b/tests/lib/AppFramework/Bootstrap/CoordinatorTest.php index a706abecc4f..0eeddb2173a 100644 --- a/tests/lib/AppFramework/Bootstrap/CoordinatorTest.php +++ b/tests/lib/AppFramework/Bootstrap/CoordinatorTest.php @@ -3,30 +3,15 @@ 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 lib\AppFramework\Bootstrap; use OC\AppFramework\Bootstrap\Coordinator; use OC\Support\CrashReport\Registry; +use OCA\Settings\AppInfo\Application; use OCP\App\IAppManager; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; @@ -83,7 +68,8 @@ class CoordinatorTest extends TestCase { $this->dashboardManager, $this->eventDispatcher, $this->eventLogger, - $this->logger + $this->appManager, + $this->logger, ); } @@ -91,8 +77,8 @@ class CoordinatorTest extends TestCase { $appId = 'settings'; $this->serverContainer->expects($this->once()) ->method('query') - ->with(\OCA\Settings\AppInfo\Application::class) - ->willThrowException(new QueryException("")); + ->with(Application::class) + ->willThrowException(new QueryException('')); $this->logger->expects($this->once()) ->method('error'); @@ -101,10 +87,10 @@ class CoordinatorTest extends TestCase { public function testBootAppNotBootable(): void { $appId = 'settings'; - $mockApp = $this->createMock(\OCA\Settings\AppInfo\Application::class); + $mockApp = $this->createMock(Application::class); $this->serverContainer->expects($this->once()) ->method('query') - ->with(\OCA\Settings\AppInfo\Application::class) + ->with(Application::class) ->willReturn($mockApp); $this->coordinator->bootApp($appId); @@ -125,7 +111,7 @@ class CoordinatorTest extends TestCase { }; $this->serverContainer->expects($this->once()) ->method('query') - ->with(\OCA\Settings\AppInfo\Application::class) + ->with(Application::class) ->willReturn($mockApp); $this->coordinator->bootApp($appId); diff --git a/tests/lib/AppFramework/Bootstrap/FunctionInjectorTest.php b/tests/lib/AppFramework/Bootstrap/FunctionInjectorTest.php index 909a98f97c8..8f6944ce34f 100644 --- a/tests/lib/AppFramework/Bootstrap/FunctionInjectorTest.php +++ b/tests/lib/AppFramework/Bootstrap/FunctionInjectorTest.php @@ -3,30 +3,15 @@ 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 lib\AppFramework\Bootstrap; use OC\AppFramework\Bootstrap\FunctionInjector; use OC\AppFramework\Utility\SimpleContainer; +use OCP\AppFramework\QueryException; use Test\TestCase; interface Foo { @@ -43,7 +28,7 @@ class FunctionInjectorTest extends TestCase { } public function testInjectFnNotRegistered(): void { - $this->expectException(\OCP\AppFramework\QueryException::class); + $this->expectException(QueryException::class); (new FunctionInjector($this->container))->injectFn(static function (Foo $p1): void { }); diff --git a/tests/lib/AppFramework/Bootstrap/RegistrationContextTest.php b/tests/lib/AppFramework/Bootstrap/RegistrationContextTest.php index 55f30a895f5..c0095713370 100644 --- a/tests/lib/AppFramework/Bootstrap/RegistrationContextTest.php +++ b/tests/lib/AppFramework/Bootstrap/RegistrationContextTest.php @@ -3,24 +3,8 @@ 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 lib\AppFramework\Bootstrap; @@ -84,9 +68,7 @@ class RegistrationContextTest extends TestCase { $this->context->delegateEventListenerRegistrations($dispatcher); } - /** - * @dataProvider dataProvider_TrueFalse - */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataProvider_TrueFalse')] public function testRegisterService(bool $shared): void { $app = $this->createMock(App::class); $service = 'abc'; @@ -172,7 +154,7 @@ class RegistrationContextTest extends TestCase { ); } - public function dataProvider_TrueFalse() { + public static function dataProvider_TrueFalse(): array { return[ [true], [false] diff --git a/tests/lib/AppFramework/Controller/ApiControllerTest.php b/tests/lib/AppFramework/Controller/ApiControllerTest.php index 975b92c5b96..9dd980f975f 100644 --- a/tests/lib/AppFramework/Controller/ApiControllerTest.php +++ b/tests/lib/AppFramework/Controller/ApiControllerTest.php @@ -1,24 +1,9 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Controller; @@ -36,7 +21,7 @@ class ApiControllerTest extends \Test\TestCase { /** @var ChildApiController */ protected $controller; - public function testCors() { + public function testCors(): void { $request = new Request( ['server' => ['HTTP_ORIGIN' => 'test']], $this->createMock(IRequestId::class), diff --git a/tests/lib/AppFramework/Controller/AuthPublicShareControllerTest.php b/tests/lib/AppFramework/Controller/AuthPublicShareControllerTest.php index e996f287c16..4efcac2dccf 100644 --- a/tests/lib/AppFramework/Controller/AuthPublicShareControllerTest.php +++ b/tests/lib/AppFramework/Controller/AuthPublicShareControllerTest.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright 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 Test\AppFramework\Controller; @@ -55,7 +39,7 @@ class AuthPublicShareControllerTest extends \Test\TestCase { $this->request, $this->session, $this->urlGenerator - ])->setMethods([ + ])->onlyMethods([ 'authFailed', 'getPasswordHash', 'isAuthenticated', @@ -68,20 +52,22 @@ class AuthPublicShareControllerTest extends \Test\TestCase { ])->getMock(); } - public function testShowAuthenticate() { + public function testShowAuthenticate(): void { $expects = new TemplateResponse('core', 'publicshareauth', [], 'guest'); $this->assertEquals($expects, $this->controller->showAuthenticate()); } - public function testAuthenticateAuthenticated() { + public function testAuthenticateAuthenticated(): void { $this->controller->method('isAuthenticated') ->willReturn(true); $this->controller->setToken('myToken'); $this->session->method('get') - ->willReturnMap(['public_link_authenticate_redirect', ['foo' => 'bar']]); + ->willReturnMap([ + ['public_link_authenticate_redirect', json_encode(['foo' => 'bar'])], + ]); $this->urlGenerator->method('linkToRoute') ->willReturn('myLink!'); @@ -91,7 +77,7 @@ class AuthPublicShareControllerTest extends \Test\TestCase { $this->assertSame('myLink!', $result->getRedirectURL()); } - public function testAuthenticateInvalidPassword() { + public function testAuthenticateInvalidPassword(): void { $this->controller->setToken('token'); $this->controller->method('isPasswordProtected') ->willReturn(true); @@ -111,7 +97,7 @@ class AuthPublicShareControllerTest extends \Test\TestCase { $this->assertEquals($expects, $result); } - public function testAuthenticateValidPassword() { + public function testAuthenticateValidPassword(): void { $this->controller->setToken('token'); $this->controller->method('isPasswordProtected') ->willReturn(true); @@ -124,7 +110,9 @@ class AuthPublicShareControllerTest extends \Test\TestCase { $this->session->expects($this->once()) ->method('regenerateId'); $this->session->method('get') - ->willReturnMap(['public_link_authenticate_redirect', ['foo' => 'bar']]); + ->willReturnMap([ + ['public_link_authenticate_redirect', json_encode(['foo' => 'bar'])], + ]); $tokenSet = false; $hashSet = false; diff --git a/tests/lib/AppFramework/Controller/ControllerTest.php b/tests/lib/AppFramework/Controller/ControllerTest.php index 1f347cea535..aa016872847 100644 --- a/tests/lib/AppFramework/Controller/ControllerTest.php +++ b/tests/lib/AppFramework/Controller/ControllerTest.php @@ -1,28 +1,14 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Controller; +use OC\AppFramework\DependencyInjection\DIContainer; use OC\AppFramework\Http\Request; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\DataResponse; @@ -30,7 +16,6 @@ use OCP\AppFramework\Http\JSONResponse; use OCP\IConfig; use OCP\IRequest; use OCP\IRequestId; -use OC\AppFramework\DependencyInjection\DIContainer; class ChildController extends Controller { public function __construct($appName, $request) { @@ -81,12 +66,12 @@ class ControllerTest extends \Test\TestCase { ); $this->app = $this->getMockBuilder(DIContainer::class) - ->setMethods(['getAppName']) + ->onlyMethods(['getAppName']) ->setConstructorArgs(['test']) ->getMock(); $this->app->expects($this->any()) - ->method('getAppName') - ->willReturn('apptemplate_advanced'); + ->method('getAppName') + ->willReturn('apptemplate_advanced'); $this->controller = new ChildController($this->app, $request); $this->overwriteService(IRequest::class, $request); @@ -94,21 +79,21 @@ class ControllerTest extends \Test\TestCase { } - public function testFormatResonseInvalidFormat() { + public function testFormatResonseInvalidFormat(): void { $this->expectException(\DomainException::class); $this->controller->buildResponse(null, 'test'); } - public function testFormat() { + public function testFormat(): void { $response = $this->controller->buildResponse(['hi'], 'json'); $this->assertEquals(['hi'], $response->getData()); } - public function testFormatDataResponseJSON() { + public function testFormatDataResponseJSON(): void { $expectedHeaders = [ 'test' => 'something', 'Cache-Control' => 'no-cache, no-store, must-revalidate', @@ -116,7 +101,7 @@ class ControllerTest extends \Test\TestCase { 'Content-Security-Policy' => "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'", 'Feature-Policy' => "autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone 'none';payment 'none'", 'X-Request-Id' => $this->request->getId(), - 'X-Robots-Tag' => 'none', + 'X-Robots-Tag' => 'noindex, nofollow', ]; $response = $this->controller->customDataResponse(['hi']); @@ -128,7 +113,7 @@ class ControllerTest extends \Test\TestCase { } - public function testCustomFormatter() { + public function testCustomFormatter(): void { $response = $this->controller->custom('hi'); $response = $this->controller->buildResponse($response, 'json'); @@ -136,14 +121,14 @@ class ControllerTest extends \Test\TestCase { } - public function testDefaultResponderToJSON() { + public function testDefaultResponderToJSON(): void { $responder = $this->controller->getResponderByHTTPHeader('*/*'); $this->assertEquals('json', $responder); } - public function testResponderAcceptHeaderParsed() { + public function testResponderAcceptHeaderParsed(): void { $responder = $this->controller->getResponderByHTTPHeader( '*/*, application/tom, application/json' ); @@ -152,7 +137,7 @@ class ControllerTest extends \Test\TestCase { } - public function testResponderAcceptHeaderParsedUpperCase() { + public function testResponderAcceptHeaderParsedUpperCase(): void { $responder = $this->controller->getResponderByHTTPHeader( '*/*, apPlication/ToM, application/json' ); diff --git a/tests/lib/AppFramework/Controller/OCSControllerTest.php b/tests/lib/AppFramework/Controller/OCSControllerTest.php index ce110f435ef..4ab45ad6b06 100644 --- a/tests/lib/AppFramework/Controller/OCSControllerTest.php +++ b/tests/lib/AppFramework/Controller/OCSControllerTest.php @@ -1,24 +1,9 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2015 Bernhard Posselt <dev@bernhard-posselt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Controller; @@ -35,7 +20,7 @@ class ChildOCSController extends OCSController { class OCSControllerTest extends \Test\TestCase { - public function testCors() { + public function testCors(): void { $request = new Request( [ 'server' => [ @@ -60,7 +45,7 @@ class OCSControllerTest extends \Test\TestCase { } - public function testXML() { + public function testXML(): void { $controller = new ChildOCSController('app', new Request( [], $this->createMock(IRequestId::class), @@ -68,19 +53,19 @@ class OCSControllerTest extends \Test\TestCase { )); $controller->setOCSVersion(1); - $expected = "<?xml version=\"1.0\"?>\n" . - "<ocs>\n" . - " <meta>\n" . - " <status>ok</status>\n" . - " <statuscode>100</statuscode>\n" . - " <message>OK</message>\n" . - " <totalitems></totalitems>\n" . - " <itemsperpage></itemsperpage>\n" . - " </meta>\n" . - " <data>\n" . - " <test>hi</test>\n" . - " </data>\n" . - "</ocs>\n"; + $expected = "<?xml version=\"1.0\"?>\n" + . "<ocs>\n" + . " <meta>\n" + . " <status>ok</status>\n" + . " <statuscode>100</statuscode>\n" + . " <message>OK</message>\n" + . " <totalitems></totalitems>\n" + . " <itemsperpage></itemsperpage>\n" + . " </meta>\n" + . " <data>\n" + . " <test>hi</test>\n" + . " </data>\n" + . "</ocs>\n"; $params = new DataResponse(['test' => 'hi']); @@ -89,15 +74,15 @@ class OCSControllerTest extends \Test\TestCase { $this->assertEquals($expected, $response->render()); } - public function testJSON() { + public function testJSON(): void { $controller = new ChildOCSController('app', new Request( [], $this->createMock(IRequestId::class), $this->createMock(IConfig::class) )); $controller->setOCSVersion(1); - $expected = '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK",' . - '"totalitems":"","itemsperpage":""},"data":{"test":"hi"}}}'; + $expected = '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK",' + . '"totalitems":"","itemsperpage":""},"data":{"test":"hi"}}}'; $params = new DataResponse(['test' => 'hi']); $response = $controller->buildResponse($params, 'json'); @@ -106,7 +91,7 @@ class OCSControllerTest extends \Test\TestCase { $this->assertEquals($expected, $response->render()); } - public function testXMLV2() { + public function testXMLV2(): void { $controller = new ChildOCSController('app', new Request( [], $this->createMock(IRequestId::class), @@ -114,17 +99,17 @@ class OCSControllerTest extends \Test\TestCase { )); $controller->setOCSVersion(2); - $expected = "<?xml version=\"1.0\"?>\n" . - "<ocs>\n" . - " <meta>\n" . - " <status>ok</status>\n" . - " <statuscode>200</statuscode>\n" . - " <message>OK</message>\n" . - " </meta>\n" . - " <data>\n" . - " <test>hi</test>\n" . - " </data>\n" . - "</ocs>\n"; + $expected = "<?xml version=\"1.0\"?>\n" + . "<ocs>\n" + . " <meta>\n" + . " <status>ok</status>\n" + . " <statuscode>200</statuscode>\n" + . " <message>OK</message>\n" + . " </meta>\n" + . " <data>\n" + . " <test>hi</test>\n" + . " </data>\n" + . "</ocs>\n"; $params = new DataResponse(['test' => 'hi']); @@ -133,7 +118,7 @@ class OCSControllerTest extends \Test\TestCase { $this->assertEquals($expected, $response->render()); } - public function testJSONV2() { + public function testJSONV2(): void { $controller = new ChildOCSController('app', new Request( [], $this->createMock(IRequestId::class), diff --git a/tests/lib/AppFramework/Controller/PublicShareControllerTest.php b/tests/lib/AppFramework/Controller/PublicShareControllerTest.php index 9c03ba4cb6e..e676b8a0d7e 100644 --- a/tests/lib/AppFramework/Controller/PublicShareControllerTest.php +++ b/tests/lib/AppFramework/Controller/PublicShareControllerTest.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright 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 Test\AppFramework\Controller; @@ -28,17 +12,14 @@ use OCP\IRequest; use OCP\ISession; class TestController extends PublicShareController { - /** @var string */ - private $hash; - - /** @var bool */ - private $isProtected; - - public function __construct(string $appName, IRequest $request, ISession $session, string $hash, bool $isProtected) { + public function __construct( + string $appName, + IRequest $request, + ISession $session, + private string $hash, + private bool $isProtected, + ) { parent::__construct($appName, $request, $session); - - $this->hash = $hash; - $this->isProtected = $isProtected; } protected function getPasswordHash(): string { @@ -67,14 +48,14 @@ class PublicShareControllerTest extends \Test\TestCase { $this->session = $this->createMock(ISession::class); } - public function testGetToken() { + public function testGetToken(): void { $controller = new TestController('app', $this->request, $this->session, 'hash', false); $controller->setToken('test'); $this->assertEquals('test', $controller->getToken()); } - public function dataIsAuthenticated() { + public static function dataIsAuthenticated(): array { return [ [false, 'token1', 'token1', 'hash1', 'hash1', true], [false, 'token1', 'token1', 'hash1', 'hash2', true], @@ -87,10 +68,8 @@ class PublicShareControllerTest extends \Test\TestCase { ]; } - /** - * @dataProvider dataIsAuthenticated - */ - public function testIsAuthenticatedNotPasswordProtected(bool $protected, string $token1, string $token2, string $hash1, string $hash2, bool $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataIsAuthenticated')] + public function testIsAuthenticatedNotPasswordProtected(bool $protected, string $token1, string $token2, string $hash1, string $hash2, bool $expected): void { $controller = new TestController('app', $this->request, $this->session, $hash2, $protected); $this->session->method('get') diff --git a/tests/lib/AppFramework/Db/EntityTest.php b/tests/lib/AppFramework/Db/EntityTest.php index d76a8ccfe06..eab081e6ac6 100644 --- a/tests/lib/AppFramework/Db/EntityTest.php +++ b/tests/lib/AppFramework/Db/EntityTest.php @@ -1,29 +1,15 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2012 Bernhard Posselt dev@bernhard-posselt.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Db; use OCP\AppFramework\Db\Entity; +use OCP\DB\Types; use PHPUnit\Framework\Constraint\IsType; /** @@ -42,25 +28,46 @@ use PHPUnit\Framework\Constraint\IsType; * @method void setTrueOrFalse(bool $trueOrFalse) * @method bool getAnotherBool() * @method bool isAnotherBool() - * @method void setAnotherBool(bool $anotherBool) * @method string getLongText() * @method void setLongText(string $longText) + * @method \DateTime getTime() + * @method void setTime(\DateTime $time) + * @method \DateTimeImmutable getDatetime() + * @method void setDatetime(\DateTimeImmutable $datetime) */ class TestEntity extends Entity { - protected $name; protected $email; protected $testId; + protected $smallInt; + protected $bigInt; protected $preName; protected $trueOrFalse; protected $anotherBool; + protected $text; protected $longText; - - public function __construct($name = null) { - $this->addType('testId', 'integer'); + protected $time; + protected $datetime; + + public function __construct( + protected $name = null, + ) { + $this->addType('testId', Types::INTEGER); + $this->addType('smallInt', Types::SMALLINT); + $this->addType('bigInt', Types::BIGINT); + $this->addType('anotherBool', Types::BOOLEAN); + $this->addType('text', Types::TEXT); + $this->addType('longText', Types::BLOB); + $this->addType('time', Types::TIME); + $this->addType('datetime', Types::DATETIME_IMMUTABLE); + + // Legacy types $this->addType('trueOrFalse', 'bool'); - $this->addType('anotherBool', 'boolean'); - $this->addType('longText', 'blob'); - $this->name = $name; + $this->addType('legacyInt', 'int'); + $this->addType('doubleNowFloat', 'double'); + } + + public function setAnotherBool(bool $anotherBool): void { + parent::setAnotherBool($anotherBool); } } @@ -74,7 +81,7 @@ class EntityTest extends \Test\TestCase { } - public function testResetUpdatedFields() { + public function testResetUpdatedFields(): void { $entity = new TestEntity(); $entity->setId(3); $entity->resetUpdatedFields(); @@ -83,19 +90,21 @@ class EntityTest extends \Test\TestCase { } - public function testFromRow() { + public function testFromRow(): void { $row = [ 'pre_name' => 'john', - 'email' => 'john@something.com' + 'email' => 'john@something.com', + 'another_bool' => 1, ]; $this->entity = TestEntity::fromRow($row); $this->assertEquals($row['pre_name'], $this->entity->getPreName()); $this->assertEquals($row['email'], $this->entity->getEmail()); + $this->assertEquals($row['another_bool'], $this->entity->getAnotherBool()); } - public function testGetSetId() { + public function testGetSetId(): void { $id = 3; $this->entity->setId(3); @@ -103,28 +112,28 @@ class EntityTest extends \Test\TestCase { } - public function testColumnToPropertyNoReplacement() { + public function testColumnToPropertyNoReplacement(): void { $column = 'my'; $this->assertEquals('my', $this->entity->columnToProperty($column)); } - public function testColumnToProperty() { + public function testColumnToProperty(): void { $column = 'my_attribute'; $this->assertEquals('myAttribute', $this->entity->columnToProperty($column)); } - public function testPropertyToColumnNoReplacement() { + public function testPropertyToColumnNoReplacement(): void { $property = 'my'; $this->assertEquals('my', $this->entity->propertyToColumn($property)); } - public function testSetterMarksFieldUpdated() { + public function testSetterMarksFieldUpdated(): void { $this->entity->setId(3); $this->assertContains('id', array_keys($this->entity->getUpdatedFields())); @@ -132,7 +141,7 @@ class EntityTest extends \Test\TestCase { - public function testCallShouldOnlyWorkForGetterSetter() { + public function testCallShouldOnlyWorkForGetterSetter(): void { $this->expectException(\BadFunctionCallException::class); $this->entity->something(); @@ -140,21 +149,21 @@ class EntityTest extends \Test\TestCase { - public function testGetterShouldFailIfAttributeNotDefined() { + public function testGetterShouldFailIfAttributeNotDefined(): void { $this->expectException(\BadFunctionCallException::class); $this->entity->getTest(); } - public function testSetterShouldFailIfAttributeNotDefined() { + public function testSetterShouldFailIfAttributeNotDefined(): void { $this->expectException(\BadFunctionCallException::class); $this->entity->setTest(); } - public function testFromRowShouldNotAssignEmptyArray() { + public function testFromRowShouldNotAssignEmptyArray(): void { $row = []; $entity2 = new TestEntity(); @@ -163,7 +172,7 @@ class EntityTest extends \Test\TestCase { } - public function testIdGetsConvertedToInt() { + public function testIdGetsConvertedToInt(): void { $row = ['id' => '4']; $this->entity = TestEntity::fromRow($row); @@ -171,7 +180,7 @@ class EntityTest extends \Test\TestCase { } - public function testSetType() { + public function testSetType(): void { $row = ['testId' => '4']; $this->entity = TestEntity::fromRow($row); @@ -179,7 +188,7 @@ class EntityTest extends \Test\TestCase { } - public function testFromParams() { + public function testFromParams(): void { $params = [ 'testId' => 4, 'email' => 'john@doe' @@ -192,7 +201,7 @@ class EntityTest extends \Test\TestCase { $this->assertTrue($entity instanceof TestEntity); } - public function testSlugify() { + public function testSlugify(): void { $entity = new TestEntity(); $entity->setName('Slugify this!'); $this->assertEquals('slugify-this', $entity->slugify('name')); @@ -201,20 +210,36 @@ class EntityTest extends \Test\TestCase { } - public function testSetterCasts() { + public static function dataSetterCasts(): array { + return [ + ['Id', '3', 3], + ['smallInt', '3', 3], + ['bigInt', '' . PHP_INT_MAX, PHP_INT_MAX], + ['trueOrFalse', 0, false], + ['trueOrFalse', 1, true], + ['anotherBool', 0, false], + ['anotherBool', 1, true], + ['text', 33, '33'], + ['longText', PHP_INT_MAX, '' . PHP_INT_MAX], + ]; + } + + + #[\PHPUnit\Framework\Attributes\DataProvider('dataSetterCasts')] + public function testSetterCasts(string $field, mixed $in, mixed $out): void { $entity = new TestEntity(); - $entity->setId('3'); - $this->assertSame(3, $entity->getId()); + $entity->{'set' . $field}($in); + $this->assertSame($out, $entity->{'get' . $field}()); } - public function testSetterDoesNotCastOnNull() { + public function testSetterDoesNotCastOnNull(): void { $entity = new TestEntity(); $entity->setId(null); $this->assertSame(null, $entity->getId()); } - public function testSetterConvertsResourcesToStringProperly() { + public function testSetterConvertsResourcesToStringProperly(): void { $string = 'Definitely a string'; $stream = fopen('php://memory', 'r+'); fwrite($stream, $string); @@ -226,33 +251,57 @@ class EntityTest extends \Test\TestCase { $this->assertSame($string, $entity->getLongText()); } + public function testSetterConvertsDatetime() { + $entity = new TestEntity(); + $entity->setDatetime('2024-08-19 15:26:00'); + $this->assertEquals(new \DateTimeImmutable('2024-08-19 15:26:00'), $entity->getDatetime()); + } + + public function testSetterDoesNotConvertNullOnDatetime() { + $entity = new TestEntity(); + $entity->setDatetime(null); + $this->assertNull($entity->getDatetime()); + } + + public function testSetterConvertsTime() { + $entity = new TestEntity(); + $entity->setTime('15:26:00'); + $this->assertEquals(new \DateTime('15:26:00'), $entity->getTime()); + } - public function testGetFieldTypes() { + public function testGetFieldTypes(): void { $entity = new TestEntity(); $this->assertEquals([ - 'id' => 'integer', - 'testId' => 'integer', - 'trueOrFalse' => 'bool', - 'anotherBool' => 'boolean', - 'longText' => 'blob', + 'id' => Types::INTEGER, + 'testId' => Types::INTEGER, + 'smallInt' => Types::SMALLINT, + 'bigInt' => Types::BIGINT, + 'anotherBool' => Types::BOOLEAN, + 'text' => Types::TEXT, + 'longText' => Types::BLOB, + 'time' => Types::TIME, + 'datetime' => Types::DATETIME_IMMUTABLE, + 'trueOrFalse' => Types::BOOLEAN, + 'legacyInt' => Types::INTEGER, + 'doubleNowFloat' => Types::FLOAT, ], $entity->getFieldTypes()); } - public function testGetItInt() { + public function testGetItInt(): void { $entity = new TestEntity(); $entity->setId(3); - $this->assertEquals('integer', gettype($entity->getId())); + $this->assertEquals(Types::INTEGER, gettype($entity->getId())); } - public function testFieldsNotMarkedUpdatedIfNothingChanges() { + public function testFieldsNotMarkedUpdatedIfNothingChanges(): void { $entity = new TestEntity('hey'); $entity->setName('hey'); $this->assertEquals(0, count($entity->getUpdatedFields())); } - public function testIsGetter() { + public function testIsGetter(): void { $entity = new TestEntity(); $entity->setTrueOrFalse(false); $entity->setAnotherBool(false); @@ -261,7 +310,7 @@ class EntityTest extends \Test\TestCase { } - public function testIsGetterShoudFailForOtherType() { + public function testIsGetterShoudFailForOtherType(): void { $this->expectException(\BadFunctionCallException::class); $entity = new TestEntity(); diff --git a/tests/lib/AppFramework/Db/QBMapperDBTest.php b/tests/lib/AppFramework/Db/QBMapperDBTest.php new file mode 100644 index 00000000000..614f1099644 --- /dev/null +++ b/tests/lib/AppFramework/Db/QBMapperDBTest.php @@ -0,0 +1,160 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\AppFramework\Db; + +use Doctrine\DBAL\Schema\SchemaException; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\QBMapper; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\DB\Types; +use OCP\IConfig; +use OCP\IDBConnection; +use OCP\Server; +use Test\TestCase; + +/** + * @method void setTime(?\DateTime $time) + * @method ?\DateTime getTime() + * @method void setDatetime(?\DateTimeImmutable $datetime) + * @method ?\DateTimeImmutable getDatetime() + */ +class QBDBTestEntity extends Entity { + protected ?\DateTime $time = null; + protected ?\DateTimeImmutable $datetime = null; + + public function __construct() { + $this->addType('time', Types::TIME); + $this->addType('datetime', Types::DATETIME_IMMUTABLE); + } +} + +/** + * Class QBDBTestMapper + * + * @package Test\AppFramework\Db + */ +class QBDBTestMapper extends QBMapper { + public function __construct(IDBConnection $db) { + parent::__construct($db, 'testing', QBDBTestEntity::class); + } + + public function getParameterTypeForPropertyForTest(Entity $entity, string $property) { + return parent::getParameterTypeForProperty($entity, $property); + } + + public function getById(int $id): QBDBTestEntity { + $qb = $this->db->getQueryBuilder(); + $query = $qb + ->select('*') + ->from($this->tableName) + ->where( + $qb->expr()->eq('id', $qb->createPositionalParameter($id, IQueryBuilder::PARAM_INT)), + ); + return $this->findEntity($query); + } +} + +/** + * Test real database handling (serialization) + * @group DB + */ +class QBMapperDBTest extends TestCase { + /** @var \Doctrine\DBAL\Connection|IDBConnection */ + protected $connection; + protected $schemaSetup = false; + + protected function setUp(): void { + parent::setUp(); + + $this->connection = Server::get(IDBConnection::class); + $this->prepareTestingTable(); + } + + public function testInsertDateTime(): void { + $mapper = new QBDBTestMapper($this->connection); + $entity = new QBDBTestEntity(); + $entity->setTime(new \DateTime('2003-01-01 12:34:00')); + $entity->setDatetime(new \DateTimeImmutable('2000-01-01 23:45:00')); + + $result = $mapper->insert($entity); + $this->assertNotNull($result->getId()); + } + + public function testRetrieveDateTime(): void { + $time = new \DateTime('2000-01-01 01:01:00'); + $datetime = new \DateTimeImmutable('2000-01-01 02:02:00'); + + $mapper = new QBDBTestMapper($this->connection); + $entity = new QBDBTestEntity(); + $entity->setTime($time); + $entity->setDatetime($datetime); + + $result = $mapper->insert($entity); + $this->assertNotNull($result->getId()); + + $dbEntity = $mapper->getById($result->getId()); + $this->assertEquals($time->format('H:i:s'), $dbEntity->getTime()->format('H:i:s')); + $this->assertEquals($datetime->format('Y-m-d H:i:s'), $dbEntity->getDatetime()->format('Y-m-d H:i:s')); + // The date is not saved for "time" + $this->assertNotEquals($time->format('Y'), $dbEntity->getTime()->format('Y')); + } + + public function testUpdateDateTime(): void { + $time = new \DateTime('2000-01-01 01:01:00'); + $datetime = new \DateTimeImmutable('2000-01-01 02:02:00'); + + $mapper = new QBDBTestMapper($this->connection); + $entity = new QBDBTestEntity(); + $entity->setTime('now'); + $entity->setDatetime('now'); + + /** @var QBDBTestEntity */ + $entity = $mapper->insert($entity); + $this->assertNotNull($entity->getId()); + + // Update the values + $entity->setTime($time); + $entity->setDatetime($datetime); + $mapper->update($entity); + + $dbEntity = $mapper->getById($entity->getId()); + $this->assertEquals($time->format('H:i:s'), $dbEntity->getTime()->format('H:i:s')); + $this->assertEquals($datetime->format('Y-m-d H:i:s'), $dbEntity->getDatetime()->format('Y-m-d H:i:s')); + } + + protected function prepareTestingTable(): void { + if ($this->schemaSetup) { + $this->connection->getQueryBuilder()->delete('testing')->executeStatement(); + } + + $prefix = Server::get(IConfig::class)->getSystemValueString('dbtableprefix', 'oc_'); + $schema = $this->connection->createSchema(); + try { + $schema->getTable($prefix . 'testing'); + $this->connection->getQueryBuilder()->delete('testing')->executeStatement(); + } catch (SchemaException $e) { + $this->schemaSetup = true; + $table = $schema->createTable($prefix . 'testing'); + $table->addColumn('id', Types::BIGINT, [ + 'autoincrement' => true, + 'notnull' => true, + ]); + + $table->addColumn('time', Types::TIME, [ + 'notnull' => false, + ]); + + $table->addColumn('datetime', Types::DATETIME_IMMUTABLE, [ + 'notnull' => false, + ]); + + $table->setPrimaryKey(['id']); + $this->connection->migrateToSchema($schema); + } + } +} diff --git a/tests/lib/AppFramework/Db/QBMapperTest.php b/tests/lib/AppFramework/Db/QBMapperTest.php index 82830dcc05a..0f18ef3f204 100644 --- a/tests/lib/AppFramework/Db/QBMapperTest.php +++ b/tests/lib/AppFramework/Db/QBMapperTest.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright 2019, Marius David Wieschollek <git.public@mdns.eu> - * - * @author Marius David Wieschollek <git.public@mdns.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/>. - * + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\AppFramework\Db; @@ -27,7 +11,9 @@ use OCP\AppFramework\Db\Entity; use OCP\AppFramework\Db\QBMapper; use OCP\DB\QueryBuilder\IExpressionBuilder; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\DB\Types; use OCP\IDBConnection; +use PHPUnit\Framework\MockObject\MockObject; /** * @method bool getBoolProp() @@ -40,6 +26,8 @@ use OCP\IDBConnection; * @method void setBooleanProp(bool $booleanProp) * @method integer getIntegerProp() * @method void setIntegerProp(integer $integerProp) + * @method ?\DateTimeImmutable getDatetimeProp() + * @method void setDatetimeProp(?\DateTimeImmutable $datetime) */ class QBTestEntity extends Entity { protected $intProp; @@ -48,14 +36,16 @@ class QBTestEntity extends Entity { protected $integerProp; protected $booleanProp; protected $jsonProp; + protected $datetimeProp; public function __construct() { $this->addType('intProp', 'int'); $this->addType('boolProp', 'bool'); - $this->addType('stringProp', 'string'); - $this->addType('integerProp', 'integer'); - $this->addType('booleanProp', 'boolean'); - $this->addType('jsonProp', 'json'); + $this->addType('stringProp', Types::STRING); + $this->addType('integerProp', Types::INTEGER); + $this->addType('booleanProp', Types::BOOLEAN); + $this->addType('jsonProp', Types::JSON); + $this->addType('datetimeProp', Types::DATETIME_IMMUTABLE); } } @@ -80,25 +70,11 @@ class QBTestMapper extends QBMapper { * @package Test\AppFramework\Db */ class QBMapperTest extends \Test\TestCase { - /** - * @var \PHPUnit\Framework\MockObject\MockObject|IDBConnection - */ - protected $db; - /** - * @var \PHPUnit\Framework\MockObject\MockObject|IQueryBuilder - */ - protected $qb; - - /** - * @var \PHPUnit\Framework\MockObject\MockObject|IExpressionBuilder - */ - protected $expr; - - /** - * @var \Test\AppFramework\Db\QBTestMapper - */ - protected $mapper; + protected IDBConnection&MockObject $db; + protected IQueryBuilder&MockObject $qb; + protected IExpressionBuilder&MockObject $expr; + protected QBTestMapper $mapper; /** * @throws \ReflectionException @@ -124,45 +100,60 @@ class QBMapperTest extends \Test\TestCase { $this->mapper = new QBTestMapper($this->db); } - - public function testInsertEntityParameterTypeMapping() { + + public function testInsertEntityParameterTypeMapping(): void { + $datetime = new \DateTimeImmutable(); $entity = new QBTestEntity(); $entity->setIntProp(123); $entity->setBoolProp(true); $entity->setStringProp('string'); $entity->setIntegerProp(456); $entity->setBooleanProp(false); + $entity->setDatetimeProp($datetime); $intParam = $this->qb->createNamedParameter('int_prop', IQueryBuilder::PARAM_INT); $boolParam = $this->qb->createNamedParameter('bool_prop', IQueryBuilder::PARAM_BOOL); $stringParam = $this->qb->createNamedParameter('string_prop', IQueryBuilder::PARAM_STR); $integerParam = $this->qb->createNamedParameter('integer_prop', IQueryBuilder::PARAM_INT); $booleanParam = $this->qb->createNamedParameter('boolean_prop', IQueryBuilder::PARAM_BOOL); - - $this->qb->expects($this->exactly(5)) + $datetimeParam = $this->qb->createNamedParameter('datetime_prop', IQueryBuilder::PARAM_DATETIME_IMMUTABLE); + + $createNamedParameterCalls = [ + [123, IQueryBuilder::PARAM_INT, null], + [true, IQueryBuilder::PARAM_BOOL, null], + ['string', IQueryBuilder::PARAM_STR, null], + [456, IQueryBuilder::PARAM_INT, null], + [false, IQueryBuilder::PARAM_BOOL, null], + [$datetime, IQueryBuilder::PARAM_DATETIME_IMMUTABLE, null], + ]; + $this->qb->expects($this->exactly(6)) ->method('createNamedParameter') - ->withConsecutive( - [$this->equalTo(123), $this->equalTo(IQueryBuilder::PARAM_INT)], - [$this->equalTo(true), $this->equalTo(IQueryBuilder::PARAM_BOOL)], - [$this->equalTo('string'), $this->equalTo(IQueryBuilder::PARAM_STR)], - [$this->equalTo(456), $this->equalTo(IQueryBuilder::PARAM_INT)], - [$this->equalTo(false), $this->equalTo(IQueryBuilder::PARAM_BOOL)] - ); - $this->qb->expects($this->exactly(5)) + ->willReturnCallback(function () use (&$createNamedParameterCalls): void { + $expected = array_shift($createNamedParameterCalls); + $this->assertEquals($expected, func_get_args()); + }); + + $setValueCalls = [ + ['int_prop', $intParam], + ['bool_prop', $boolParam], + ['string_prop', $stringParam], + ['integer_prop', $integerParam], + ['boolean_prop', $booleanParam], + ['datetime_prop', $datetimeParam], + ]; + $this->qb->expects($this->exactly(6)) ->method('setValue') - ->withConsecutive( - [$this->equalTo('int_prop'), $this->equalTo($intParam)], - [$this->equalTo('bool_prop'), $this->equalTo($boolParam)], - [$this->equalTo('string_prop'), $this->equalTo($stringParam)], - [$this->equalTo('integer_prop'), $this->equalTo($integerParam)], - [$this->equalTo('boolean_prop'), $this->equalTo($booleanParam)] - ); + ->willReturnCallback(function () use (&$setValueCalls): void { + $expected = array_shift($setValueCalls); + $this->assertEquals($expected, func_get_args()); + }); $this->mapper->insert($entity); } - - public function testUpdateEntityParameterTypeMapping() { + + public function testUpdateEntityParameterTypeMapping(): void { + $datetime = new \DateTimeImmutable(); $entity = new QBTestEntity(); $entity->setId(789); $entity->setIntProp(123); @@ -170,7 +161,8 @@ class QBMapperTest extends \Test\TestCase { $entity->setStringProp('string'); $entity->setIntegerProp(456); $entity->setBooleanProp(false); - $entity->setJsonProp(["hello" => "world"]); + $entity->setJsonProp(['hello' => 'world']); + $entity->setDatetimeProp($datetime); $idParam = $this->qb->createNamedParameter('id', IQueryBuilder::PARAM_INT); $intParam = $this->qb->createNamedParameter('int_prop', IQueryBuilder::PARAM_INT); @@ -179,29 +171,40 @@ class QBMapperTest extends \Test\TestCase { $integerParam = $this->qb->createNamedParameter('integer_prop', IQueryBuilder::PARAM_INT); $booleanParam = $this->qb->createNamedParameter('boolean_prop', IQueryBuilder::PARAM_BOOL); $jsonParam = $this->qb->createNamedParameter('json_prop', IQueryBuilder::PARAM_JSON); - - $this->qb->expects($this->exactly(7)) + $datetimeParam = $this->qb->createNamedParameter('datetime_prop', IQueryBuilder::PARAM_DATETIME_IMMUTABLE); + + $createNamedParameterCalls = [ + [123, IQueryBuilder::PARAM_INT, null], + [true, IQueryBuilder::PARAM_BOOL, null], + ['string', IQueryBuilder::PARAM_STR, null], + [456, IQueryBuilder::PARAM_INT, null], + [false, IQueryBuilder::PARAM_BOOL, null], + [['hello' => 'world'], IQueryBuilder::PARAM_JSON, null], + [$datetime, IQueryBuilder::PARAM_DATETIME_IMMUTABLE, null], + [789, IQueryBuilder::PARAM_INT, null], + ]; + $this->qb->expects($this->exactly(8)) ->method('createNamedParameter') - ->withConsecutive( - [$this->equalTo(123), $this->equalTo(IQueryBuilder::PARAM_INT)], - [$this->equalTo(true), $this->equalTo(IQueryBuilder::PARAM_BOOL)], - [$this->equalTo('string'), $this->equalTo(IQueryBuilder::PARAM_STR)], - [$this->equalTo(456), $this->equalTo(IQueryBuilder::PARAM_INT)], - [$this->equalTo(false), $this->equalTo(IQueryBuilder::PARAM_BOOL)], - [$this->equalTo(["hello" => "world"]), $this->equalTo(IQueryBuilder::PARAM_JSON)], - [$this->equalTo(789), $this->equalTo(IQueryBuilder::PARAM_INT)], - ); - - $this->qb->expects($this->exactly(6)) + ->willReturnCallback(function () use (&$createNamedParameterCalls): void { + $expected = array_shift($createNamedParameterCalls); + $this->assertEquals($expected, func_get_args()); + }); + + $setCalls = [ + ['int_prop', $intParam], + ['bool_prop', $boolParam], + ['string_prop', $stringParam], + ['integer_prop', $integerParam], + ['boolean_prop', $booleanParam], + ['json_prop', $datetimeParam], + ['datetime_prop', $datetimeParam], + ]; + $this->qb->expects($this->exactly(7)) ->method('set') - ->withConsecutive( - [$this->equalTo('int_prop'), $this->equalTo($intParam)], - [$this->equalTo('bool_prop'), $this->equalTo($boolParam)], - [$this->equalTo('string_prop'), $this->equalTo($stringParam)], - [$this->equalTo('integer_prop'), $this->equalTo($integerParam)], - [$this->equalTo('boolean_prop'), $this->equalTo($booleanParam)], - [$this->equalTo('json_prop'), $this->equalTo($jsonParam)] - ); + ->willReturnCallback(function () use (&$setCalls): void { + $expected = array_shift($setCalls); + $this->assertEquals($expected, func_get_args()); + }); $this->expr->expects($this->once()) ->method('eq') @@ -211,8 +214,8 @@ class QBMapperTest extends \Test\TestCase { $this->mapper->update($entity); } - - public function testGetParameterTypeForProperty() { + + public function testGetParameterTypeForProperty(): void { $entity = new QBTestEntity(); $intType = $this->mapper->getParameterTypeForPropertyForTest($entity, 'intProp'); @@ -233,6 +236,9 @@ class QBMapperTest extends \Test\TestCase { $jsonType = $this->mapper->getParameterTypeForPropertyForTest($entity, 'jsonProp'); $this->assertEquals(IQueryBuilder::PARAM_JSON, $jsonType, 'JSON type property mapping incorrect'); + $datetimeType = $this->mapper->getParameterTypeForPropertyForTest($entity, 'datetimeProp'); + $this->assertEquals(IQueryBuilder::PARAM_DATETIME_IMMUTABLE, $datetimeType, 'DateTimeImmutable type property mapping incorrect'); + $unknownType = $this->mapper->getParameterTypeForPropertyForTest($entity, 'someProp'); $this->assertEquals(IQueryBuilder::PARAM_STR, $unknownType, 'Unknown type property mapping incorrect'); } diff --git a/tests/lib/AppFramework/Db/TransactionalTest.php b/tests/lib/AppFramework/Db/TransactionalTest.php index fc2d4121382..72a3d9ae59f 100644 --- a/tests/lib/AppFramework/Db/TransactionalTest.php +++ b/tests/lib/AppFramework/Db/TransactionalTest.php @@ -1,25 +1,9 @@ <?php declare(strict_types=1); -/* - * @copyright 2022 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @author 2022 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: 2022 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace lib\AppFramework\Db; @@ -44,14 +28,13 @@ class TransactionalTest extends TestCase { $test = new class($this->db) { use TTransactional; - private IDBConnection $db; - - public function __construct(IDBConnection $db) { - $this->db = $db; + public function __construct( + private IDBConnection $db, + ) { } public function fail(): void { - $this->atomic(function () { + $this->atomic(function (): void { throw new RuntimeException('nope'); }, $this->db); } @@ -71,10 +54,9 @@ class TransactionalTest extends TestCase { $test = new class($this->db) { use TTransactional; - private IDBConnection $db; - - public function __construct(IDBConnection $db) { - $this->db = $db; + public function __construct( + private IDBConnection $db, + ) { } public function succeed(): int { diff --git a/tests/lib/AppFramework/DependencyInjection/DIContainerTest.php b/tests/lib/AppFramework/DependencyInjection/DIContainerTest.php index 04422643121..31188b12f14 100644 --- a/tests/lib/AppFramework/DependencyInjection/DIContainerTest.php +++ b/tests/lib/AppFramework/DependencyInjection/DIContainerTest.php @@ -1,26 +1,9 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @author Morris Jobke - * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com> - * @copyright 2013 Morris Jobke <morris.jobke@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\DependencyInjection; @@ -35,41 +18,43 @@ use OCP\AppFramework\Middleware; use OCP\AppFramework\QueryException; use OCP\IConfig; use OCP\IRequestId; +use PHPUnit\Framework\MockObject\MockObject; /** * @group DB */ class DIContainerTest extends \Test\TestCase { - /** @var DIContainer|\PHPUnit\Framework\MockObject\MockObject */ - private $container; + private DIContainer&MockObject $container; protected function setUp(): void { parent::setUp(); $this->container = $this->getMockBuilder(DIContainer::class) - ->setMethods(['isAdminUser']) + ->onlyMethods(['isAdminUser']) ->setConstructorArgs(['name']) ->getMock(); } - public function testProvidesRequest() { + public function testProvidesRequest(): void { $this->assertTrue(isset($this->container['Request'])); } - public function testProvidesMiddlewareDispatcher() { + public function testProvidesMiddlewareDispatcher(): void { $this->assertTrue(isset($this->container['MiddlewareDispatcher'])); } - public function testProvidesAppName() { + public function testProvidesAppName(): void { $this->assertTrue(isset($this->container['AppName'])); + $this->assertTrue(isset($this->container['appName'])); } - public function testAppNameIsSetCorrectly() { + public function testAppNameIsSetCorrectly(): void { $this->assertEquals('name', $this->container['AppName']); + $this->assertEquals('name', $this->container['appName']); } - public function testMiddlewareDispatcherIncludesSecurityMiddleware() { + public function testMiddlewareDispatcherIncludesSecurityMiddleware(): void { $this->container['Request'] = new Request( ['method' => 'GET'], $this->createMock(IRequestId::class), @@ -152,7 +137,7 @@ class DIContainerTest extends \Test\TestCase { $this->fail('Bootstrap registered middleware not found'); } - public function testInvalidAppClass() { + public function testInvalidAppClass(): void { $this->expectException(QueryException::class); $this->container->query('\OCA\Name\Foo'); } diff --git a/tests/lib/AppFramework/DependencyInjection/DIIntergrationTests.php b/tests/lib/AppFramework/DependencyInjection/DIIntergrationTests.php index 369a30ba7a3..219fd5134ae 100644 --- a/tests/lib/AppFramework/DependencyInjection/DIIntergrationTests.php +++ b/tests/lib/AppFramework/DependencyInjection/DIIntergrationTests.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 Test\AppFramework\DependencyInjection; @@ -38,16 +22,14 @@ class ClassA2 implements Interface1 { } class ClassB { - /** @var Interface1 */ - public $interface1; - /** * ClassB constructor. * * @param Interface1 $interface1 */ - public function __construct(Interface1 $interface1) { - $this->interface1 = $interface1; + public function __construct( + public Interface1 $interface1, + ) { } } @@ -65,7 +47,7 @@ class DIIntergrationTests extends TestCase { $this->container = new DIContainer('App1', [], $this->server); } - public function testInjectFromServer() { + public function testInjectFromServer(): void { $this->server->registerService(Interface1::class, function () { return new ClassA1(); }); @@ -81,7 +63,7 @@ class DIIntergrationTests extends TestCase { $this->assertSame(ClassA1::class, get_class($res->interface1)); } - public function testInjectDepFromServer() { + public function testInjectDepFromServer(): void { $this->server->registerService(Interface1::class, function () { return new ClassA1(); }); @@ -97,7 +79,7 @@ class DIIntergrationTests extends TestCase { $this->assertSame(ClassA1::class, get_class($res->interface1)); } - public function testOverwriteDepFromServer() { + public function testOverwriteDepFromServer(): void { $this->server->registerService(Interface1::class, function () { return new ClassA1(); }); @@ -117,7 +99,7 @@ class DIIntergrationTests extends TestCase { $this->assertSame(ClassA2::class, get_class($res->interface1)); } - public function testIgnoreOverwriteInServerClass() { + public function testIgnoreOverwriteInServerClass(): void { $this->server->registerService(Interface1::class, function () { return new ClassA1(); }); diff --git a/tests/lib/AppFramework/Http/ContentSecurityPolicyTest.php b/tests/lib/AppFramework/Http/ContentSecurityPolicyTest.php index 5c3f3ead5b0..75527e7eaf8 100644 --- a/tests/lib/AppFramework/Http/ContentSecurityPolicyTest.php +++ b/tests/lib/AppFramework/Http/ContentSecurityPolicyTest.php @@ -1,9 +1,9 @@ <?php + /** - * Copyright (c) 2015 Lukas Reschke lukas@owncloud.com - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\AppFramework\Http; @@ -24,416 +24,400 @@ class ContentSecurityPolicyTest extends \Test\TestCase { $this->contentSecurityPolicy = new ContentSecurityPolicy(); } - public function testGetPolicyDefault() { + public function testGetPolicyDefault(): void { $defaultPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; $this->assertSame($defaultPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyScriptDomainValid() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' www.owncloud.com;style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyScriptDomainValid(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' www.nextcloud.com;style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyScriptDomainValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' www.owncloud.com www.owncloud.org;style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyScriptDomainValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' www.nextcloud.com www.nextcloud.org;style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); - $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowScriptDomain() { + public function testGetPolicyDisallowScriptDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowScriptDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowScriptDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' www.owncloud.com;style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyDisallowScriptDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' www.nextcloud.com;style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowScriptDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowScriptDomainMultipleStacked() { + public function testGetPolicyDisallowScriptDomainMultipleStacked(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.org')->disallowScriptDomain('www.owncloud.com'); - $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); - } - - public function testGetPolicyScriptAllowInline() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' 'unsafe-inline';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - - $this->contentSecurityPolicy->allowInlineScript(true); - $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); - } - - public function testGetPolicyScriptAllowInlineWithDomain() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' www.owncloud.com 'unsafe-inline';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - - $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); - $this->contentSecurityPolicy->allowInlineScript(true); + $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowScriptDomain('www.nextcloud.org')->disallowScriptDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyScriptDisallowInlineAndEval() { + public function testGetPolicyScriptDisallowEval(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->allowInlineScript(false); $this->contentSecurityPolicy->allowEvalScript(false); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyStyleDomainValid() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' www.owncloud.com 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyStyleDomainValid(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' www.nextcloud.com 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedStyleDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyStyleDomainValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' www.owncloud.com www.owncloud.org 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyStyleDomainValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' www.nextcloud.com www.nextcloud.org 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); - $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedStyleDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedStyleDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowStyleDomain() { + public function testGetPolicyDisallowStyleDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedStyleDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowStyleDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowStyleDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' www.owncloud.com 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyDisallowStyleDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' www.nextcloud.com 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedStyleDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowStyleDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowStyleDomainMultipleStacked() { + public function testGetPolicyDisallowStyleDomainMultipleStacked(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.org')->disallowStyleDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedStyleDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowStyleDomain('www.nextcloud.org')->disallowStyleDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyStyleAllowInline() { + public function testGetPolicyStyleAllowInline(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; $this->contentSecurityPolicy->allowInlineStyle(true); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyStyleAllowInlineWithDomain() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' www.owncloud.com 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyStyleAllowInlineWithDomain(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' www.nextcloud.com 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedStyleDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyStyleDisallowInline() { + public function testGetPolicyStyleDisallowInline(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; $this->contentSecurityPolicy->allowInlineStyle(false); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyImageDomainValid() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob: www.owncloud.com;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyImageDomainValid(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob: www.nextcloud.com;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedImageDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyImageDomainValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob: www.owncloud.com www.owncloud.org;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyImageDomainValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob: www.nextcloud.com www.nextcloud.org;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); - $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedImageDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedImageDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowImageDomain() { + public function testGetPolicyDisallowImageDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowImageDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedImageDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowImageDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowImageDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob: www.owncloud.com;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyDisallowImageDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob: www.nextcloud.com;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowImageDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedImageDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowImageDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowImageDomainMultipleStakes() { + public function testGetPolicyDisallowImageDomainMultipleStakes(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowImageDomain('www.owncloud.org')->disallowImageDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedImageDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowImageDomain('www.nextcloud.org')->disallowImageDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyFontDomainValid() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data: www.owncloud.com;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyFontDomainValid(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data: www.nextcloud.com;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedFontDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyFontDomainValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data: www.owncloud.com www.owncloud.org;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyFontDomainValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data: www.nextcloud.com www.nextcloud.org;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); - $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedFontDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedFontDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowFontDomain() { + public function testGetPolicyDisallowFontDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowFontDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedFontDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowFontDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowFontDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data: www.owncloud.com;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyDisallowFontDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data: www.nextcloud.com;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowFontDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedFontDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowFontDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowFontDomainMultipleStakes() { + public function testGetPolicyDisallowFontDomainMultipleStakes(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowFontDomain('www.owncloud.org')->disallowFontDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedFontDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowFontDomain('www.nextcloud.org')->disallowFontDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyConnectDomainValid() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self' www.owncloud.com;media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyConnectDomainValid(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self' www.nextcloud.com;media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedConnectDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyConnectDomainValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self' www.owncloud.com www.owncloud.org;media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyConnectDomainValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self' www.nextcloud.com www.nextcloud.org;media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); - $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedConnectDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedConnectDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowConnectDomain() { + public function testGetPolicyDisallowConnectDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedConnectDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowConnectDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowConnectDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self' www.owncloud.com;media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyDisallowConnectDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self' www.nextcloud.com;media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedConnectDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowConnectDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowConnectDomainMultipleStakes() { + public function testGetPolicyDisallowConnectDomainMultipleStakes(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.org')->disallowConnectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedConnectDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowConnectDomain('www.nextcloud.org')->disallowConnectDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyMediaDomainValid() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self' www.owncloud.com;frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyMediaDomainValid(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self' www.nextcloud.com;frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedMediaDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyMediaDomainValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self' www.owncloud.com www.owncloud.org;frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyMediaDomainValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self' www.nextcloud.com www.nextcloud.org;frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); - $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedMediaDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedMediaDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowMediaDomain() { + public function testGetPolicyDisallowMediaDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedMediaDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowMediaDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowMediaDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self' www.owncloud.com;frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyDisallowMediaDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self' www.nextcloud.com;frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedMediaDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowMediaDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowMediaDomainMultipleStakes() { + public function testGetPolicyDisallowMediaDomainMultipleStakes(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.org')->disallowMediaDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedMediaDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowMediaDomain('www.nextcloud.org')->disallowMediaDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyObjectDomainValid() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';object-src www.owncloud.com;frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyObjectDomainValid(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';object-src www.nextcloud.com;frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedObjectDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyObjectDomainValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';object-src www.owncloud.com www.owncloud.org;frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyObjectDomainValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';object-src www.nextcloud.com www.nextcloud.org;frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); - $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedObjectDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedObjectDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowObjectDomain() { + public function testGetPolicyDisallowObjectDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedObjectDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowObjectDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowObjectDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';object-src www.owncloud.com;frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyDisallowObjectDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';object-src www.nextcloud.com;frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedObjectDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowObjectDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowObjectDomainMultipleStakes() { + public function testGetPolicyDisallowObjectDomainMultipleStakes(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.org')->disallowObjectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedObjectDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowObjectDomain('www.nextcloud.org')->disallowObjectDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetAllowedFrameDomain() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-src www.owncloud.com;frame-ancestors 'self';form-action 'self'"; + public function testGetAllowedFrameDomain(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-src www.nextcloud.com;frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedFrameDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyFrameDomainValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-src www.owncloud.com www.owncloud.org;frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyFrameDomainValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-src www.nextcloud.com www.nextcloud.org;frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); - $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedFrameDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedFrameDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowFrameDomain() { + public function testGetPolicyDisallowFrameDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedFrameDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowFrameDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowFrameDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-src www.owncloud.com;frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyDisallowFrameDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-src www.nextcloud.com;frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedFrameDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowFrameDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowFrameDomainMultipleStakes() { + public function testGetPolicyDisallowFrameDomainMultipleStakes(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.org')->disallowFrameDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedFrameDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowFrameDomain('www.nextcloud.org')->disallowFrameDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetAllowedChildSrcDomain() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';child-src child.owncloud.com;frame-ancestors 'self';form-action 'self'"; + public function testGetAllowedChildSrcDomain(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';child-src child.nextcloud.com;frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.owncloud.com'); + $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyChildSrcValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';child-src child.owncloud.com child.owncloud.org;frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyChildSrcValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';child-src child.nextcloud.com child.nextcloud.org;frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.owncloud.com'); - $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.owncloud.org'); + $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowChildSrcDomain() { + public function testGetPolicyDisallowChildSrcDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowChildSrcDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowChildSrcDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';child-src www.owncloud.com;frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyDisallowChildSrcDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';child-src www.nextcloud.com;frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowChildSrcDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowChildSrcDomainMultipleStakes() { + public function testGetPolicyDisallowChildSrcDomainMultipleStakes(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.org')->disallowChildSrcDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowChildSrcDomain('www.nextcloud.org')->disallowChildSrcDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetAllowedFrameAncestorDomain() { + public function testGetAllowedFrameAncestorDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self' sub.nextcloud.com;form-action 'self'"; $this->contentSecurityPolicy->addAllowedFrameAncestorDomain('sub.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyFrameAncestorValidMultiple() { + public function testGetPolicyFrameAncestorValidMultiple(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self' sub.nextcloud.com foo.nextcloud.com;form-action 'self'"; $this->contentSecurityPolicy->addAllowedFrameAncestorDomain('sub.nextcloud.com'); @@ -441,7 +425,7 @@ class ContentSecurityPolicyTest extends \Test\TestCase { $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowFrameAncestorDomain() { + public function testGetPolicyDisallowFrameAncestorDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; $this->contentSecurityPolicy->addAllowedFrameAncestorDomain('www.nextcloud.com'); @@ -449,7 +433,7 @@ class ContentSecurityPolicyTest extends \Test\TestCase { $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowFrameAncestorDomainMultiple() { + public function testGetPolicyDisallowFrameAncestorDomainMultiple(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self' www.nextcloud.com;form-action 'self'"; $this->contentSecurityPolicy->addAllowedFrameAncestorDomain('www.nextcloud.com'); @@ -457,35 +441,76 @@ class ContentSecurityPolicyTest extends \Test\TestCase { $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowFrameAncestorDomainMultipleStakes() { + public function testGetPolicyDisallowFrameAncestorDomainMultipleStakes(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; - $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.org')->disallowChildSrcDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowChildSrcDomain('www.nextcloud.org')->disallowChildSrcDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyUnsafeEval() { + public function testGetPolicyUnsafeEval(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; $this->contentSecurityPolicy->allowEvalScript(true); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyNonce() { - $nonce = 'my-nonce'; - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'nonce-".base64_encode($nonce) . "';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyUnsafeWasmEval(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' 'wasm-unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + + $this->contentSecurityPolicy->allowEvalWasm(true); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyNonce(): void { + $nonce = base64_encode('my-nonce'); + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'nonce-$nonce';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + + $this->contentSecurityPolicy->useJsNonce($nonce); + $this->contentSecurityPolicy->useStrictDynamicOnScripts(false); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyNonceDefault(): void { + $nonce = base64_encode('my-nonce'); + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'nonce-$nonce';script-src-elem 'strict-dynamic' 'nonce-$nonce';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; $this->contentSecurityPolicy->useJsNonce($nonce); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyNonceStrictDynamic() { - $nonce = 'my-nonce'; - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'strict-dynamic' 'nonce-".base64_encode($nonce) . "';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + public function testGetPolicyNonceStrictDynamic(): void { + $nonce = base64_encode('my-nonce'); + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'strict-dynamic' 'nonce-$nonce';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; $this->contentSecurityPolicy->useJsNonce($nonce); $this->contentSecurityPolicy->useStrictDynamic(true); + $this->contentSecurityPolicy->useStrictDynamicOnScripts(false); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyNonceStrictDynamicDefault(): void { + $nonce = base64_encode('my-nonce'); + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'strict-dynamic' 'nonce-$nonce';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + + $this->contentSecurityPolicy->useJsNonce($nonce); + $this->contentSecurityPolicy->useStrictDynamic(true); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyStrictDynamicOnScriptsOff(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + + $this->contentSecurityPolicy->useStrictDynamicOnScripts(false); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyStrictDynamicAndStrictDynamicOnScripts(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self' data:;connect-src 'self';media-src 'self';frame-ancestors 'self';form-action 'self'"; + + $this->contentSecurityPolicy->useStrictDynamic(true); + $this->contentSecurityPolicy->useStrictDynamicOnScripts(true); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } } diff --git a/tests/lib/AppFramework/Http/DataResponseTest.php b/tests/lib/AppFramework/Http/DataResponseTest.php index 575698dd878..e9a2c511140 100644 --- a/tests/lib/AppFramework/Http/DataResponseTest.php +++ b/tests/lib/AppFramework/Http/DataResponseTest.php @@ -1,24 +1,9 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2014 Bernhard Posselt <dev@bernhard-posselt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Http; @@ -26,6 +11,7 @@ namespace Test\AppFramework\Http; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; +use OCP\Server; class DataResponseTest extends \Test\TestCase { /** @@ -39,7 +25,7 @@ class DataResponseTest extends \Test\TestCase { } - public function testSetData() { + public function testSetData(): void { $params = ['hi', 'yo']; $this->response->setData($params); @@ -47,7 +33,7 @@ class DataResponseTest extends \Test\TestCase { } - public function testConstructorAllowsToSetData() { + public function testConstructorAllowsToSetData(): void { $data = ['hi']; $code = 300; $response = new DataResponse($data, $code); @@ -57,7 +43,7 @@ class DataResponseTest extends \Test\TestCase { } - public function testConstructorAllowsToSetHeaders() { + public function testConstructorAllowsToSetHeaders(): void { $data = ['hi']; $code = 300; $headers = ['test' => 'something']; @@ -67,8 +53,8 @@ class DataResponseTest extends \Test\TestCase { 'Cache-Control' => 'no-cache, no-store, must-revalidate', 'Content-Security-Policy' => "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'", 'Feature-Policy' => "autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone 'none';payment 'none'", - 'X-Robots-Tag' => 'none', - 'X-Request-Id' => \OC::$server->get(IRequest::class)->getId(), + 'X-Robots-Tag' => 'noindex, nofollow', + 'X-Request-Id' => Server::get(IRequest::class)->getId(), ]; $expectedHeaders = array_merge($expectedHeaders, $headers); @@ -78,7 +64,7 @@ class DataResponseTest extends \Test\TestCase { } - public function testChainability() { + public function testChainability(): void { $params = ['hi', 'yo']; $this->response->setData($params) ->setStatus(Http::STATUS_NOT_FOUND); diff --git a/tests/lib/AppFramework/Http/DispatcherTest.php b/tests/lib/AppFramework/Http/DispatcherTest.php index 7f81701a8b3..86c78e840e0 100644 --- a/tests/lib/AppFramework/Http/DispatcherTest.php +++ b/tests/lib/AppFramework/Http/DispatcherTest.php @@ -1,28 +1,14 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Http; +use OC\AppFramework\DependencyInjection\DIContainer; use OC\AppFramework\Http\Dispatcher; use OC\AppFramework\Http\Request; use OC\AppFramework\Middleware\MiddlewareDispatcher; @@ -31,19 +17,22 @@ use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\Http\ParameterOutOfRangeException; use OCP\AppFramework\Http\Response; use OCP\Diagnostics\IEventLogger; use OCP\IConfig; +use OCP\IDBConnection; use OCP\IRequest; +use OCP\IRequestId; +use OCP\Server; use PHPUnit\Framework\MockObject\MockObject; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; -use OCP\IRequestId; class TestController extends Controller { /** * @param string $appName - * @param \OCP\IRequest $request + * @param IRequest $request */ public function __construct($appName, $request) { parent::__construct($appName, $request); @@ -77,6 +66,10 @@ class TestController extends Controller { 'text' => [$int, $bool, $test, $test2] ]); } + + public function test(): Response { + return new DataResponse(); + } } /** @@ -91,19 +84,19 @@ class DispatcherTest extends \Test\TestCase { /** @var Dispatcher */ private $dispatcher; private $controllerMethod; - /** @var Controller|MockObject */ + /** @var Controller|MockObject */ private $controller; private $response; - /** @var IRequest|MockObject */ + /** @var IRequest|MockObject */ private $request; private $lastModified; private $etag; - /** @var Http|MockObject */ + /** @var Http|MockObject */ private $http; private $reflector; - /** @var IConfig|MockObject */ + /** @var IConfig|MockObject */ private $config; - /** @var LoggerInterface|MockObject */ + /** @var LoggerInterface|MockObject */ private $logger; /** @var IEventLogger|MockObject */ private $eventLogger; @@ -118,33 +111,17 @@ class DispatcherTest extends \Test\TestCase { $this->logger = $this->createMock(LoggerInterface::class); $this->eventLogger = $this->createMock(IEventLogger::class); $this->container = $this->createMock(ContainerInterface::class); - $app = $this->getMockBuilder( - 'OC\AppFramework\DependencyInjection\DIContainer') - ->disableOriginalConstructor() - ->getMock(); - $request = $this->getMockBuilder( - '\OC\AppFramework\Http\Request') - ->disableOriginalConstructor() - ->getMock(); - $this->http = $this->getMockBuilder( - \OC\AppFramework\Http::class) - ->disableOriginalConstructor() - ->getMock(); + $app = $this->createMock(DIContainer::class); + $request = $this->createMock(Request::class); + $this->http = $this->createMock(\OC\AppFramework\Http::class); - $this->middlewareDispatcher = $this->getMockBuilder( - '\OC\AppFramework\Middleware\MiddlewareDispatcher') - ->disableOriginalConstructor() - ->getMock(); - $this->controller = $this->getMockBuilder( - '\OCP\AppFramework\Controller') - ->setMethods([$this->controllerMethod]) + $this->middlewareDispatcher = $this->createMock(MiddlewareDispatcher::class); + $this->controller = $this->getMockBuilder(TestController::class) + ->onlyMethods([$this->controllerMethod]) ->setConstructorArgs([$app, $request]) ->getMock(); - $this->request = $this->getMockBuilder( - '\OC\AppFramework\Http\Request') - ->disableOriginalConstructor() - ->getMock(); + $this->request = $this->createMock(Request::class); $this->reflector = new ControllerMethodReflector(); @@ -154,7 +131,7 @@ class DispatcherTest extends \Test\TestCase { $this->reflector, $this->request, $this->config, - \OC::$server->getDatabaseConnection(), + Server::get(IDBConnection::class), $this->logger, $this->eventLogger, $this->container, @@ -180,7 +157,7 @@ class DispatcherTest extends \Test\TestCase { ->method('beforeController') ->with($this->equalTo($this->controller), $this->equalTo($this->controllerMethod)) - ->will($this->throwException($exception)); + ->willThrowException($exception); if ($catchEx) { $this->middlewareDispatcher->expects($this->once()) ->method('afterException') @@ -244,7 +221,7 @@ class DispatcherTest extends \Test\TestCase { } - public function testDispatcherReturnsArrayWith2Entries() { + public function testDispatcherReturnsArrayWith2Entries(): void { $this->setMiddlewareExpectations(''); $response = $this->dispatcher->dispatch($this->controller, $this->controllerMethod); @@ -254,7 +231,7 @@ class DispatcherTest extends \Test\TestCase { } - public function testHeadersAndOutputAreReturned() { + public function testHeadersAndOutputAreReturned(): void { $out = 'yo'; $httpHeaders = 'Http'; $responseHeaders = ['hell' => 'yeah']; @@ -269,7 +246,7 @@ class DispatcherTest extends \Test\TestCase { } - public function testExceptionCallsAfterException() { + public function testExceptionCallsAfterException(): void { $out = 'yo'; $httpHeaders = 'Http'; $responseHeaders = ['hell' => 'yeah']; @@ -284,7 +261,7 @@ class DispatcherTest extends \Test\TestCase { } - public function testExceptionThrowsIfCanNotBeHandledByAfterException() { + public function testExceptionThrowsIfCanNotBeHandledByAfterException(): void { $out = 'yo'; $httpHeaders = 'Http'; $responseHeaders = ['hell' => 'yeah']; @@ -300,7 +277,7 @@ class DispatcherTest extends \Test\TestCase { private function dispatcherPassthrough() { $this->middlewareDispatcher->expects($this->once()) - ->method('beforeController'); + ->method('beforeController'); $this->middlewareDispatcher->expects($this->once()) ->method('afterController') ->willReturnCallback(function ($a, $b, $in) { @@ -314,7 +291,7 @@ class DispatcherTest extends \Test\TestCase { } - public function testControllerParametersInjected() { + public function testControllerParametersInjected(): void { $this->request = new Request( [ 'post' => [ @@ -331,7 +308,7 @@ class DispatcherTest extends \Test\TestCase { $this->http, $this->middlewareDispatcher, $this->reflector, $this->request, $this->config, - \OC::$server->getDatabaseConnection(), + Server::get(IDBConnection::class), $this->logger, $this->eventLogger, $this->container @@ -342,11 +319,11 @@ class DispatcherTest extends \Test\TestCase { $this->dispatcherPassthrough(); $response = $this->dispatcher->dispatch($controller, 'exec'); - $this->assertEquals('[3,true,4,1]', $response[3]); + $this->assertEquals('[3,false,4,1]', $response[3]); } - public function testControllerParametersInjectedDefaultOverwritten() { + public function testControllerParametersInjectedDefaultOverwritten(): void { $this->request = new Request( [ 'post' => [ @@ -364,7 +341,7 @@ class DispatcherTest extends \Test\TestCase { $this->http, $this->middlewareDispatcher, $this->reflector, $this->request, $this->config, - \OC::$server->getDatabaseConnection(), + Server::get(IDBConnection::class), $this->logger, $this->eventLogger, $this->container @@ -375,12 +352,12 @@ class DispatcherTest extends \Test\TestCase { $this->dispatcherPassthrough(); $response = $this->dispatcher->dispatch($controller, 'exec'); - $this->assertEquals('[3,true,4,7]', $response[3]); + $this->assertEquals('[3,false,4,7]', $response[3]); } - public function testResponseTransformedByUrlFormat() { + public function testResponseTransformedByUrlFormat(): void { $this->request = new Request( [ 'post' => [ @@ -400,7 +377,7 @@ class DispatcherTest extends \Test\TestCase { $this->http, $this->middlewareDispatcher, $this->reflector, $this->request, $this->config, - \OC::$server->getDatabaseConnection(), + Server::get(IDBConnection::class), $this->logger, $this->eventLogger, $this->container @@ -415,7 +392,7 @@ class DispatcherTest extends \Test\TestCase { } - public function testResponseTransformsDataResponse() { + public function testResponseTransformsDataResponse(): void { $this->request = new Request( [ 'post' => [ @@ -435,7 +412,7 @@ class DispatcherTest extends \Test\TestCase { $this->http, $this->middlewareDispatcher, $this->reflector, $this->request, $this->config, - \OC::$server->getDatabaseConnection(), + Server::get(IDBConnection::class), $this->logger, $this->eventLogger, $this->container @@ -450,7 +427,7 @@ class DispatcherTest extends \Test\TestCase { } - public function testResponseTransformedByAcceptHeader() { + public function testResponseTransformedByAcceptHeader(): void { $this->request = new Request( [ 'post' => [ @@ -471,7 +448,7 @@ class DispatcherTest extends \Test\TestCase { $this->http, $this->middlewareDispatcher, $this->reflector, $this->request, $this->config, - \OC::$server->getDatabaseConnection(), + Server::get(IDBConnection::class), $this->logger, $this->eventLogger, $this->container @@ -485,8 +462,43 @@ class DispatcherTest extends \Test\TestCase { $this->assertEquals('{"text":[3,false,4,1]}', $response[3]); } + public function testResponseTransformedBySendingMultipartFormData(): void { + $this->request = new Request( + [ + 'post' => [ + 'int' => '3', + 'bool' => 'false', + 'double' => 1.2, + ], + 'server' => [ + 'HTTP_ACCEPT' => 'application/text, test', + 'HTTP_CONTENT_TYPE' => 'multipart/form-data' + ], + 'method' => 'POST' + ], + $this->createMock(IRequestId::class), + $this->createMock(IConfig::class) + ); + $this->dispatcher = new Dispatcher( + $this->http, $this->middlewareDispatcher, $this->reflector, + $this->request, + $this->config, + Server::get(IDBConnection::class), + $this->logger, + $this->eventLogger, + $this->container + ); + $controller = new TestController('app', $this->request); - public function testResponsePrimarilyTransformedByParameterFormat() { + // reflector is supposed to be called once + $this->dispatcherPassthrough(); + $response = $this->dispatcher->dispatch($controller, 'exec'); + + $this->assertEquals('{"text":[3,false,4,1]}', $response[3]); + } + + + public function testResponsePrimarilyTransformedByParameterFormat(): void { $this->request = new Request( [ 'post' => [ @@ -509,7 +521,7 @@ class DispatcherTest extends \Test\TestCase { $this->http, $this->middlewareDispatcher, $this->reflector, $this->request, $this->config, - \OC::$server->getDatabaseConnection(), + Server::get(IDBConnection::class), $this->logger, $this->eventLogger, $this->container @@ -520,6 +532,51 @@ class DispatcherTest extends \Test\TestCase { $this->dispatcherPassthrough(); $response = $this->dispatcher->dispatch($controller, 'exec'); - $this->assertEquals('{"text":[3,true,4,1]}', $response[3]); + $this->assertEquals('{"text":[3,false,4,1]}', $response[3]); + } + + + public static function rangeDataProvider(): array { + return [ + [PHP_INT_MIN, PHP_INT_MAX, 42, false], + [0, 12, -5, true], + [-12, 0, 5, true], + [7, 14, 5, true], + [7, 14, 10, false], + [-14, -7, -10, false], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('rangeDataProvider')] + public function testEnsureParameterValueSatisfiesRange(int $min, int $max, int $input, bool $throw): void { + $this->reflector = $this->createMock(ControllerMethodReflector::class); + $this->reflector->expects($this->any()) + ->method('getRange') + ->willReturn([ + 'min' => $min, + 'max' => $max, + ]); + + $this->dispatcher = new Dispatcher( + $this->http, + $this->middlewareDispatcher, + $this->reflector, + $this->request, + $this->config, + Server::get(IDBConnection::class), + $this->logger, + $this->eventLogger, + $this->container, + ); + + if ($throw) { + $this->expectException(ParameterOutOfRangeException::class); + } + + $this->invokePrivate($this->dispatcher, 'ensureParameterValueSatisfiesRange', ['myArgument', $input]); + if (!$throw) { + // do not mark this test risky + $this->assertTrue(true); + } } } diff --git a/tests/lib/AppFramework/Http/DownloadResponseTest.php b/tests/lib/AppFramework/Http/DownloadResponseTest.php index 89de248cea0..b2f60edd999 100644 --- a/tests/lib/AppFramework/Http/DownloadResponseTest.php +++ b/tests/lib/AppFramework/Http/DownloadResponseTest.php @@ -1,24 +1,9 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Http; @@ -34,7 +19,7 @@ class DownloadResponseTest extends \Test\TestCase { parent::setUp(); } - public function testHeaders() { + public function testHeaders(): void { $response = new ChildDownloadResponse('file', 'content'); $headers = $response->getHeaders(); @@ -42,17 +27,15 @@ class DownloadResponseTest extends \Test\TestCase { $this->assertEquals('content', $headers['Content-Type']); } - /** - * @dataProvider filenameEncodingProvider - */ - public function testFilenameEncoding(string $input, string $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('filenameEncodingProvider')] + public function testFilenameEncoding(string $input, string $expected): void { $response = new ChildDownloadResponse($input, 'content'); $headers = $response->getHeaders(); - $this->assertEquals('attachment; filename="'.$expected.'"', $headers['Content-Disposition']); + $this->assertEquals('attachment; filename="' . $expected . '"', $headers['Content-Disposition']); } - public function filenameEncodingProvider() : array { + public static function filenameEncodingProvider() : array { return [ ['TestName.txt', 'TestName.txt'], ['A "Quoted" Filename.txt', 'A \\"Quoted\\" Filename.txt'], diff --git a/tests/lib/AppFramework/Http/EmptyContentSecurityPolicyTest.php b/tests/lib/AppFramework/Http/EmptyContentSecurityPolicyTest.php index 68e54886527..66abce43cc4 100644 --- a/tests/lib/AppFramework/Http/EmptyContentSecurityPolicyTest.php +++ b/tests/lib/AppFramework/Http/EmptyContentSecurityPolicyTest.php @@ -1,9 +1,9 @@ <?php + /** - * Copyright (c) 2015 Lukas Reschke lukas@owncloud.com - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\AppFramework\Http; @@ -24,443 +24,475 @@ class EmptyContentSecurityPolicyTest extends \Test\TestCase { $this->contentSecurityPolicy = new EmptyContentSecurityPolicy(); } - public function testGetPolicyDefault() { + public function testGetPolicyDefault(): void { $defaultPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; $this->assertSame($defaultPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyScriptDomainValid() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetPolicyScriptDomainValid(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyScriptDomainValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src www.owncloud.com www.owncloud.org;frame-ancestors 'none'"; + public function testGetPolicyScriptDomainValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src www.nextcloud.com www.nextcloud.org;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); - $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowScriptDomain() { + public function testGetPolicyDisallowScriptDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowScriptDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowScriptDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetPolicyDisallowScriptDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowScriptDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowScriptDomainMultipleStacked() { + public function testGetPolicyDisallowScriptDomainMultipleStacked(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowScriptDomain('www.owncloud.org')->disallowScriptDomain('www.owncloud.com'); - $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); - } - - public function testGetPolicyScriptAllowInline() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'unsafe-inline';frame-ancestors 'none'"; - - $this->contentSecurityPolicy->allowInlineScript(true); + $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowScriptDomain('www.nextcloud.org')->disallowScriptDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyScriptAllowInlineWithDomain() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src www.owncloud.com 'unsafe-inline';frame-ancestors 'none'"; + public function testGetPolicyScriptAllowEval(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'unsafe-eval';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedScriptDomain('www.owncloud.com'); - $this->contentSecurityPolicy->allowInlineScript(true); + $this->contentSecurityPolicy->allowEvalScript(true); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyScriptAllowInlineAndEval() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'unsafe-inline' 'unsafe-eval';frame-ancestors 'none'"; + public function testGetPolicyScriptAllowWasmEval(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'wasm-unsafe-eval';frame-ancestors 'none'"; - $this->contentSecurityPolicy->allowInlineScript(true); - $this->contentSecurityPolicy->allowEvalScript(true); + $this->contentSecurityPolicy->allowEvalWasm(true); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyStyleDomainValid() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';style-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetPolicyStyleDomainValid(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';style-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedStyleDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyStyleDomainValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';style-src www.owncloud.com www.owncloud.org;frame-ancestors 'none'"; + public function testGetPolicyStyleDomainValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';style-src www.nextcloud.com www.nextcloud.org;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); - $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedStyleDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedStyleDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowStyleDomain() { + public function testGetPolicyDisallowStyleDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedStyleDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowStyleDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowStyleDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';style-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetPolicyDisallowStyleDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';style-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedStyleDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowStyleDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowStyleDomainMultipleStacked() { + public function testGetPolicyDisallowStyleDomainMultipleStacked(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowStyleDomain('www.owncloud.org')->disallowStyleDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedStyleDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowStyleDomain('www.nextcloud.org')->disallowStyleDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyStyleAllowInline() { + public function testGetPolicyStyleAllowInline(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';style-src 'unsafe-inline';frame-ancestors 'none'"; $this->contentSecurityPolicy->allowInlineStyle(true); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyStyleAllowInlineWithDomain() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';style-src www.owncloud.com 'unsafe-inline';frame-ancestors 'none'"; + public function testGetPolicyStyleAllowInlineWithDomain(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';style-src www.nextcloud.com 'unsafe-inline';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedStyleDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedStyleDomain('www.nextcloud.com'); $this->contentSecurityPolicy->allowInlineStyle(true); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyStyleDisallowInline() { + public function testGetPolicyStyleDisallowInline(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; $this->contentSecurityPolicy->allowInlineStyle(false); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyImageDomainValid() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';img-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetPolicyImageDomainValid(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';img-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedImageDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyImageDomainValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';img-src www.owncloud.com www.owncloud.org;frame-ancestors 'none'"; + public function testGetPolicyImageDomainValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';img-src www.nextcloud.com www.nextcloud.org;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); - $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedImageDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedImageDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowImageDomain() { + public function testGetPolicyDisallowImageDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowImageDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedImageDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowImageDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowImageDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';img-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetPolicyDisallowImageDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';img-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowImageDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedImageDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowImageDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowImageDomainMultipleStakes() { + public function testGetPolicyDisallowImageDomainMultipleStakes(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedImageDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowImageDomain('www.owncloud.org')->disallowImageDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedImageDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowImageDomain('www.nextcloud.org')->disallowImageDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyFontDomainValid() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';font-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetPolicyFontDomainValid(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';font-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedFontDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyFontDomainValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';font-src www.owncloud.com www.owncloud.org;frame-ancestors 'none'"; + public function testGetPolicyFontDomainValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';font-src www.nextcloud.com www.nextcloud.org;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); - $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedFontDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedFontDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowFontDomain() { + public function testGetPolicyDisallowFontDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowFontDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedFontDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowFontDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowFontDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';font-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetPolicyDisallowFontDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';font-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowFontDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedFontDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowFontDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowFontDomainMultipleStakes() { + public function testGetPolicyDisallowFontDomainMultipleStakes(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedFontDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowFontDomain('www.owncloud.org')->disallowFontDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedFontDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowFontDomain('www.nextcloud.org')->disallowFontDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyConnectDomainValid() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';connect-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetPolicyConnectDomainValid(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';connect-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedConnectDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyConnectDomainValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';connect-src www.owncloud.com www.owncloud.org;frame-ancestors 'none'"; + public function testGetPolicyConnectDomainValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';connect-src www.nextcloud.com www.nextcloud.org;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); - $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedConnectDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedConnectDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowConnectDomain() { + public function testGetPolicyDisallowConnectDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedConnectDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowConnectDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowConnectDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';connect-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetPolicyDisallowConnectDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';connect-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedConnectDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowConnectDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowConnectDomainMultipleStakes() { + public function testGetPolicyDisallowConnectDomainMultipleStakes(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedConnectDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowConnectDomain('www.owncloud.org')->disallowConnectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedConnectDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowConnectDomain('www.nextcloud.org')->disallowConnectDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyMediaDomainValid() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';media-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetPolicyMediaDomainValid(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';media-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedMediaDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyMediaDomainValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';media-src www.owncloud.com www.owncloud.org;frame-ancestors 'none'"; + public function testGetPolicyMediaDomainValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';media-src www.nextcloud.com www.nextcloud.org;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); - $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedMediaDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedMediaDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowMediaDomain() { + public function testGetPolicyDisallowMediaDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedMediaDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowMediaDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowMediaDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';media-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetPolicyDisallowMediaDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';media-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedMediaDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowMediaDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowMediaDomainMultipleStakes() { + public function testGetPolicyDisallowMediaDomainMultipleStakes(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedMediaDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowMediaDomain('www.owncloud.org')->disallowMediaDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedMediaDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowMediaDomain('www.nextcloud.org')->disallowMediaDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyObjectDomainValid() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';object-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetPolicyObjectDomainValid(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';object-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedObjectDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyObjectDomainValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';object-src www.owncloud.com www.owncloud.org;frame-ancestors 'none'"; + public function testGetPolicyObjectDomainValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';object-src www.nextcloud.com www.nextcloud.org;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); - $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedObjectDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedObjectDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowObjectDomain() { + public function testGetPolicyDisallowObjectDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedObjectDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowObjectDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowObjectDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';object-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetPolicyDisallowObjectDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';object-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedObjectDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowObjectDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowObjectDomainMultipleStakes() { + public function testGetPolicyDisallowObjectDomainMultipleStakes(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedObjectDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowObjectDomain('www.owncloud.org')->disallowObjectDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedObjectDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowObjectDomain('www.nextcloud.org')->disallowObjectDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetAllowedFrameDomain() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetAllowedFrameDomain(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedFrameDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyFrameDomainValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-src www.owncloud.com www.owncloud.org;frame-ancestors 'none'"; + public function testGetPolicyFrameDomainValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-src www.nextcloud.com www.nextcloud.org;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); - $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedFrameDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedFrameDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowFrameDomain() { + public function testGetPolicyDisallowFrameDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedFrameDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowFrameDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowFrameDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetPolicyDisallowFrameDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedFrameDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowFrameDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowFrameDomainMultipleStakes() { + public function testGetPolicyDisallowFrameDomainMultipleStakes(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedFrameDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowFrameDomain('www.owncloud.org')->disallowFrameDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedFrameDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowFrameDomain('www.nextcloud.org')->disallowFrameDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetAllowedChildSrcDomain() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';child-src child.owncloud.com;frame-ancestors 'none'"; + public function testGetAllowedChildSrcDomain(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';child-src child.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.owncloud.com'); + $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyChildSrcValidMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';child-src child.owncloud.com child.owncloud.org;frame-ancestors 'none'"; + public function testGetPolicyChildSrcValidMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';child-src child.nextcloud.com child.nextcloud.org;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.owncloud.com'); - $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.owncloud.org'); + $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.nextcloud.com'); + $this->contentSecurityPolicy->addAllowedChildSrcDomain('child.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowChildSrcDomain() { + public function testGetPolicyDisallowChildSrcDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowChildSrcDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowChildSrcDomainMultiple() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';child-src www.owncloud.com;frame-ancestors 'none'"; + public function testGetPolicyDisallowChildSrcDomainMultiple(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';child-src www.nextcloud.com;frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.org'); + $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowChildSrcDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyDisallowChildSrcDomainMultipleStakes() { + public function testGetPolicyDisallowChildSrcDomainMultipleStakes(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; - $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.owncloud.com'); - $this->contentSecurityPolicy->disallowChildSrcDomain('www.owncloud.org')->disallowChildSrcDomain('www.owncloud.com'); + $this->contentSecurityPolicy->addAllowedChildSrcDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->disallowChildSrcDomain('www.nextcloud.org')->disallowChildSrcDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyWithJsNonceAndScriptDomains() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'nonce-TXlKc05vbmNl' www.nextcloud.com www.nextcloud.org;frame-ancestors 'none'"; + public function testGetPolicyWithJsNonceAndScriptDomains(): void { + $nonce = base64_encode('MyJsNonce'); + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'nonce-$nonce' www.nextcloud.com www.nextcloud.org;frame-ancestors 'none'"; $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.com'); - $this->contentSecurityPolicy->useJsNonce('MyJsNonce'); + $this->contentSecurityPolicy->useJsNonce($nonce); $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.org'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyWithJsNonceAndSelfScriptDomain() { - $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'nonce-TXlKc05vbmNl';frame-ancestors 'none'"; + public function testGetPolicyWithJsNonceAndStrictDynamic(): void { + $nonce = base64_encode('MyJsNonce'); + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'strict-dynamic' 'nonce-$nonce' www.nextcloud.com;frame-ancestors 'none'"; + + $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->useStrictDynamic(true); + $this->contentSecurityPolicy->useJsNonce($nonce); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyWithJsNonceAndStrictDynamicAndStrictDynamicOnScripts(): void { + $nonce = base64_encode('MyJsNonce'); + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'strict-dynamic' 'nonce-$nonce' www.nextcloud.com;frame-ancestors 'none'"; + + $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->useStrictDynamic(true); + $this->contentSecurityPolicy->useStrictDynamicOnScripts(true); + $this->contentSecurityPolicy->useJsNonce($nonce); + // Should be same as `testGetPolicyWithJsNonceAndStrictDynamic` because of fallback + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyWithJsNonceAndStrictDynamicOnScripts(): void { + $nonce = base64_encode('MyJsNonce'); + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'nonce-$nonce' www.nextcloud.com;script-src-elem 'strict-dynamic' 'nonce-$nonce' www.nextcloud.com;frame-ancestors 'none'"; + + $this->contentSecurityPolicy->addAllowedScriptDomain('www.nextcloud.com'); + $this->contentSecurityPolicy->useStrictDynamicOnScripts(true); + $this->contentSecurityPolicy->useJsNonce($nonce); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyWithStrictDynamicOnScripts(): void { + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; + + $this->contentSecurityPolicy->useStrictDynamicOnScripts(true); + $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); + } + + public function testGetPolicyWithJsNonceAndSelfScriptDomain(): void { + $nonce = base64_encode('MyJsNonce'); + $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'nonce-$nonce';frame-ancestors 'none'"; - $this->contentSecurityPolicy->useJsNonce('MyJsNonce'); + $this->contentSecurityPolicy->useJsNonce($nonce); $this->contentSecurityPolicy->addAllowedScriptDomain("'self'"); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyWithoutJsNonceAndSelfScriptDomain() { + public function testGetPolicyWithoutJsNonceAndSelfScriptDomain(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self';frame-ancestors 'none'"; $this->contentSecurityPolicy->addAllowedScriptDomain("'self'"); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyWithReportUri() { + public function testGetPolicyWithReportUri(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none';report-uri https://my-report-uri.com"; - $this->contentSecurityPolicy->addReportTo("https://my-report-uri.com"); + $this->contentSecurityPolicy->addReportTo('https://my-report-uri.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } - public function testGetPolicyWithMultipleReportUri() { + public function testGetPolicyWithMultipleReportUri(): void { $expectedPolicy = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none';report-uri https://my-report-uri.com https://my-other-report-uri.com"; - $this->contentSecurityPolicy->addReportTo("https://my-report-uri.com"); - $this->contentSecurityPolicy->addReportTo("https://my-other-report-uri.com"); + $this->contentSecurityPolicy->addReportTo('https://my-report-uri.com'); + $this->contentSecurityPolicy->addReportTo('https://my-other-report-uri.com'); $this->assertSame($expectedPolicy, $this->contentSecurityPolicy->buildPolicy()); } } diff --git a/tests/lib/AppFramework/Http/EmptyFeaturePolicyTest.php b/tests/lib/AppFramework/Http/EmptyFeaturePolicyTest.php index 6ced435286c..71342485552 100644 --- a/tests/lib/AppFramework/Http/EmptyFeaturePolicyTest.php +++ b/tests/lib/AppFramework/Http/EmptyFeaturePolicyTest.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\AppFramework\Http; @@ -36,19 +19,19 @@ class EmptyFeaturePolicyTest extends \Test\TestCase { $this->policy = new EmptyFeaturePolicy(); } - public function testGetPolicyDefault() { + public function testGetPolicyDefault(): void { $defaultPolicy = "autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone 'none';payment 'none'"; $this->assertSame($defaultPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyAutoplayDomainValid() { + public function testGetPolicyAutoplayDomainValid(): void { $expectedPolicy = "autoplay www.nextcloud.com;camera 'none';fullscreen 'none';geolocation 'none';microphone 'none';payment 'none'"; $this->policy->addAllowedAutoplayDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyAutoplayDomainValidMultiple() { + public function testGetPolicyAutoplayDomainValidMultiple(): void { $expectedPolicy = "autoplay www.nextcloud.com www.nextcloud.org;camera 'none';fullscreen 'none';geolocation 'none';microphone 'none';payment 'none'"; $this->policy->addAllowedAutoplayDomain('www.nextcloud.com'); @@ -56,14 +39,14 @@ class EmptyFeaturePolicyTest extends \Test\TestCase { $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyCameraDomainValid() { + public function testGetPolicyCameraDomainValid(): void { $expectedPolicy = "autoplay 'none';camera www.nextcloud.com;fullscreen 'none';geolocation 'none';microphone 'none';payment 'none'"; $this->policy->addAllowedCameraDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyCameraDomainValidMultiple() { + public function testGetPolicyCameraDomainValidMultiple(): void { $expectedPolicy = "autoplay 'none';camera www.nextcloud.com www.nextcloud.org;fullscreen 'none';geolocation 'none';microphone 'none';payment 'none'"; $this->policy->addAllowedCameraDomain('www.nextcloud.com'); @@ -71,14 +54,14 @@ class EmptyFeaturePolicyTest extends \Test\TestCase { $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyFullScreenDomainValid() { + public function testGetPolicyFullScreenDomainValid(): void { $expectedPolicy = "autoplay 'none';camera 'none';fullscreen www.nextcloud.com;geolocation 'none';microphone 'none';payment 'none'"; $this->policy->addAllowedFullScreenDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyFullScreenDomainValidMultiple() { + public function testGetPolicyFullScreenDomainValidMultiple(): void { $expectedPolicy = "autoplay 'none';camera 'none';fullscreen www.nextcloud.com www.nextcloud.org;geolocation 'none';microphone 'none';payment 'none'"; $this->policy->addAllowedFullScreenDomain('www.nextcloud.com'); @@ -86,14 +69,14 @@ class EmptyFeaturePolicyTest extends \Test\TestCase { $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyGeoLocationDomainValid() { + public function testGetPolicyGeoLocationDomainValid(): void { $expectedPolicy = "autoplay 'none';camera 'none';fullscreen 'none';geolocation www.nextcloud.com;microphone 'none';payment 'none'"; $this->policy->addAllowedGeoLocationDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyGeoLocationDomainValidMultiple() { + public function testGetPolicyGeoLocationDomainValidMultiple(): void { $expectedPolicy = "autoplay 'none';camera 'none';fullscreen 'none';geolocation www.nextcloud.com www.nextcloud.org;microphone 'none';payment 'none'"; $this->policy->addAllowedGeoLocationDomain('www.nextcloud.com'); @@ -101,14 +84,14 @@ class EmptyFeaturePolicyTest extends \Test\TestCase { $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyMicrophoneDomainValid() { + public function testGetPolicyMicrophoneDomainValid(): void { $expectedPolicy = "autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone www.nextcloud.com;payment 'none'"; $this->policy->addAllowedMicrophoneDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyMicrophoneDomainValidMultiple() { + public function testGetPolicyMicrophoneDomainValidMultiple(): void { $expectedPolicy = "autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone www.nextcloud.com www.nextcloud.org;payment 'none'"; $this->policy->addAllowedMicrophoneDomain('www.nextcloud.com'); @@ -116,14 +99,14 @@ class EmptyFeaturePolicyTest extends \Test\TestCase { $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyPaymentDomainValid() { + public function testGetPolicyPaymentDomainValid(): void { $expectedPolicy = "autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone 'none';payment www.nextcloud.com"; $this->policy->addAllowedPaymentDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyPaymentDomainValidMultiple() { + public function testGetPolicyPaymentDomainValidMultiple(): void { $expectedPolicy = "autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone 'none';payment www.nextcloud.com www.nextcloud.org"; $this->policy->addAllowedPaymentDomain('www.nextcloud.com'); diff --git a/tests/lib/AppFramework/Http/FeaturePolicyTest.php b/tests/lib/AppFramework/Http/FeaturePolicyTest.php index 60ddca7481b..6ea990fb111 100644 --- a/tests/lib/AppFramework/Http/FeaturePolicyTest.php +++ b/tests/lib/AppFramework/Http/FeaturePolicyTest.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\AppFramework\Http; @@ -36,19 +19,19 @@ class FeaturePolicyTest extends \Test\TestCase { $this->policy = new FeaturePolicy(); } - public function testGetPolicyDefault() { + public function testGetPolicyDefault(): void { $defaultPolicy = "autoplay 'self';camera 'none';fullscreen 'self';geolocation 'none';microphone 'none';payment 'none'"; $this->assertSame($defaultPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyAutoplayDomainValid() { + public function testGetPolicyAutoplayDomainValid(): void { $expectedPolicy = "autoplay 'self' www.nextcloud.com;camera 'none';fullscreen 'self';geolocation 'none';microphone 'none';payment 'none'"; $this->policy->addAllowedAutoplayDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyAutoplayDomainValidMultiple() { + public function testGetPolicyAutoplayDomainValidMultiple(): void { $expectedPolicy = "autoplay 'self' www.nextcloud.com www.nextcloud.org;camera 'none';fullscreen 'self';geolocation 'none';microphone 'none';payment 'none'"; $this->policy->addAllowedAutoplayDomain('www.nextcloud.com'); @@ -56,14 +39,14 @@ class FeaturePolicyTest extends \Test\TestCase { $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyCameraDomainValid() { + public function testGetPolicyCameraDomainValid(): void { $expectedPolicy = "autoplay 'self';camera www.nextcloud.com;fullscreen 'self';geolocation 'none';microphone 'none';payment 'none'"; $this->policy->addAllowedCameraDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyCameraDomainValidMultiple() { + public function testGetPolicyCameraDomainValidMultiple(): void { $expectedPolicy = "autoplay 'self';camera www.nextcloud.com www.nextcloud.org;fullscreen 'self';geolocation 'none';microphone 'none';payment 'none'"; $this->policy->addAllowedCameraDomain('www.nextcloud.com'); @@ -71,14 +54,14 @@ class FeaturePolicyTest extends \Test\TestCase { $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyFullScreenDomainValid() { + public function testGetPolicyFullScreenDomainValid(): void { $expectedPolicy = "autoplay 'self';camera 'none';fullscreen 'self' www.nextcloud.com;geolocation 'none';microphone 'none';payment 'none'"; $this->policy->addAllowedFullScreenDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyFullScreenDomainValidMultiple() { + public function testGetPolicyFullScreenDomainValidMultiple(): void { $expectedPolicy = "autoplay 'self';camera 'none';fullscreen 'self' www.nextcloud.com www.nextcloud.org;geolocation 'none';microphone 'none';payment 'none'"; $this->policy->addAllowedFullScreenDomain('www.nextcloud.com'); @@ -86,14 +69,14 @@ class FeaturePolicyTest extends \Test\TestCase { $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyGeoLocationDomainValid() { + public function testGetPolicyGeoLocationDomainValid(): void { $expectedPolicy = "autoplay 'self';camera 'none';fullscreen 'self';geolocation www.nextcloud.com;microphone 'none';payment 'none'"; $this->policy->addAllowedGeoLocationDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyGeoLocationDomainValidMultiple() { + public function testGetPolicyGeoLocationDomainValidMultiple(): void { $expectedPolicy = "autoplay 'self';camera 'none';fullscreen 'self';geolocation www.nextcloud.com www.nextcloud.org;microphone 'none';payment 'none'"; $this->policy->addAllowedGeoLocationDomain('www.nextcloud.com'); @@ -101,14 +84,14 @@ class FeaturePolicyTest extends \Test\TestCase { $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyMicrophoneDomainValid() { + public function testGetPolicyMicrophoneDomainValid(): void { $expectedPolicy = "autoplay 'self';camera 'none';fullscreen 'self';geolocation 'none';microphone www.nextcloud.com;payment 'none'"; $this->policy->addAllowedMicrophoneDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyMicrophoneDomainValidMultiple() { + public function testGetPolicyMicrophoneDomainValidMultiple(): void { $expectedPolicy = "autoplay 'self';camera 'none';fullscreen 'self';geolocation 'none';microphone www.nextcloud.com www.nextcloud.org;payment 'none'"; $this->policy->addAllowedMicrophoneDomain('www.nextcloud.com'); @@ -116,14 +99,14 @@ class FeaturePolicyTest extends \Test\TestCase { $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyPaymentDomainValid() { + public function testGetPolicyPaymentDomainValid(): void { $expectedPolicy = "autoplay 'self';camera 'none';fullscreen 'self';geolocation 'none';microphone 'none';payment www.nextcloud.com"; $this->policy->addAllowedPaymentDomain('www.nextcloud.com'); $this->assertSame($expectedPolicy, $this->policy->buildPolicy()); } - public function testGetPolicyPaymentDomainValidMultiple() { + public function testGetPolicyPaymentDomainValidMultiple(): void { $expectedPolicy = "autoplay 'self';camera 'none';fullscreen 'self';geolocation 'none';microphone 'none';payment www.nextcloud.com www.nextcloud.org"; $this->policy->addAllowedPaymentDomain('www.nextcloud.com'); diff --git a/tests/lib/AppFramework/Http/FileDisplayResponseTest.php b/tests/lib/AppFramework/Http/FileDisplayResponseTest.php index 0a244a85754..029ddaad712 100644 --- a/tests/lib/AppFramework/Http/FileDisplayResponseTest.php +++ b/tests/lib/AppFramework/Http/FileDisplayResponseTest.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\AppFramework\Http; @@ -51,23 +35,23 @@ class FileDisplayResponseTest extends \Test\TestCase { $this->response = new FileDisplayResponse($this->file); } - public function testHeader() { + public function testHeader(): void { $headers = $this->response->getHeaders(); $this->assertArrayHasKey('Content-Disposition', $headers); $this->assertSame('inline; filename="myFileName"', $headers['Content-Disposition']); } - public function testETag() { + public function testETag(): void { $this->assertSame('myETag', $this->response->getETag()); } - public function testLastModified() { + public function testLastModified(): void { $lastModified = $this->response->getLastModified(); $this->assertNotNull($lastModified); $this->assertSame(1464825600, $lastModified->getTimestamp()); } - public function test304() { + public function test304(): void { $output = $this->getMockBuilder('OCP\AppFramework\Http\IOutput') ->disableOriginalConstructor() ->getMock(); @@ -84,7 +68,7 @@ class FileDisplayResponseTest extends \Test\TestCase { } - public function testNon304() { + public function testNon304(): void { $output = $this->getMockBuilder('OCP\AppFramework\Http\IOutput') ->disableOriginalConstructor() ->getMock(); diff --git a/tests/lib/AppFramework/Http/HttpTest.php b/tests/lib/AppFramework/Http/HttpTest.php index d3d23425f7c..d3ec8438554 100644 --- a/tests/lib/AppFramework/Http/HttpTest.php +++ b/tests/lib/AppFramework/Http/HttpTest.php @@ -1,24 +1,9 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Http; @@ -41,19 +26,19 @@ class HttpTest extends \Test\TestCase { } - public function testProtocol() { + public function testProtocol(): void { $header = $this->http->getStatusHeader(Http::STATUS_TEMPORARY_REDIRECT); $this->assertEquals('HTTP/1.1 307 Temporary Redirect', $header); } - public function testProtocol10() { + public function testProtocol10(): void { $this->http = new Http($this->server, 'HTTP/1.0'); $header = $this->http->getStatusHeader(Http::STATUS_OK); $this->assertEquals('HTTP/1.0 200 OK', $header); } - public function testTempRedirectBecomesFoundInHttp10() { + public function testTempRedirectBecomesFoundInHttp10(): void { $http = new Http([], 'HTTP/1.0'); $header = $http->getStatusHeader(Http::STATUS_TEMPORARY_REDIRECT); diff --git a/tests/lib/AppFramework/Http/JSONResponseTest.php b/tests/lib/AppFramework/Http/JSONResponseTest.php index 82f00457907..56f67b23f0d 100644 --- a/tests/lib/AppFramework/Http/JSONResponseTest.php +++ b/tests/lib/AppFramework/Http/JSONResponseTest.php @@ -1,26 +1,9 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @author Morris Jobke - * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com> - * @copyright 2013 Morris Jobke <morris.jobke@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Http; @@ -40,13 +23,13 @@ class JSONResponseTest extends \Test\TestCase { } - public function testHeader() { + public function testHeader(): void { $headers = $this->json->getHeaders(); $this->assertEquals('application/json; charset=utf-8', $headers['Content-Type']); } - public function testSetData() { + public function testSetData(): void { $params = ['hi', 'yo']; $this->json->setData($params); @@ -54,7 +37,7 @@ class JSONResponseTest extends \Test\TestCase { } - public function testSetRender() { + public function testSetRender(): void { $params = ['test' => 'hi']; $this->json->setData($params); @@ -63,10 +46,7 @@ class JSONResponseTest extends \Test\TestCase { $this->assertEquals($expected, $this->json->render()); } - /** - * @return array - */ - public function renderDataProvider() { + public static function renderDataProvider(): array { return [ [ ['test' => 'hi'], '{"test":"hi"}', @@ -78,17 +58,17 @@ class JSONResponseTest extends \Test\TestCase { } /** - * @dataProvider renderDataProvider * @param array $input * @param string $expected */ - public function testRender(array $input, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('renderDataProvider')] + public function testRender(array $input, $expected): void { $this->json->setData($input); $this->assertEquals($expected, $this->json->render()); } - public function testRenderWithNonUtf8Encoding() { + public function testRenderWithNonUtf8Encoding(): void { $this->expectException(\JsonException::class); $this->expectExceptionMessage('Malformed UTF-8 characters, possibly incorrectly encoded'); @@ -97,7 +77,7 @@ class JSONResponseTest extends \Test\TestCase { $this->json->render(); } - public function testConstructorAllowsToSetData() { + public function testConstructorAllowsToSetData(): void { $data = ['hi']; $code = 300; $response = new JSONResponse($data, $code); @@ -107,7 +87,7 @@ class JSONResponseTest extends \Test\TestCase { $this->assertEquals($code, $response->getStatus()); } - public function testChainability() { + public function testChainability(): void { $params = ['hi', 'yo']; $this->json->setData($params) ->setStatus(Http::STATUS_NOT_FOUND); diff --git a/tests/lib/AppFramework/Http/OutputTest.php b/tests/lib/AppFramework/Http/OutputTest.php index 5fe35d24bde..2ba93833dd1 100644 --- a/tests/lib/AppFramework/Http/OutputTest.php +++ b/tests/lib/AppFramework/Http/OutputTest.php @@ -1,9 +1,8 @@ <?php + /** - * Copyright (c) 2016 Robin Appelman <robin@icewind.nl> - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\AppFramework\Http; @@ -11,19 +10,19 @@ namespace Test\AppFramework\Http; use OC\AppFramework\Http\Output; class OutputTest extends \Test\TestCase { - public function testSetOutput() { + public function testSetOutput(): void { $this->expectOutputString('foo'); $output = new Output(''); $output->setOutput('foo'); } - public function testSetReadfile() { + public function testSetReadfile(): void { $this->expectOutputString(file_get_contents(__FILE__)); $output = new Output(''); $output->setReadfile(__FILE__); } - public function testSetReadfileStream() { + public function testSetReadfileStream(): void { $this->expectOutputString(file_get_contents(__FILE__)); $output = new Output(''); $output->setReadfile(fopen(__FILE__, 'r')); diff --git a/tests/lib/AppFramework/Http/PublicTemplateResponseTest.php b/tests/lib/AppFramework/Http/PublicTemplateResponseTest.php index cbf8f8303c3..cb7bd97f5da 100644 --- a/tests/lib/AppFramework/Http/PublicTemplateResponseTest.php +++ b/tests/lib/AppFramework/Http/PublicTemplateResponseTest.php @@ -1,41 +1,23 @@ <?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 Test\AppFramework\Http; -use OCP\AppFramework\Http; use OCP\AppFramework\Http\Template\PublicTemplateResponse; +use OCP\AppFramework\Http\Template\SimpleMenuAction; use Test\TestCase; class PublicTemplateResponseTest extends TestCase { - public function testSetParamsConstructor() { + public function testSetParamsConstructor(): void { $template = new PublicTemplateResponse('app', 'home', ['key' => 'value']); - $this->assertContains('core/js/public/publicpage', \OC_Util::$scripts); $this->assertEquals(['key' => 'value'], $template->getParams()); } - public function testAdditionalElements() { + public function testAdditionalElements(): void { $template = new PublicTemplateResponse('app', 'home', ['key' => 'value']); $template->setHeaderTitle('Header'); $template->setHeaderDetails('Details'); @@ -44,9 +26,9 @@ class PublicTemplateResponseTest extends TestCase { $this->assertEquals('Details', $template->getHeaderDetails()); } - public function testActionSingle() { + public function testActionSingle(): void { $actions = [ - new Http\Template\SimpleMenuAction('link', 'Download', 'download', 'downloadLink', 0) + new SimpleMenuAction('link', 'Download', 'download', 'downloadLink', 0) ]; $template = new PublicTemplateResponse('app', 'home', ['key' => 'value']); $template->setHeaderActions($actions); @@ -57,11 +39,11 @@ class PublicTemplateResponseTest extends TestCase { } - public function testActionMultiple() { + public function testActionMultiple(): void { $actions = [ - new Http\Template\SimpleMenuAction('link1', 'Download1', 'download1', 'downloadLink1', 100), - new Http\Template\SimpleMenuAction('link2', 'Download2', 'download2', 'downloadLink2', 20), - new Http\Template\SimpleMenuAction('link3', 'Download3', 'download3', 'downloadLink3', 0) + new SimpleMenuAction('link1', 'Download1', 'download1', 'downloadLink1', 100), + new SimpleMenuAction('link2', 'Download2', 'download2', 'downloadLink2', 20), + new SimpleMenuAction('link3', 'Download3', 'download3', 'downloadLink3', 0) ]; $template = new PublicTemplateResponse('app', 'home', ['key' => 'value']); $template->setHeaderActions($actions); @@ -72,9 +54,8 @@ class PublicTemplateResponseTest extends TestCase { } - public function testGetRenderAs() { + public function testGetRenderAs(): void { $template = new PublicTemplateResponse('app', 'home', ['key' => 'value']); - $this->assertContains('core/js/public/publicpage', \OC_Util::$scripts); $this->assertEquals(['key' => 'value'], $template->getParams()); $this->assertEquals('public', $template->getRenderAs()); } diff --git a/tests/lib/AppFramework/Http/RedirectResponseTest.php b/tests/lib/AppFramework/Http/RedirectResponseTest.php index c49c4a7c1f7..f6319782e79 100644 --- a/tests/lib/AppFramework/Http/RedirectResponseTest.php +++ b/tests/lib/AppFramework/Http/RedirectResponseTest.php @@ -1,24 +1,9 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Http; @@ -38,7 +23,7 @@ class RedirectResponseTest extends \Test\TestCase { } - public function testHeaders() { + public function testHeaders(): void { $headers = $this->response->getHeaders(); $this->assertEquals('/url', $headers['Location']); $this->assertEquals(Http::STATUS_SEE_OTHER, @@ -46,7 +31,7 @@ class RedirectResponseTest extends \Test\TestCase { } - public function testGetRedirectUrl() { + public function testGetRedirectUrl(): void { $this->assertEquals('/url', $this->response->getRedirectUrl()); } } diff --git a/tests/lib/AppFramework/Http/RequestIdTest.php b/tests/lib/AppFramework/Http/RequestIdTest.php index 9f9afed4b7f..9cfd3b1785c 100644 --- a/tests/lib/AppFramework/Http/RequestIdTest.php +++ b/tests/lib/AppFramework/Http/RequestIdTest.php @@ -2,23 +2,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com> - * - * @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: 2022 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\AppFramework\Http; @@ -64,11 +49,7 @@ class RequestIdTest extends \Test\TestCase { $this->secureRandom->expects($this->once()) ->method('generate') ->with('20') - ->willReturnOnConsecutiveCalls( - 'GeneratedByNextcloudItself1', - 'GeneratedByNextcloudItself2', - 'GeneratedByNextcloudItself3' - ); + ->willReturn('GeneratedByNextcloudItself1'); $this->assertSame('GeneratedByNextcloudItself1', $requestId->getId()); $this->assertSame('GeneratedByNextcloudItself1', $requestId->getId()); diff --git a/tests/lib/AppFramework/Http/RequestStream.php b/tests/lib/AppFramework/Http/RequestStream.php index 1a99685e340..7340391b2d5 100644 --- a/tests/lib/AppFramework/Http/RequestStream.php +++ b/tests/lib/AppFramework/Http/RequestStream.php @@ -1,5 +1,9 @@ <?php +/** + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ namespace Test\AppFramework\Http; /** @@ -14,7 +18,7 @@ class RequestStream { public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool { $url = parse_url($path); - $this->varname = $url["host"] ?? ''; + $this->varname = $url['host'] ?? ''; $this->position = 0; return true; @@ -101,7 +105,7 @@ class RequestStream { public function stream_metadata(string $path, int $option, $var): bool { if ($option == STREAM_META_TOUCH) { $url = parse_url($path); - $varname = $url["host"] ?? ''; + $varname = $url['host'] ?? ''; if (!isset($GLOBALS[$varname])) { $GLOBALS[$varname] = ''; } diff --git a/tests/lib/AppFramework/Http/RequestTest.php b/tests/lib/AppFramework/Http/RequestTest.php index 78e656f5fc3..7ea2cb31482 100644 --- a/tests/lib/AppFramework/Http/RequestTest.php +++ b/tests/lib/AppFramework/Http/RequestTest.php @@ -1,14 +1,10 @@ <?php + /** - * @copyright 2013 Thomas Tanghus (thomas@tanghus.net) - * @copyright 2016 Lukas Reschke lukas@owncloud.com - * @copyright 2022 Stanimir Bozhilov (stanimir@audriga.com) - * - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace Test\AppFramework\Http; use OC\AppFramework\Http\Request; @@ -52,7 +48,7 @@ class RequestTest extends \Test\TestCase { parent::tearDown(); } - public function testRequestAccessors() { + public function testRequestAccessors(): void { $vars = [ 'get' => ['name' => 'John Q. Public', 'nickname' => 'Joey'], 'method' => 'GET', @@ -82,7 +78,7 @@ class RequestTest extends \Test\TestCase { } // urlParams has precedence over POST which has precedence over GET - public function testPrecedence() { + public function testPrecedence(): void { $vars = [ 'get' => ['name' => 'John Q. Public', 'nickname' => 'Joey'], 'post' => ['name' => 'Jane Doe', 'nickname' => 'Janey'], @@ -105,7 +101,7 @@ class RequestTest extends \Test\TestCase { - public function testImmutableArrayAccess() { + public function testImmutableArrayAccess(): void { $this->expectException(\RuntimeException::class); $vars = [ @@ -125,7 +121,7 @@ class RequestTest extends \Test\TestCase { } - public function testImmutableMagicAccess() { + public function testImmutableMagicAccess(): void { $this->expectException(\RuntimeException::class); $vars = [ @@ -145,7 +141,7 @@ class RequestTest extends \Test\TestCase { } - public function testGetTheMethodRight() { + public function testGetTheMethodRight(): void { $this->expectException(\LogicException::class); $vars = [ @@ -164,7 +160,7 @@ class RequestTest extends \Test\TestCase { $request->post; } - public function testTheMethodIsRight() { + public function testTheMethodIsRight(): void { $vars = [ 'get' => ['name' => 'John Q. Public', 'nickname' => 'Joey'], 'method' => 'GET', @@ -184,7 +180,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('Joey', $result['nickname']); } - public function testJsonPost() { + public function testJsonPost(): void { global $data; $data = '{"name": "John Q. Public", "nickname": "Joey"}'; $vars = [ @@ -208,7 +204,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('Joey', $request['nickname']); } - public function testScimJsonPost() { + public function testScimJsonPost(): void { global $data; $data = '{"userName":"testusername", "displayName":"Example User"}'; $vars = [ @@ -232,7 +228,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('Example User', $request['displayName']); } - public function testCustomJsonPost() { + public function testCustomJsonPost(): void { global $data; $data = '{"propertyA":"sometestvalue", "propertyB":"someothertestvalue"}'; @@ -256,7 +252,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('someothertestvalue', $result['propertyB']); } - public function notJsonDataProvider() { + public static function dataNotJsonData(): array { return [ ['this is not valid json'], ['"just a string"'], @@ -264,10 +260,8 @@ class RequestTest extends \Test\TestCase { ]; } - /** - * @dataProvider notJsonDataProvider - */ - public function testNotJsonPost($testData) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataNotJsonData')] + public function testNotJsonPost(string $testData): void { global $data; $data = $testData; $vars = [ @@ -288,7 +282,7 @@ class RequestTest extends \Test\TestCase { // ensure there's no error attempting to decode the content } - public function testNotScimJsonPost() { + public function testNotScimJsonPost(): void { global $data; $data = 'this is not valid scim json'; $vars = [ @@ -309,7 +303,7 @@ class RequestTest extends \Test\TestCase { // ensure there's no error attempting to decode the content } - public function testNotCustomJsonPost() { + public function testNotCustomJsonPost(): void { global $data; $data = 'this is not valid json'; $vars = [ @@ -330,7 +324,7 @@ class RequestTest extends \Test\TestCase { // ensure there's no error attempting to decode the content } - public function testPatch() { + public function testPatch(): void { global $data; $data = http_build_query(['name' => 'John Q. Public', 'nickname' => 'Joey'], '', '&'); @@ -354,7 +348,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('Joey', $result['nickname']); } - public function testJsonPatchAndPut() { + public function testJsonPatchAndPut(): void { global $data; // PUT content @@ -400,7 +394,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame(null, $result['nickname']); } - public function testScimJsonPatchAndPut() { + public function testScimJsonPatchAndPut(): void { global $data; // PUT content @@ -446,7 +440,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame(null, $result['displayName']); } - public function testCustomJsonPatchAndPut() { + public function testCustomJsonPatchAndPut(): void { global $data; // PUT content @@ -492,7 +486,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame(null, $result['propertyB']); } - public function testPutStream() { + public function testPutStream(): void { global $data; $data = file_get_contents(__DIR__ . '/../../../data/testimage.png'); @@ -527,7 +521,7 @@ class RequestTest extends \Test\TestCase { } - public function testSetUrlParameters() { + public function testSetUrlParameters(): void { $vars = [ 'post' => [], 'method' => 'POST', @@ -549,331 +543,182 @@ class RequestTest extends \Test\TestCase { $this->assertEquals('3', $request->getParams()['id']); } - public function testGetRemoteAddressWithoutTrustedRemote() { - $this->config - ->expects($this->once()) - ->method('getSystemValue') - ->with('trusted_proxies') - ->willReturn([]); - - $request = new Request( - [ - 'server' => [ + public static function dataGetRemoteAddress(): array { + return [ + 'IPv4 without trusted remote' => [ + [ 'REMOTE_ADDR' => '10.0.0.2', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', ], + [], + [], + '10.0.0.2', ], - $this->requestId, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('10.0.0.2', $request->getRemoteAddress()); - } - - public function testGetRemoteAddressWithNoTrustedHeader() { - $this->config - ->expects($this->exactly(2)) - ->method('getSystemValue') - ->withConsecutive( - ['trusted_proxies'], - ['forwarded_for_headers'], - )->willReturnOnConsecutiveCalls( - ['10.0.0.2'], - [] - ); - - $request = new Request( - [ - 'server' => [ + 'IPv4 without trusted headers' => [ + [ 'REMOTE_ADDR' => '10.0.0.2', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', ], - ], - $this->requestId, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('10.0.0.2', $request->getRemoteAddress()); - } - - public function testGetRemoteAddressWithSingleTrustedRemote() { - $this->config - ->expects($this->exactly(2)) - ->method('getSystemValue') - ->withConsecutive( - ['trusted_proxies'], - ['forwarded_for_headers'], - )-> willReturnOnConsecutiveCalls( ['10.0.0.2'], - ['HTTP_X_FORWARDED'], - ); - - $request = new Request( - [ - 'server' => [ + [], + '10.0.0.2', + ], + 'IPv4 with single trusted remote' => [ + [ 'REMOTE_ADDR' => '10.0.0.2', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', ], - ], - $this->requestId, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('10.4.0.5', $request->getRemoteAddress()); - } - - public function testGetRemoteAddressIPv6WithSingleTrustedRemote() { - $this->config - ->expects($this->exactly(2)) - ->method('getSystemValue') - ->withConsecutive( - ['trusted_proxies'], - ['forwarded_for_headers'], - )-> willReturnOnConsecutiveCalls( - ['2001:db8:85a3:8d3:1319:8a2e:370:7348'], + ['10.0.0.2'], ['HTTP_X_FORWARDED'], - ); - - $request = new Request( - [ - 'server' => [ + '10.4.0.4', + ], + 'IPv6 with single trusted remote' => [ + [ 'REMOTE_ADDR' => '2001:db8:85a3:8d3:1319:8a2e:370:7348', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', ], + ['2001:db8:85a3:8d3:1319:8a2e:370:7348'], + ['HTTP_X_FORWARDED'], + '10.4.0.4', ], - $this->requestId, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('10.4.0.5', $request->getRemoteAddress()); - } - - public function testGetRemoteAddressVerifyPriorityHeader() { - $this->config - ->expects($this->exactly(2)) - ->method('getSystemValue') - ->withConsecutive( - ['trusted_proxies'], - ['forwarded_for_headers'], - )-> willReturnOnConsecutiveCalls( + 'IPv4 with multiple trusted remotes' => [ + [ + 'REMOTE_ADDR' => '10.0.0.2', + 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4, ::1', + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', + ], + ['10.0.0.2', '::1'], + ['HTTP_X_FORWARDED'], + '10.4.0.4', + ], + 'IPv4 order of forwarded-for headers' => [ + [ + 'REMOTE_ADDR' => '10.0.0.2', + 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', + ], ['10.0.0.2'], [ - 'HTTP_CLIENT_IP', - 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', + 'HTTP_X_FORWARDED_FOR', + 'HTTP_CLIENT_IP', ], - ); - - $request = new Request( - [ - 'server' => [ + '192.168.0.233', + ], + 'IPv4 order of forwarded-for headers (reversed)' => [ + [ 'REMOTE_ADDR' => '10.0.0.2', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', ], - ], - $this->requestId, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('192.168.0.233', $request->getRemoteAddress()); - } - - public function testGetRemoteAddressIPv6VerifyPriorityHeader() { - $this->config - ->expects($this->exactly(2)) - ->method('getSystemValue') - ->withConsecutive( - ['trusted_proxies'], - ['forwarded_for_headers'], - )-> willReturnOnConsecutiveCalls( - ['2001:db8:85a3:8d3:1319:8a2e:370:7348'], + ['10.0.0.2'], [ 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', - 'HTTP_X_FORWARDED' + 'HTTP_X_FORWARDED', ], - ); - - $request = new Request( - [ - 'server' => [ + '10.4.0.4', + ], + 'IPv6 order of forwarded-for headers' => [ + [ 'REMOTE_ADDR' => '2001:db8:85a3:8d3:1319:8a2e:370:7348', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', ], - ], - $this->requestId, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('192.168.0.233', $request->getRemoteAddress()); - } - - public function testGetRemoteAddressWithMatchingCidrTrustedRemote() { - $this->config - ->expects($this->exactly(2)) - ->method('getSystemValue') - ->withConsecutive( - ['trusted_proxies'], - ['forwarded_for_headers'], - )-> willReturnOnConsecutiveCalls( - ['192.168.2.0/24'], - ['HTTP_X_FORWARDED_FOR'], - ); - - $request = new Request( - [ - 'server' => [ - 'REMOTE_ADDR' => '192.168.2.99', - 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + ['2001:db8:85a3:8d3:1319:8a2e:370:7348'], + [ + 'HTTP_X_FORWARDED', + 'HTTP_X_FORWARDED_FOR', + 'HTTP_CLIENT_IP', ], + '192.168.0.233', ], - $this->requestId, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('192.168.0.233', $request->getRemoteAddress()); - } - - public function testGetRemoteAddressWithNotMatchingCidrTrustedRemote() { - $this->config - ->expects($this->once()) - ->method('getSystemValue') - ->with('trusted_proxies') - ->willReturn(['192.168.2.0/24']); - - $request = new Request( - [ - 'server' => [ + 'IPv4 matching CIDR of trusted proxy' => [ + [ 'REMOTE_ADDR' => '192.168.3.99', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', ], + ['192.168.2.0/24'], + ['HTTP_X_FORWARDED_FOR'], + '192.168.3.99', ], - $this->requestId, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('192.168.3.99', $request->getRemoteAddress()); - } - - public function testGetRemoteIpv6AddressWithMatchingIpv6CidrTrustedRemote() { - $this->config - ->expects($this->exactly(2)) - ->method('getSystemValue') - ->withConsecutive( - ['trusted_proxies'], - ['forwarded_for_headers'] - )->willReturnOnConsecutiveCalls( - ['2001:db8:85a3:8d3:1319:8a20::/95'], - ['HTTP_X_FORWARDED_FOR'] - ); - - $request = new Request( - [ - 'server' => [ + 'IPv6 matching CIDR of trusted proxy' => [ + [ 'REMOTE_ADDR' => '2001:db8:85a3:8d3:1319:8a21:370:7348', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', ], + ['2001:db8:85a3:8d3:1319:8a20::/95'], + ['HTTP_X_FORWARDED_FOR'], + '192.168.0.233', ], - $this->requestId, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('192.168.0.233', $request->getRemoteAddress()); - } - - public function testGetRemoteAddressIpv6WithNotMatchingCidrTrustedRemote() { - $this->config - ->expects($this->once()) - ->method('getSystemValue') - ->with('trusted_proxies') - ->willReturn(['fd::/8']); - - $request = new Request( - [ - 'server' => [ + 'IPv6 not matching CIDR of trusted proxy' => [ + [ 'REMOTE_ADDR' => '2001:db8:85a3:8d3:1319:8a2e:370:7348', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', ], + ['fd::/8'], + [], + '2001:db8:85a3:8d3:1319:8a2e:370:7348', ], - $this->requestId, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('2001:db8:85a3:8d3:1319:8a2e:370:7348', $request->getRemoteAddress()); - } - - public function testGetRemoteAddressIpv6WithInvalidTrustedProxy() { - $this->config - ->expects($this->once()) - ->method('getSystemValue') - ->with('trusted_proxies') - ->willReturn(['fx::/8']); - - $request = new Request( - [ - 'server' => [ + 'IPv6 with invalid trusted proxy' => [ + [ 'REMOTE_ADDR' => '2001:db8:85a3:8d3:1319:8a2e:370:7348', 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4', - 'HTTP_X_FORWARDED_FOR' => '192.168.0.233' + 'HTTP_X_FORWARDED_FOR' => '192.168.0.233', ], + ['fx::/8'], + [], + '2001:db8:85a3:8d3:1319:8a2e:370:7348', ], - $this->requestId, - $this->config, - $this->csrfTokenManager, - $this->stream - ); - - $this->assertSame('2001:db8:85a3:8d3:1319:8a2e:370:7348', $request->getRemoteAddress()); + 'IPv4 forwarded for IPv6' => [ + [ + 'REMOTE_ADDR' => '192.168.2.99', + 'HTTP_X_FORWARDED_FOR' => '[2001:db8:85a3:8d3:1319:8a2e:370:7348]', + ], + ['192.168.2.0/24'], + ['HTTP_X_FORWARDED_FOR'], + '2001:db8:85a3:8d3:1319:8a2e:370:7348', + ], + 'IPv4 with port' => [ + [ + 'REMOTE_ADDR' => '2001:db8:85a3:8d3:1319:8a2e:370:7348', + 'HTTP_X_FORWARDED_FOR' => '192.168.2.99:8080', + ], + ['2001:db8::/8'], + ['HTTP_X_FORWARDED_FOR'], + '192.168.2.99', + ], + 'IPv6 with port' => [ + [ + 'REMOTE_ADDR' => '192.168.2.99', + 'HTTP_X_FORWARDED_FOR' => '[2001:db8:85a3:8d3:1319:8a2e:370:7348]:8080', + ], + ['192.168.2.0/24'], + ['HTTP_X_FORWARDED_FOR'], + '2001:db8:85a3:8d3:1319:8a2e:370:7348', + ], + ]; } - public function testGetRemoteAddressWithXForwardedForIPv6() { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGetRemoteAddress')] + public function testGetRemoteAddress(array $headers, array $trustedProxies, array $forwardedForHeaders, string $expected): void { $this->config - ->expects($this->exactly(2)) ->method('getSystemValue') - ->withConsecutive( - ['trusted_proxies'], - ['forwarded_for_headers'], - )-> willReturnOnConsecutiveCalls( - ['192.168.2.0/24'], - ['HTTP_X_FORWARDED_FOR'], - ); + ->willReturnMap([ + ['trusted_proxies', [], $trustedProxies], + ['forwarded_for_headers', ['HTTP_X_FORWARDED_FOR'], $forwardedForHeaders], + ]); $request = new Request( [ - 'server' => [ - 'REMOTE_ADDR' => '192.168.2.99', - 'HTTP_X_FORWARDED_FOR' => '[2001:db8:85a3:8d3:1319:8a2e:370:7348]', - ], + 'server' => $headers, ], $this->requestId, $this->config, @@ -881,13 +726,10 @@ class RequestTest extends \Test\TestCase { $this->stream ); - $this->assertSame('2001:db8:85a3:8d3:1319:8a2e:370:7348', $request->getRemoteAddress()); + $this->assertSame($expected, $request->getRemoteAddress()); } - /** - * @return array - */ - public function httpProtocolProvider() { + public static function dataHttpProtocol(): array { return [ // Valid HTTP 1.0 ['HTTP/1.0', 'HTTP/1.0'], @@ -914,12 +756,12 @@ class RequestTest extends \Test\TestCase { } /** - * @dataProvider httpProtocolProvider * * @param mixed $input * @param string $expected */ - public function testGetHttpProtocol($input, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataHttpProtocol')] + public function testGetHttpProtocol($input, $expected): void { $request = new Request( [ 'server' => [ @@ -935,12 +777,12 @@ class RequestTest extends \Test\TestCase { $this->assertSame($expected, $request->getHttpProtocol()); } - public function testGetServerProtocolWithOverride() { + public function testGetServerProtocolWithOverrideValid(): void { $this->config ->expects($this->exactly(3)) - ->method('getSystemValue') + ->method('getSystemValueString') ->willReturnMap([ - ['overwriteprotocol', '', 'customProtocol'], + ['overwriteprotocol', '', 'HTTPS'], // should be automatically lowercased ['overwritecondaddr', '', ''], ]); @@ -952,10 +794,30 @@ class RequestTest extends \Test\TestCase { $this->stream ); - $this->assertSame('customProtocol', $request->getServerProtocol()); + $this->assertSame('https', $request->getServerProtocol()); } - public function testGetServerProtocolWithProtoValid() { + public function testGetServerProtocolWithOverrideInValid(): void { + $this->config + ->expects($this->exactly(3)) + ->method('getSystemValueString') + ->willReturnMap([ + ['overwriteprotocol', '', 'bogusProtocol'], // should trigger fallback to http + ['overwritecondaddr', '', ''], + ]); + + $request = new Request( + [], + $this->requestId, + $this->config, + $this->csrfTokenManager, + $this->stream + ); + + $this->assertSame('http', $request->getServerProtocol()); + } + + public function testGetServerProtocolWithProtoValid(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -996,7 +858,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('http', $requestHttp->getServerProtocol()); } - public function testGetServerProtocolWithHttpsServerValueOn() { + public function testGetServerProtocolWithHttpsServerValueOn(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -1017,7 +879,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('https', $request->getServerProtocol()); } - public function testGetServerProtocolWithHttpsServerValueOff() { + public function testGetServerProtocolWithHttpsServerValueOff(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -1038,7 +900,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('http', $request->getServerProtocol()); } - public function testGetServerProtocolWithHttpsServerValueEmpty() { + public function testGetServerProtocolWithHttpsServerValueEmpty(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -1059,7 +921,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('http', $request->getServerProtocol()); } - public function testGetServerProtocolDefault() { + public function testGetServerProtocolDefault(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -1076,7 +938,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('http', $request->getServerProtocol()); } - public function testGetServerProtocolBehindLoadBalancers() { + public function testGetServerProtocolBehindLoadBalancers(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -1104,12 +966,12 @@ class RequestTest extends \Test\TestCase { } /** - * @dataProvider userAgentProvider * @param string $testAgent * @param array $userAgent * @param bool $matches */ - public function testUserAgent($testAgent, $userAgent, $matches) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataUserAgent')] + public function testUserAgent($testAgent, $userAgent, $matches): void { $request = new Request( [ 'server' => [ @@ -1126,12 +988,12 @@ class RequestTest extends \Test\TestCase { } /** - * @dataProvider userAgentProvider * @param string $testAgent * @param array $userAgent * @param bool $matches */ - public function testUndefinedUserAgent($testAgent, $userAgent, $matches) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataUserAgent')] + public function testUndefinedUserAgent($testAgent, $userAgent, $matches): void { $request = new Request( [], $this->requestId, @@ -1143,10 +1005,7 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->isUserAgent($userAgent)); } - /** - * @return array - */ - public function userAgentProvider() { + public static function dataUserAgent(): array { return [ [ 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)', @@ -1265,7 +1124,64 @@ class RequestTest extends \Test\TestCase { ]; } - public function testInsecureServerHostServerNameHeader() { + public static function dataMatchClientVersion(): array { + return [ + [ + 'Mozilla/5.0 (Android) Nextcloud-android/3.24.1', + Request::USER_AGENT_CLIENT_ANDROID, + '3.24.1', + ], + [ + 'Mozilla/5.0 (iOS) Nextcloud-iOS/4.8.2', + Request::USER_AGENT_CLIENT_IOS, + '4.8.2', + ], + [ + 'Mozilla/5.0 (Windows) mirall/3.8.1', + Request::USER_AGENT_CLIENT_DESKTOP, + '3.8.1', + ], + [ + 'Mozilla/5.0 (Android) Nextcloud-Talk v17.10.0', + Request::USER_AGENT_TALK_ANDROID, + '17.10.0', + ], + [ + 'Mozilla/5.0 (iOS) Nextcloud-Talk v17.0.1', + Request::USER_AGENT_TALK_IOS, + '17.0.1', + ], + [ + 'Mozilla/5.0 (Windows) Nextcloud-Talk v0.6.0', + Request::USER_AGENT_TALK_DESKTOP, + '0.6.0', + ], + [ + 'Mozilla/5.0 (Windows) Nextcloud-Outlook v1.0.0', + Request::USER_AGENT_OUTLOOK_ADDON, + '1.0.0', + ], + [ + 'Filelink for *cloud/1.0.0', + Request::USER_AGENT_THUNDERBIRD_ADDON, + '1.0.0', + ], + ]; + } + + /** + * @param string $testAgent + * @param string $userAgent + * @param string $version + */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataMatchClientVersion')] + public function testMatchClientVersion(string $testAgent, string $userAgent, string $version): void { + preg_match($userAgent, $testAgent, $matches); + + $this->assertSame($version, $matches[1]); + } + + public function testInsecureServerHostServerNameHeader(): void { $request = new Request( [ 'server' => [ @@ -1281,7 +1197,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('from.server.name:8080', $request->getInsecureServerHost()); } - public function testInsecureServerHostHttpHostHeader() { + public function testInsecureServerHostHttpHostHeader(): void { $request = new Request( [ 'server' => [ @@ -1298,7 +1214,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('from.host.header:8080', $request->getInsecureServerHost()); } - public function testInsecureServerHostHttpFromForwardedHeaderSingle() { + public function testInsecureServerHostHttpFromForwardedHeaderSingle(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -1327,7 +1243,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('from.forwarded.host:8080', $request->getInsecureServerHost()); } - public function testInsecureServerHostHttpFromForwardedHeaderStacked() { + public function testInsecureServerHostHttpFromForwardedHeaderStacked(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -1356,9 +1272,9 @@ class RequestTest extends \Test\TestCase { $this->assertSame('from.forwarded.host2:8080', $request->getInsecureServerHost()); } - public function testGetServerHostWithOverwriteHost() { + public function testGetServerHostWithOverwriteHost(): void { $this->config - ->method('getSystemValue') + ->method('getSystemValueString') ->willReturnCallback(function ($key, $default) { if ($key === 'overwritecondaddr') { return ''; @@ -1380,7 +1296,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('my.overwritten.host', $request->getServerHost()); } - public function testGetServerHostWithTrustedDomain() { + public function testGetServerHostWithTrustedDomain(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -1409,7 +1325,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('my.trusted.host', $request->getServerHost()); } - public function testGetServerHostWithUntrustedDomain() { + public function testGetServerHostWithUntrustedDomain(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -1438,7 +1354,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('my.trusted.host', $request->getServerHost()); } - public function testGetServerHostWithNoTrustedDomain() { + public function testGetServerHostWithNoTrustedDomain(): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) { @@ -1464,10 +1380,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame('', $request->getServerHost()); } - /** - * @return array - */ - public function dataGetServerHostTrustedDomain() { + public static function dataGetServerHostTrustedDomain(): array { return [ 'is array' => ['my.trusted.host', ['my.trusted.host']], 'is array but undefined index 0' => ['my.trusted.host', [2 => 'my.trusted.host']], @@ -1476,12 +1389,8 @@ class RequestTest extends \Test\TestCase { ]; } - /** - * @dataProvider dataGetServerHostTrustedDomain - * @param $expected - * @param $trustedDomain - */ - public function testGetServerHostTrustedDomain($expected, $trustedDomain) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGetServerHostTrustedDomain')] + public function testGetServerHostTrustedDomain(string $expected, $trustedDomain): void { $this->config ->method('getSystemValue') ->willReturnCallback(function ($key, $default) use ($trustedDomain) { @@ -1510,10 +1419,10 @@ class RequestTest extends \Test\TestCase { $this->assertSame($expected, $request->getServerHost()); } - public function testGetOverwriteHostDefaultNull() { + public function testGetOverwriteHostDefaultNull(): void { $this->config ->expects($this->once()) - ->method('getSystemValue') + ->method('getSystemValueString') ->with('overwritehost') ->willReturn(''); $request = new Request( @@ -1527,10 +1436,10 @@ class RequestTest extends \Test\TestCase { $this->assertNull(self::invokePrivate($request, 'getOverwriteHost')); } - public function testGetOverwriteHostWithOverwrite() { + public function testGetOverwriteHostWithOverwrite(): void { $this->config ->expects($this->exactly(3)) - ->method('getSystemValue') + ->method('getSystemValueString') ->willReturnMap([ ['overwritehost', '', 'www.owncloud.org'], ['overwritecondaddr', '', ''], @@ -1548,7 +1457,7 @@ class RequestTest extends \Test\TestCase { } - public function testGetPathInfoNotProcessible() { + public function testGetPathInfoNotProcessible(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('The requested uri(/foo.php) cannot be processed by the script \'/var/www/index.php\')'); @@ -1569,7 +1478,7 @@ class RequestTest extends \Test\TestCase { } - public function testGetRawPathInfoNotProcessible() { + public function testGetRawPathInfoNotProcessible(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('The requested uri(/foo.php) cannot be processed by the script \'/var/www/index.php\')'); @@ -1590,12 +1499,12 @@ class RequestTest extends \Test\TestCase { } /** - * @dataProvider genericPathInfoProvider * @param string $requestUri * @param string $scriptName * @param string $expected */ - public function testGetPathInfoWithoutSetEnvGeneric($requestUri, $scriptName, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGenericPathInfo')] + public function testGetPathInfoWithoutSetEnvGeneric($requestUri, $scriptName, $expected): void { $request = new Request( [ 'server' => [ @@ -1613,12 +1522,12 @@ class RequestTest extends \Test\TestCase { } /** - * @dataProvider genericPathInfoProvider * @param string $requestUri * @param string $scriptName * @param string $expected */ - public function testGetRawPathInfoWithoutSetEnvGeneric($requestUri, $scriptName, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGenericPathInfo')] + public function testGetRawPathInfoWithoutSetEnvGeneric($requestUri, $scriptName, $expected): void { $request = new Request( [ 'server' => [ @@ -1636,12 +1545,12 @@ class RequestTest extends \Test\TestCase { } /** - * @dataProvider rawPathInfoProvider * @param string $requestUri * @param string $scriptName * @param string $expected */ - public function testGetRawPathInfoWithoutSetEnv($requestUri, $scriptName, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataRawPathInfo')] + public function testGetRawPathInfoWithoutSetEnv($requestUri, $scriptName, $expected): void { $request = new Request( [ 'server' => [ @@ -1659,12 +1568,12 @@ class RequestTest extends \Test\TestCase { } /** - * @dataProvider pathInfoProvider * @param string $requestUri * @param string $scriptName * @param string $expected */ - public function testGetPathInfoWithoutSetEnv($requestUri, $scriptName, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataPathInfo')] + public function testGetPathInfoWithoutSetEnv($requestUri, $scriptName, $expected): void { $request = new Request( [ 'server' => [ @@ -1681,10 +1590,7 @@ class RequestTest extends \Test\TestCase { $this->assertSame($expected, $request->getPathInfo()); } - /** - * @return array - */ - public function genericPathInfoProvider() { + public static function dataGenericPathInfo(): array { return [ ['/core/index.php?XDEBUG_SESSION_START=14600', '/core/index.php', ''], ['/index.php/apps/files/', 'index.php', '/apps/files/'], @@ -1696,28 +1602,22 @@ class RequestTest extends \Test\TestCase { ]; } - /** - * @return array - */ - public function rawPathInfoProvider() { + public static function dataRawPathInfo(): array { return [ ['/foo%2Fbar/subfolder', '', 'foo%2Fbar/subfolder'], ]; } - /** - * @return array - */ - public function pathInfoProvider() { + public static function dataPathInfo(): array { return [ ['/foo%2Fbar/subfolder', '', 'foo/bar/subfolder'], ]; } - public function testGetRequestUriWithoutOverwrite() { + public function testGetRequestUriWithoutOverwrite(): void { $this->config ->expects($this->once()) - ->method('getSystemValue') + ->method('getSystemValueString') ->with('overwritewebroot') ->willReturn(''); @@ -1736,32 +1636,31 @@ class RequestTest extends \Test\TestCase { $this->assertSame('/test.php', $request->getRequestUri()); } - public function providesGetRequestUriWithOverwriteData() { + public static function dataGetRequestUriWithOverwrite(): array { return [ ['/scriptname.php/some/PathInfo', '/owncloud/', ''], - ['/scriptname.php/some/PathInfo', '/owncloud/', '123'], + ['/scriptname.php/some/PathInfo', '/owncloud/', '123', '123.123.123.123'], ]; } - /** - * @dataProvider providesGetRequestUriWithOverwriteData - */ - public function testGetRequestUriWithOverwrite($expectedUri, $overwriteWebRoot, $overwriteCondAddr) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGetRequestUriWithOverwrite')] + public function testGetRequestUriWithOverwrite($expectedUri, $overwriteWebRoot, $overwriteCondAddr, $remoteAddr = ''): void { $this->config ->expects($this->exactly(2)) - ->method('getSystemValue') + ->method('getSystemValueString') ->willReturnMap([ ['overwritewebroot', '', $overwriteWebRoot], ['overwritecondaddr', '', $overwriteCondAddr], ]); - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ 'REQUEST_URI' => '/test.php/some/PathInfo', 'SCRIPT_NAME' => '/test.php', + 'REMOTE_ADDR' => $remoteAddr ] ], $this->requestId, @@ -1778,10 +1677,10 @@ class RequestTest extends \Test\TestCase { $this->assertSame($expectedUri, $request->getRequestUri()); } - public function testPassesCSRFCheckWithGet() { + public function testPassesCSRFCheckWithGet(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'get' => [ @@ -1808,10 +1707,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesCSRFCheck()); } - public function testPassesCSRFCheckWithPost() { + public function testPassesCSRFCheckWithPost(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'post' => [ @@ -1838,10 +1737,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesCSRFCheck()); } - public function testPassesCSRFCheckWithHeader() { + public function testPassesCSRFCheckWithHeader(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -1868,10 +1767,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesCSRFCheck()); } - public function testPassesCSRFCheckWithGetAndWithoutCookies() { + public function testPassesCSRFCheckWithGetAndWithoutCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'get' => [ @@ -1892,10 +1791,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesCSRFCheck()); } - public function testPassesCSRFCheckWithPostAndWithoutCookies() { + public function testPassesCSRFCheckWithPostAndWithoutCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'post' => [ @@ -1916,10 +1815,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesCSRFCheck()); } - public function testPassesCSRFCheckWithHeaderAndWithoutCookies() { + public function testPassesCSRFCheckWithHeaderAndWithoutCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -1940,10 +1839,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesCSRFCheck()); } - public function testFailsCSRFCheckWithHeaderAndNotAllChecksPassing() { + public function testFailsCSRFCheckWithHeaderAndNotAllChecksPassing(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -1967,10 +1866,10 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesCSRFCheck()); } - public function testPassesStrictCookieCheckWithAllCookiesAndStrict() { + public function testPassesStrictCookieCheckWithAllCookiesAndStrict(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName', 'getCookieParams']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName', 'getCookieParams']) ->setConstructorArgs([ [ 'server' => [ @@ -1999,10 +1898,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesStrictCookieCheck()); } - public function testFailsStrictCookieCheckWithAllCookiesAndMissingStrict() { + public function testFailsStrictCookieCheckWithAllCookiesAndMissingStrict(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName', 'getCookieParams']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName', 'getCookieParams']) ->setConstructorArgs([ [ 'server' => [ @@ -2031,10 +1930,10 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesStrictCookieCheck()); } - public function testGetCookieParams() { + public function testGetCookieParams(): void { /** @var Request $request */ $request = $this->getMockBuilder(Request::class) - ->setMethods(['getScriptName']) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [], $this->requestId, @@ -2047,10 +1946,10 @@ class RequestTest extends \Test\TestCase { $this->assertSame(session_get_cookie_params(), $actual); } - public function testPassesStrictCookieCheckWithAllCookies() { + public function testPassesStrictCookieCheckWithAllCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -2072,10 +1971,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesStrictCookieCheck()); } - public function testPassesStrictCookieCheckWithRandomCookies() { + public function testPassesStrictCookieCheckWithRandomCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -2095,10 +1994,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesStrictCookieCheck()); } - public function testFailsStrictCookieCheckWithSessionCookie() { + public function testFailsStrictCookieCheckWithSessionCookie(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -2118,10 +2017,10 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesStrictCookieCheck()); } - public function testFailsStrictCookieCheckWithRememberMeCookie() { + public function testFailsStrictCookieCheckWithRememberMeCookie(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -2141,10 +2040,10 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesStrictCookieCheck()); } - public function testFailsCSRFCheckWithPostAndWithCookies() { + public function testFailsCSRFCheckWithPostAndWithCookies(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'post' => [ @@ -2168,10 +2067,10 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesCSRFCheck()); } - public function testFailStrictCookieCheckWithOnlyLaxCookie() { + public function testFailStrictCookieCheckWithOnlyLaxCookie(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -2192,10 +2091,10 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesStrictCookieCheck()); } - public function testFailStrictCookieCheckWithOnlyStrictCookie() { + public function testFailStrictCookieCheckWithOnlyStrictCookie(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -2216,10 +2115,10 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesStrictCookieCheck()); } - public function testPassesLaxCookieCheck() { + public function testPassesLaxCookieCheck(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -2240,10 +2139,10 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesLaxCookieCheck()); } - public function testFailsLaxCookieCheckWithOnlyStrictCookie() { + public function testFailsLaxCookieCheckWithOnlyStrictCookie(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -2264,10 +2163,10 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesLaxCookieCheck()); } - public function testSkipCookieCheckForOCSRequests() { + public function testSkipCookieCheckForOCSRequests(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -2289,10 +2188,7 @@ class RequestTest extends \Test\TestCase { $this->assertTrue($request->passesStrictCookieCheck()); } - /** - * @return array - */ - public function invalidTokenDataProvider() { + public static function dataInvalidToken(): array { return [ ['InvalidSentToken'], ['InvalidSentToken:InvalidSecret'], @@ -2300,14 +2196,11 @@ class RequestTest extends \Test\TestCase { ]; } - /** - * @dataProvider invalidTokenDataProvider - * @param string $invalidToken - */ - public function testPassesCSRFCheckWithInvalidToken($invalidToken) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataInvalidToken')] + public function testPassesCSRFCheckWithInvalidToken(string $invalidToken): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [ 'server' => [ @@ -2331,10 +2224,10 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesCSRFCheck()); } - public function testPassesCSRFCheckWithoutTokenFail() { + public function testPassesCSRFCheckWithoutTokenFail(): void { /** @var Request $request */ - $request = $this->getMockBuilder('\OC\AppFramework\Http\Request') - ->setMethods(['getScriptName']) + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) ->setConstructorArgs([ [], $this->requestId, @@ -2346,4 +2239,24 @@ class RequestTest extends \Test\TestCase { $this->assertFalse($request->passesCSRFCheck()); } + + public function testPassesCSRFCheckWithOCSAPIRequestHeader(): void { + /** @var Request $request */ + $request = $this->getMockBuilder(Request::class) + ->onlyMethods(['getScriptName']) + ->setConstructorArgs([ + [ + 'server' => [ + 'HTTP_OCS_APIREQUEST' => 'true', + ], + ], + $this->requestId, + $this->config, + $this->csrfTokenManager, + $this->stream + ]) + ->getMock(); + + $this->assertTrue($request->passesCSRFCheck()); + } } diff --git a/tests/lib/AppFramework/Http/ResponseTest.php b/tests/lib/AppFramework/Http/ResponseTest.php index c5d228e5753..4c76695f6e4 100644 --- a/tests/lib/AppFramework/Http/ResponseTest.php +++ b/tests/lib/AppFramework/Http/ResponseTest.php @@ -1,35 +1,22 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Http; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\ContentSecurityPolicy; +use OCP\AppFramework\Http\EmptyContentSecurityPolicy; use OCP\AppFramework\Http\Response; use OCP\AppFramework\Utility\ITimeFactory; class ResponseTest extends \Test\TestCase { /** - * @var \OCP\AppFramework\Http\Response + * @var Response */ private $childResponse; @@ -39,35 +26,37 @@ class ResponseTest extends \Test\TestCase { } - public function testAddHeader() { + public function testAddHeader(): void { $this->childResponse->addHeader(' hello ', 'world'); $headers = $this->childResponse->getHeaders(); $this->assertEquals('world', $headers['hello']); } - public function testSetHeaders() { + public function testSetHeaders(): void { $expected = [ 'Last-Modified' => 1, 'ETag' => 3, 'Something-Else' => 'hi', - 'X-Robots-Tag' => 'none', + 'X-Robots-Tag' => 'noindex, nofollow', + 'Cache-Control' => 'no-cache, no-store, must-revalidate', ]; $this->childResponse->setHeaders($expected); - $headers = $this->childResponse->getHeaders(); $expected['Content-Security-Policy'] = "default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'"; $expected['Feature-Policy'] = "autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone 'none';payment 'none'"; + $headers = $this->childResponse->getHeaders(); + unset($headers['X-Request-Id']); + $this->assertEquals($expected, $headers); } - public function testOverwriteCsp() { + public function testOverwriteCsp(): void { $expected = [ 'Content-Security-Policy' => "default-src 'none';base-uri 'none';manifest-src 'self';script-src 'self' 'unsafe-inline';style-src 'self' 'unsafe-inline';img-src 'self';font-src 'self' data:;connect-src 'self';media-src 'self'", ]; - $policy = new Http\ContentSecurityPolicy(); - $policy->allowInlineScript(true); + $policy = new ContentSecurityPolicy(); $this->childResponse->setContentSecurityPolicy($policy); $headers = $this->childResponse->getHeaders(); @@ -75,32 +64,31 @@ class ResponseTest extends \Test\TestCase { $this->assertEquals(array_merge($expected, $headers), $headers); } - public function testGetCsp() { - $policy = new Http\ContentSecurityPolicy(); - $policy->allowInlineScript(true); + public function testGetCsp(): void { + $policy = new ContentSecurityPolicy(); $this->childResponse->setContentSecurityPolicy($policy); $this->assertEquals($policy, $this->childResponse->getContentSecurityPolicy()); } - public function testGetCspEmpty() { - $this->assertEquals(new Http\EmptyContentSecurityPolicy(), $this->childResponse->getContentSecurityPolicy()); + public function testGetCspEmpty(): void { + $this->assertEquals(new EmptyContentSecurityPolicy(), $this->childResponse->getContentSecurityPolicy()); } - public function testAddHeaderValueNullDeletesIt() { + public function testAddHeaderValueNullDeletesIt(): void { $this->childResponse->addHeader('hello', 'world'); $this->childResponse->addHeader('hello', null); $this->assertEquals(5, count($this->childResponse->getHeaders())); } - public function testCacheHeadersAreDisabledByDefault() { + public function testCacheHeadersAreDisabledByDefault(): void { $headers = $this->childResponse->getHeaders(); $this->assertEquals('no-cache, no-store, must-revalidate', $headers['Cache-Control']); } - public function testAddCookie() { + public function testAddCookie(): void { $this->childResponse->addCookie('foo', 'bar'); $this->childResponse->addCookie('bar', 'foo', new \DateTime('1970-01-01')); @@ -120,7 +108,7 @@ class ResponseTest extends \Test\TestCase { } - public function testSetCookies() { + public function testSetCookies(): void { $expected = [ 'foo' => [ 'value' => 'bar', @@ -139,7 +127,7 @@ class ResponseTest extends \Test\TestCase { } - public function testInvalidateCookie() { + public function testInvalidateCookie(): void { $this->childResponse->addCookie('foo', 'bar'); $this->childResponse->invalidateCookie('foo'); $expected = [ @@ -156,7 +144,7 @@ class ResponseTest extends \Test\TestCase { } - public function testInvalidateCookies() { + public function testInvalidateCookies(): void { $this->childResponse->addCookie('foo', 'bar'); $this->childResponse->addCookie('bar', 'foo'); $expected = [ @@ -193,12 +181,12 @@ class ResponseTest extends \Test\TestCase { } - public function testRenderReturnNullByDefault() { + public function testRenderReturnNullByDefault(): void { $this->assertEquals(null, $this->childResponse->render()); } - public function testGetStatus() { + public function testGetStatus(): void { $default = $this->childResponse->getStatus(); $this->childResponse->setStatus(Http::STATUS_NOT_FOUND); @@ -208,13 +196,13 @@ class ResponseTest extends \Test\TestCase { } - public function testGetEtag() { + public function testGetEtag(): void { $this->childResponse->setEtag('hi'); $this->assertSame('hi', $this->childResponse->getEtag()); } - public function testGetLastModified() { + public function testGetLastModified(): void { $lastModified = new \DateTime('now', new \DateTimeZone('GMT')); $lastModified->setTimestamp(1); $this->childResponse->setLastModified($lastModified); @@ -223,17 +211,16 @@ class ResponseTest extends \Test\TestCase { - public function testCacheSecondsZero() { + public function testCacheSecondsZero(): void { $this->childResponse->cacheFor(0); $headers = $this->childResponse->getHeaders(); $this->assertEquals('no-cache, no-store, must-revalidate', $headers['Cache-Control']); - $this->assertFalse(isset($headers['Pragma'])); $this->assertFalse(isset($headers['Expires'])); } - public function testCacheSeconds() { + public function testCacheSeconds(): void { $time = $this->createMock(ITimeFactory::class); $time->method('getTime') ->willReturn(1234567); @@ -244,21 +231,20 @@ class ResponseTest extends \Test\TestCase { $headers = $this->childResponse->getHeaders(); $this->assertEquals('private, max-age=33, must-revalidate', $headers['Cache-Control']); - $this->assertEquals('private', $headers['Pragma']); - $this->assertEquals('Thu, 15 Jan 1970 06:56:40 +0000', $headers['Expires']); + $this->assertEquals('Thu, 15 Jan 1970 06:56:40 GMT', $headers['Expires']); } - public function testEtagLastModifiedHeaders() { + public function testEtagLastModifiedHeaders(): void { $lastModified = new \DateTime('now', new \DateTimeZone('GMT')); $lastModified->setTimestamp(1); $this->childResponse->setLastModified($lastModified); $headers = $this->childResponse->getHeaders(); - $this->assertEquals('Thu, 01 Jan 1970 00:00:01 +0000', $headers['Last-Modified']); + $this->assertEquals('Thu, 01 Jan 1970 00:00:01 GMT', $headers['Last-Modified']); } - public function testChainability() { + public function testChainability(): void { $lastModified = new \DateTime('now', new \DateTimeZone('GMT')); $lastModified->setTimestamp(1); @@ -273,18 +259,18 @@ class ResponseTest extends \Test\TestCase { $this->assertEquals('world', $headers['hello']); $this->assertEquals(Http::STATUS_NOT_FOUND, $this->childResponse->getStatus()); $this->assertEquals('hi', $this->childResponse->getEtag()); - $this->assertEquals('Thu, 01 Jan 1970 00:00:01 +0000', $headers['Last-Modified']); + $this->assertEquals('Thu, 01 Jan 1970 00:00:01 GMT', $headers['Last-Modified']); $this->assertEquals('private, max-age=33, must-revalidate', $headers['Cache-Control']); } - public function testThrottle() { + public function testThrottle(): void { $this->assertFalse($this->childResponse->isThrottled()); $this->childResponse->throttle(); $this->assertTrue($this->childResponse->isThrottled()); } - public function testGetThrottleMetadata() { + public function testGetThrottleMetadata(): void { $this->childResponse->throttle(['foo' => 'bar']); $this->assertSame(['foo' => 'bar'], $this->childResponse->getThrottleMetadata()); } diff --git a/tests/lib/AppFramework/Http/StreamResponseTest.php b/tests/lib/AppFramework/Http/StreamResponseTest.php index 3c0105ad145..87f6097a07a 100644 --- a/tests/lib/AppFramework/Http/StreamResponseTest.php +++ b/tests/lib/AppFramework/Http/StreamResponseTest.php @@ -1,24 +1,9 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2015 Bernhard Posselt <dev@bernhard-posselt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Http; @@ -38,7 +23,7 @@ class StreamResponseTest extends \Test\TestCase { ->getMock(); } - public function testOutputNotModified() { + public function testOutputNotModified(): void { $path = __FILE__; $this->output->expects($this->once()) ->method('getHttpResponseCode') @@ -50,7 +35,7 @@ class StreamResponseTest extends \Test\TestCase { $response->callback($this->output); } - public function testOutputOk() { + public function testOutputOk(): void { $path = __FILE__; $this->output->expects($this->once()) ->method('getHttpResponseCode') @@ -64,7 +49,7 @@ class StreamResponseTest extends \Test\TestCase { $response->callback($this->output); } - public function testOutputNotFound() { + public function testOutputNotFound(): void { $path = __FILE__ . 'test'; $this->output->expects($this->once()) ->method('getHttpResponseCode') @@ -79,7 +64,7 @@ class StreamResponseTest extends \Test\TestCase { $response->callback($this->output); } - public function testOutputReadFileError() { + public function testOutputReadFileError(): void { $path = __FILE__; $this->output->expects($this->once()) ->method('getHttpResponseCode') diff --git a/tests/lib/AppFramework/Http/TemplateResponseTest.php b/tests/lib/AppFramework/Http/TemplateResponseTest.php index 13eef5c7c22..28f952e35e3 100644 --- a/tests/lib/AppFramework/Http/TemplateResponseTest.php +++ b/tests/lib/AppFramework/Http/TemplateResponseTest.php @@ -1,24 +1,9 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Http; @@ -28,7 +13,7 @@ use OCP\AppFramework\Http\TemplateResponse; class TemplateResponseTest extends \Test\TestCase { /** - * @var \OCP\AppFramework\Http\TemplateResponse + * @var TemplateResponse */ private $tpl; @@ -39,7 +24,7 @@ class TemplateResponseTest extends \Test\TestCase { } - public function testSetParamsConstructor() { + public function testSetParamsConstructor(): void { $params = ['hi' => 'yo']; $this->tpl = new TemplateResponse('app', 'home', $params); @@ -47,7 +32,7 @@ class TemplateResponseTest extends \Test\TestCase { } - public function testSetRenderAsConstructor() { + public function testSetRenderAsConstructor(): void { $renderAs = 'myrender'; $this->tpl = new TemplateResponse('app', 'home', [], $renderAs); @@ -55,7 +40,7 @@ class TemplateResponseTest extends \Test\TestCase { } - public function testSetParams() { + public function testSetParams(): void { $params = ['hi' => 'yo']; $this->tpl->setParams($params); @@ -63,17 +48,17 @@ class TemplateResponseTest extends \Test\TestCase { } - public function testGetTemplateName() { + public function testGetTemplateName(): void { $this->assertEquals('home', $this->tpl->getTemplateName()); } - public function testGetRenderAs() { + public function testGetRenderAs(): void { $render = 'myrender'; $this->tpl->renderAs($render); $this->assertEquals($render, $this->tpl->getRenderAs()); } - public function testChainability() { + public function testChainability(): void { $params = ['hi' => 'yo']; $this->tpl->setParams($params) ->setStatus(Http::STATUS_NOT_FOUND); diff --git a/tests/lib/AppFramework/Middleware/AdditionalScriptsMiddlewareTest.php b/tests/lib/AppFramework/Middleware/AdditionalScriptsMiddlewareTest.php index 1cd6b614aad..4fa5de62b0b 100644 --- a/tests/lib/AppFramework/Middleware/AdditionalScriptsMiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/AdditionalScriptsMiddlewareTest.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\AppFramework\Middleware; @@ -35,11 +18,8 @@ use OCP\AppFramework\PublicShareController; use OCP\EventDispatcher\IEventDispatcher; use OCP\IUserSession; use PHPUnit\Framework\MockObject\MockObject; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; class AdditionalScriptsMiddlewareTest extends \Test\TestCase { - /** @var EventDispatcherInterface|MockObject */ - private $legacyDispatcher; /** @var IUserSession|MockObject */ private $userSession; @@ -54,11 +34,9 @@ class AdditionalScriptsMiddlewareTest extends \Test\TestCase { protected function setUp(): void { parent::setUp(); - $this->legacyDispatcher = $this->createMock(EventDispatcherInterface::class); $this->userSession = $this->createMock(IUserSession::class); $this->dispatcher = $this->createMock(IEventDispatcher::class); $this->middleWare = new AdditionalScriptsMiddleware( - $this->legacyDispatcher, $this->userSession, $this->dispatcher ); @@ -66,9 +44,7 @@ class AdditionalScriptsMiddlewareTest extends \Test\TestCase { $this->controller = $this->createMock(Controller::class); } - public function testNoTemplateResponse() { - $this->legacyDispatcher->expects($this->never()) - ->method($this->anything()); + public function testNoTemplateResponse(): void { $this->userSession->expects($this->never()) ->method($this->anything()); $this->dispatcher->expects($this->never()) @@ -77,9 +53,7 @@ class AdditionalScriptsMiddlewareTest extends \Test\TestCase { $this->middleWare->afterController($this->controller, 'myMethod', $this->createMock(Response::class)); } - public function testPublicShareController() { - $this->legacyDispatcher->expects($this->never()) - ->method($this->anything()); + public function testPublicShareController(): void { $this->userSession->expects($this->never()) ->method($this->anything()); $this->dispatcher->expects($this->never()) @@ -88,21 +62,12 @@ class AdditionalScriptsMiddlewareTest extends \Test\TestCase { $this->middleWare->afterController($this->createMock(PublicShareController::class), 'myMethod', $this->createMock(Response::class)); } - public function testStandaloneTemplateResponse() { - $this->legacyDispatcher->expects($this->once()) - ->method('dispatch') - ->willReturnCallback(function ($eventName) { - if ($eventName === TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS) { - return; - } - - $this->fail('Wrong event dispatched'); - }); + public function testStandaloneTemplateResponse(): void { $this->userSession->expects($this->never()) ->method($this->anything()); $this->dispatcher->expects($this->once()) ->method('dispatchTyped') - ->willReturnCallback(function ($event) { + ->willReturnCallback(function ($event): void { if ($event instanceof BeforeTemplateRenderedEvent && $event->isLoggedIn() === false) { return; } @@ -113,21 +78,12 @@ class AdditionalScriptsMiddlewareTest extends \Test\TestCase { $this->middleWare->afterController($this->controller, 'myMethod', $this->createMock(StandaloneTemplateResponse::class)); } - public function testTemplateResponseNotLoggedIn() { - $this->legacyDispatcher->expects($this->once()) - ->method('dispatch') - ->willReturnCallback(function ($eventName) { - if ($eventName === TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS) { - return; - } - - $this->fail('Wrong event dispatched'); - }); + public function testTemplateResponseNotLoggedIn(): void { $this->userSession->method('isLoggedIn') ->willReturn(false); $this->dispatcher->expects($this->once()) ->method('dispatchTyped') - ->willReturnCallback(function ($event) { + ->willReturnCallback(function ($event): void { if ($event instanceof BeforeTemplateRenderedEvent && $event->isLoggedIn() === false) { return; } @@ -138,25 +94,14 @@ class AdditionalScriptsMiddlewareTest extends \Test\TestCase { $this->middleWare->afterController($this->controller, 'myMethod', $this->createMock(TemplateResponse::class)); } - public function testTemplateResponseLoggedIn() { + public function testTemplateResponseLoggedIn(): void { $events = []; - $this->legacyDispatcher->expects($this->exactly(2)) - ->method('dispatch') - ->willReturnCallback(function ($eventName) use (&$events) { - if ($eventName === TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS || - $eventName === TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS_LOGGEDIN) { - $events[] = $eventName; - return; - } - - $this->fail('Wrong event dispatched'); - }); $this->userSession->method('isLoggedIn') ->willReturn(true); $this->dispatcher->expects($this->once()) ->method('dispatchTyped') - ->willReturnCallback(function ($event) { + ->willReturnCallback(function ($event): void { if ($event instanceof BeforeTemplateRenderedEvent && $event->isLoggedIn() === true) { return; } @@ -165,8 +110,5 @@ class AdditionalScriptsMiddlewareTest extends \Test\TestCase { }); $this->middleWare->afterController($this->controller, 'myMethod', $this->createMock(TemplateResponse::class)); - - $this->assertContains(TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS, $events); - $this->assertContains(TemplateResponse::EVENT_LOAD_ADDITIONAL_SCRIPTS_LOGGEDIN, $events); } } diff --git a/tests/lib/AppFramework/Middleware/CompressionMiddlewareTest.php b/tests/lib/AppFramework/Middleware/CompressionMiddlewareTest.php index 79e07ac6686..010ce3fff6d 100644 --- a/tests/lib/AppFramework/Middleware/CompressionMiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/CompressionMiddlewareTest.php @@ -2,25 +2,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, 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: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\AppFramework\Middleware; @@ -53,7 +36,7 @@ class CompressionMiddlewareTest extends \Test\TestCase { $this->controller = $this->createMock(Controller::class); } - public function testGzipOCSV1() { + public function testGzipOCSV1(): void { $this->request->method('getHeader') ->with('Accept-Encoding') ->willReturn('gzip'); @@ -75,7 +58,7 @@ class CompressionMiddlewareTest extends \Test\TestCase { $this->assertSame($output, gzdecode($result)); } - public function testGzipOCSV2() { + public function testGzipOCSV2(): void { $this->request->method('getHeader') ->with('Accept-Encoding') ->willReturn('gzip'); @@ -97,7 +80,7 @@ class CompressionMiddlewareTest extends \Test\TestCase { $this->assertSame($output, gzdecode($result)); } - public function testGzipJSONResponse() { + public function testGzipJSONResponse(): void { $this->request->method('getHeader') ->with('Accept-Encoding') ->willReturn('gzip'); @@ -119,7 +102,7 @@ class CompressionMiddlewareTest extends \Test\TestCase { $this->assertSame($output, gzdecode($result)); } - public function testNoGzipDataResponse() { + public function testNoGzipDataResponse(): void { $this->request->method('getHeader') ->with('Accept-Encoding') ->willReturn('gzip'); @@ -139,7 +122,7 @@ class CompressionMiddlewareTest extends \Test\TestCase { $this->assertSame($output, $result); } - public function testNoGzipNo200() { + public function testNoGzipNo200(): void { $this->request->method('getHeader') ->with('Accept-Encoding') ->willReturn('gzip'); diff --git a/tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php b/tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php index f408320971d..aae1c53456b 100644 --- a/tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php +++ b/tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php @@ -1,30 +1,16 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Middleware; use OC\AppFramework\Http\Request; use OC\AppFramework\Middleware\MiddlewareDispatcher; +use OCP\AppFramework\Controller; use OCP\AppFramework\Http\Response; use OCP\AppFramework\Middleware; use OCP\IConfig; @@ -48,17 +34,16 @@ class TestMiddleware extends Middleware { public $response; public $output; - private $beforeControllerThrowsEx; - /** * @param boolean $beforeControllerThrowsEx */ - public function __construct($beforeControllerThrowsEx) { + public function __construct( + private $beforeControllerThrowsEx, + ) { self::$beforeControllerCalled = 0; self::$afterControllerCalled = 0; self::$afterExceptionCalled = 0; self::$beforeOutputCalled = 0; - $this->beforeControllerThrowsEx = $beforeControllerThrowsEx; } public function beforeController($controller, $methodName) { @@ -99,6 +84,10 @@ class TestMiddleware extends Middleware { } } +class TestController extends Controller { + public function method(): void { + } +} class MiddlewareDispatcherTest extends \Test\TestCase { public $exception; @@ -125,8 +114,8 @@ class MiddlewareDispatcherTest extends \Test\TestCase { private function getControllerMock() { - return $this->getMockBuilder('OCP\AppFramework\Controller') - ->setMethods(['method']) + return $this->getMockBuilder(TestController::class) + ->onlyMethods(['method']) ->setConstructorArgs(['app', new Request( ['method' => 'GET'], @@ -144,20 +133,20 @@ class MiddlewareDispatcherTest extends \Test\TestCase { } - public function testAfterExceptionShouldReturnResponseOfMiddleware() { + public function testAfterExceptionShouldReturnResponseOfMiddleware(): void { $response = new Response(); - $m1 = $this->getMockBuilder('\OCP\AppFramework\Middleware') - ->setMethods(['afterException', 'beforeController']) + $m1 = $this->getMockBuilder(Middleware::class) + ->onlyMethods(['afterException', 'beforeController']) ->getMock(); $m1->expects($this->never()) - ->method('afterException'); + ->method('afterException'); - $m2 = $this->getMockBuilder('OCP\AppFramework\Middleware') - ->setMethods(['afterException', 'beforeController']) + $m2 = $this->getMockBuilder(Middleware::class) + ->onlyMethods(['afterException', 'beforeController']) ->getMock(); $m2->expects($this->once()) - ->method('afterException') - ->willReturn($response); + ->method('afterException') + ->willReturn($response); $this->dispatcher->registerMiddleware($m1); $this->dispatcher->registerMiddleware($m2); @@ -167,7 +156,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase { } - public function testAfterExceptionShouldThrowAgainWhenNotHandled() { + public function testAfterExceptionShouldThrowAgainWhenNotHandled(): void { $m1 = new TestMiddleware(false); $m2 = new TestMiddleware(true); @@ -180,7 +169,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase { } - public function testBeforeControllerCorrectArguments() { + public function testBeforeControllerCorrectArguments(): void { $m1 = $this->getMiddleware(); $this->dispatcher->beforeController($this->controller, $this->method); @@ -189,7 +178,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase { } - public function testAfterControllerCorrectArguments() { + public function testAfterControllerCorrectArguments(): void { $m1 = $this->getMiddleware(); $this->dispatcher->afterController($this->controller, $this->method, $this->response); @@ -200,7 +189,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase { } - public function testAfterExceptionCorrectArguments() { + public function testAfterExceptionCorrectArguments(): void { $m1 = $this->getMiddleware(); $this->expectException(\Exception::class); @@ -214,7 +203,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase { } - public function testBeforeOutputCorrectArguments() { + public function testBeforeOutputCorrectArguments(): void { $m1 = $this->getMiddleware(); $this->dispatcher->beforeOutput($this->controller, $this->method, $this->out); @@ -225,7 +214,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase { } - public function testBeforeControllerOrder() { + public function testBeforeControllerOrder(): void { $m1 = $this->getMiddleware(); $m2 = $this->getMiddleware(); @@ -235,7 +224,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase { $this->assertEquals(2, $m2->beforeControllerOrder); } - public function testAfterControllerOrder() { + public function testAfterControllerOrder(): void { $m1 = $this->getMiddleware(); $m2 = $this->getMiddleware(); @@ -246,7 +235,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase { } - public function testAfterExceptionOrder() { + public function testAfterExceptionOrder(): void { $m1 = $this->getMiddleware(); $m2 = $this->getMiddleware(); @@ -259,7 +248,7 @@ class MiddlewareDispatcherTest extends \Test\TestCase { } - public function testBeforeOutputOrder() { + public function testBeforeOutputOrder(): void { $m1 = $this->getMiddleware(); $m2 = $this->getMiddleware(); @@ -270,16 +259,16 @@ class MiddlewareDispatcherTest extends \Test\TestCase { } - public function testExceptionShouldRunAfterExceptionOfOnlyPreviouslyExecutedMiddlewares() { + public function testExceptionShouldRunAfterExceptionOfOnlyPreviouslyExecutedMiddlewares(): void { $m1 = $this->getMiddleware(); $m2 = $this->getMiddleware(true); $m3 = $this->createMock(Middleware::class); $m3->expects($this->never()) - ->method('afterException'); + ->method('afterException'); $m3->expects($this->never()) - ->method('beforeController'); + ->method('beforeController'); $m3->expects($this->never()) - ->method('afterController'); + ->method('afterController'); $m3->method('beforeOutput') ->willReturnArgument(2); diff --git a/tests/lib/AppFramework/Middleware/MiddlewareTest.php b/tests/lib/AppFramework/Middleware/MiddlewareTest.php index f9d8926db7e..addd9683122 100644 --- a/tests/lib/AppFramework/Middleware/MiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/MiddlewareTest.php @@ -1,35 +1,20 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Middleware; +use OC\AppFramework\DependencyInjection\DIContainer; use OC\AppFramework\Http\Request; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\Response; use OCP\AppFramework\Middleware; use OCP\IConfig; use OCP\IRequestId; -use OC\AppFramework\DependencyInjection\DIContainer; class ChildMiddleware extends Middleware { }; @@ -51,12 +36,9 @@ class MiddlewareTest extends \Test\TestCase { $this->middleware = new ChildMiddleware(); - $this->api = $this->getMockBuilder(DIContainer::class) - ->disableOriginalConstructor() - ->getMock(); + $this->api = $this->createMock(DIContainer::class); $this->controller = $this->getMockBuilder(Controller::class) - ->setMethods([]) ->setConstructorArgs([ $this->api, new Request( @@ -66,31 +48,31 @@ class MiddlewareTest extends \Test\TestCase { ) ])->getMock(); $this->exception = new \Exception(); - $this->response = $this->getMockBuilder(Response::class)->getMock(); + $this->response = $this->createMock(Response::class); } - public function testBeforeController() { - $this->middleware->beforeController($this->controller, null); + public function testBeforeController(): void { + $this->middleware->beforeController($this->controller, ''); $this->assertNull(null); } - public function testAfterExceptionRaiseAgainWhenUnhandled() { + public function testAfterExceptionRaiseAgainWhenUnhandled(): void { $this->expectException(\Exception::class); - $this->middleware->afterException($this->controller, null, $this->exception); + $this->middleware->afterException($this->controller, '', $this->exception); } - public function testAfterControllerReturnResponseWhenUnhandled() { - $response = $this->middleware->afterController($this->controller, null, $this->response); + public function testAfterControllerReturnResponseWhenUnhandled(): void { + $response = $this->middleware->afterController($this->controller, '', $this->response); $this->assertEquals($this->response, $response); } - public function testBeforeOutputReturnOutputhenUnhandled() { - $output = $this->middleware->beforeOutput($this->controller, null, 'test'); + public function testBeforeOutputReturnOutputhenUnhandled(): void { + $output = $this->middleware->beforeOutput($this->controller, '', 'test'); $this->assertEquals('test', $output); } diff --git a/tests/lib/AppFramework/Middleware/NotModifiedMiddlewareTest.php b/tests/lib/AppFramework/Middleware/NotModifiedMiddlewareTest.php index 3b69a289e99..7dcb28a2af4 100644 --- a/tests/lib/AppFramework/Middleware/NotModifiedMiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/NotModifiedMiddlewareTest.php @@ -2,25 +2,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, 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: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\AppFramework\Middleware; @@ -28,6 +11,7 @@ namespace Test\AppFramework\Middleware; use OC\AppFramework\Middleware\NotModifiedMiddleware; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Response; use OCP\IRequest; class NotModifiedMiddlewareTest extends \Test\TestCase { @@ -49,7 +33,7 @@ class NotModifiedMiddlewareTest extends \Test\TestCase { $this->controller = $this->createMock(Controller::class); } - public function dataModified(): array { + public static function dataModified(): array { $now = new \DateTime(); return [ @@ -60,20 +44,18 @@ class NotModifiedMiddlewareTest extends \Test\TestCase { [null, '"etag"', null, '', false], ['etag', '"etag"', null, '', true], - [null, '', $now, $now->format(\DateTimeInterface::RFC2822), true], + [null, '', $now, $now->format(\DateTimeInterface::RFC7231), true], [null, '', $now, $now->format(\DateTimeInterface::ATOM), false], - [null, '', null, $now->format(\DateTimeInterface::RFC2822), false], + [null, '', null, $now->format(\DateTimeInterface::RFC7231), false], [null, '', $now, '', false], ['etag', '"etag"', $now, $now->format(\DateTimeInterface::ATOM), true], - ['etag', '"etag"', $now, $now->format(\DateTimeInterface::RFC2822), true], + ['etag', '"etag"', $now, $now->format(\DateTimeInterface::RFC7231), true], ]; } - /** - * @dataProvider dataModified - */ - public function testMiddleware(?string $etag, string $etagHeader, ?\DateTime $lastModified, string $lastModifiedHeader, bool $notModifiedSet) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataModified')] + public function testMiddleware(?string $etag, string $etagHeader, ?\DateTime $lastModified, string $lastModifiedHeader, bool $notModifiedSet): void { $this->request->method('getHeader') ->willReturnCallback(function (string $name) use ($etagHeader, $lastModifiedHeader) { if ($name === 'IF_NONE_MATCH') { @@ -85,7 +67,7 @@ class NotModifiedMiddlewareTest extends \Test\TestCase { return ''; }); - $response = new Http\Response(); + $response = new Response(); if ($etag !== null) { $response->setETag($etag); } diff --git a/tests/lib/AppFramework/Middleware/OCSMiddlewareTest.php b/tests/lib/AppFramework/Middleware/OCSMiddlewareTest.php index 4839ff75b5e..e5c6a417a4b 100644 --- a/tests/lib/AppFramework/Middleware/OCSMiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/OCSMiddlewareTest.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 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\AppFramework\Middleware; @@ -28,6 +13,8 @@ use OC\AppFramework\OCS\V1Response; use OC\AppFramework\OCS\V2Response; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\Http\Response; use OCP\AppFramework\OCS\OCSBadRequestException; use OCP\AppFramework\OCS\OCSException; use OCP\AppFramework\OCS\OCSForbiddenException; @@ -48,49 +35,35 @@ class OCSMiddlewareTest extends \Test\TestCase { ->getMock(); } - public function dataAfterException() { - $OCSController = $this->getMockBuilder(OCSController::class) - ->disableOriginalConstructor() - ->getMock(); - $controller = $this->getMockBuilder(Controller::class) - ->disableOriginalConstructor() - ->getMock(); - + public static function dataAfterException(): array { return [ - [$OCSController, new \Exception(), true], - [$OCSController, new OCSException(), false, '', Http::STATUS_INTERNAL_SERVER_ERROR], - [$OCSController, new OCSException('foo'), false, 'foo', Http::STATUS_INTERNAL_SERVER_ERROR], - [$OCSController, new OCSException('foo', Http::STATUS_IM_A_TEAPOT), false, 'foo', Http::STATUS_IM_A_TEAPOT], - [$OCSController, new OCSBadRequestException(), false, '', Http::STATUS_BAD_REQUEST], - [$OCSController, new OCSBadRequestException('foo'), false, 'foo', Http::STATUS_BAD_REQUEST], - [$OCSController, new OCSForbiddenException(), false, '', Http::STATUS_FORBIDDEN], - [$OCSController, new OCSForbiddenException('foo'), false, 'foo', Http::STATUS_FORBIDDEN], - [$OCSController, new OCSNotFoundException(), false, '', Http::STATUS_NOT_FOUND], - [$OCSController, new OCSNotFoundException('foo'), false, 'foo', Http::STATUS_NOT_FOUND], - - [$controller, new \Exception(), true], - [$controller, new OCSException(), true], - [$controller, new OCSException('foo'), true], - [$controller, new OCSException('foo', Http::STATUS_IM_A_TEAPOT), true], - [$controller, new OCSBadRequestException(), true], - [$controller, new OCSBadRequestException('foo'), true], - [$controller, new OCSForbiddenException(), true], - [$controller, new OCSForbiddenException('foo'), true], - [$controller, new OCSNotFoundException(), true], - [$controller, new OCSNotFoundException('foo'), true], + [OCSController::class, new \Exception(), true], + [OCSController::class, new OCSException(), false, '', Http::STATUS_INTERNAL_SERVER_ERROR], + [OCSController::class, new OCSException('foo'), false, 'foo', Http::STATUS_INTERNAL_SERVER_ERROR], + [OCSController::class, new OCSException('foo', Http::STATUS_IM_A_TEAPOT), false, 'foo', Http::STATUS_IM_A_TEAPOT], + [OCSController::class, new OCSBadRequestException(), false, '', Http::STATUS_BAD_REQUEST], + [OCSController::class, new OCSBadRequestException('foo'), false, 'foo', Http::STATUS_BAD_REQUEST], + [OCSController::class, new OCSForbiddenException(), false, '', Http::STATUS_FORBIDDEN], + [OCSController::class, new OCSForbiddenException('foo'), false, 'foo', Http::STATUS_FORBIDDEN], + [OCSController::class, new OCSNotFoundException(), false, '', Http::STATUS_NOT_FOUND], + [OCSController::class, new OCSNotFoundException('foo'), false, 'foo', Http::STATUS_NOT_FOUND], + + [Controller::class, new \Exception(), true], + [Controller::class, new OCSException(), true], + [Controller::class, new OCSException('foo'), true], + [Controller::class, new OCSException('foo', Http::STATUS_IM_A_TEAPOT), true], + [Controller::class, new OCSBadRequestException(), true], + [Controller::class, new OCSBadRequestException('foo'), true], + [Controller::class, new OCSForbiddenException(), true], + [Controller::class, new OCSForbiddenException('foo'), true], + [Controller::class, new OCSNotFoundException(), true], + [Controller::class, new OCSNotFoundException('foo'), true], ]; } - /** - * @dataProvider dataAfterException - * - * @param Controller $controller - * @param \Exception $exception - * @param bool $forward - * @param string $message - * @param int $code - */ - public function testAfterExceptionOCSv1($controller, $exception, $forward, $message = '', $code = 0) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataAfterException')] + public function testAfterExceptionOCSv1(string $controller, \Exception $exception, bool $forward, string $message = '', int $code = 0): void { + $controller = $this->createMock($controller); $this->request ->method('getScriptName') ->willReturn('/ocs/v1.php'); @@ -109,7 +82,7 @@ class OCSMiddlewareTest extends \Test\TestCase { $this->assertSame($message, $this->invokePrivate($result, 'statusMessage')); if ($exception->getCode() === 0) { - $this->assertSame(\OCP\AppFramework\OCSController::RESPOND_UNKNOWN_ERROR, $result->getOCSStatus()); + $this->assertSame(OCSController::RESPOND_UNKNOWN_ERROR, $result->getOCSStatus()); } else { $this->assertSame($code, $result->getOCSStatus()); } @@ -117,16 +90,9 @@ class OCSMiddlewareTest extends \Test\TestCase { $this->assertSame(Http::STATUS_OK, $result->getStatus()); } - /** - * @dataProvider dataAfterException - * - * @param Controller $controller - * @param \Exception $exception - * @param bool $forward - * @param string $message - * @param int $code - */ - public function testAfterExceptionOCSv2($controller, $exception, $forward, $message = '', $code = 0) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataAfterException')] + public function testAfterExceptionOCSv2(string $controller, \Exception $exception, bool $forward, string $message = '', int $code = 0): void { + $controller = $this->createMock($controller); $this->request ->method('getScriptName') ->willReturn('/ocs/v2.php'); @@ -144,23 +110,16 @@ class OCSMiddlewareTest extends \Test\TestCase { $this->assertSame($message, $this->invokePrivate($result, 'statusMessage')); if ($exception->getCode() === 0) { - $this->assertSame(\OCP\AppFramework\OCSController::RESPOND_UNKNOWN_ERROR, $result->getOCSStatus()); + $this->assertSame(OCSController::RESPOND_UNKNOWN_ERROR, $result->getOCSStatus()); } else { $this->assertSame($code, $result->getOCSStatus()); } $this->assertSame($code, $result->getStatus()); } - /** - * @dataProvider dataAfterException - * - * @param Controller $controller - * @param \Exception $exception - * @param bool $forward - * @param string $message - * @param int $code - */ - public function testAfterExceptionOCSv2SubFolder($controller, $exception, $forward, $message = '', $code = 0) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataAfterException')] + public function testAfterExceptionOCSv2SubFolder(string $controller, \Exception $exception, bool $forward, string $message = '', int $code = 0): void { + $controller = $this->createMock($controller); $this->request ->method('getScriptName') ->willReturn('/mysubfolder/ocs/v2.php'); @@ -168,7 +127,7 @@ class OCSMiddlewareTest extends \Test\TestCase { $OCSMiddleware->beforeController($controller, 'method'); if ($forward) { - $this->expectException(get_class($exception)); + $this->expectException($exception::class); $this->expectExceptionMessage($exception->getMessage()); } @@ -178,46 +137,33 @@ class OCSMiddlewareTest extends \Test\TestCase { $this->assertSame($message, $this->invokePrivate($result, 'statusMessage')); if ($exception->getCode() === 0) { - $this->assertSame(\OCP\AppFramework\OCSController::RESPOND_UNKNOWN_ERROR, $result->getOCSStatus()); + $this->assertSame(OCSController::RESPOND_UNKNOWN_ERROR, $result->getOCSStatus()); } else { $this->assertSame($code, $result->getOCSStatus()); } $this->assertSame($code, $result->getStatus()); } - public function dataAfterController() { - $OCSController = $this->getMockBuilder(OCSController::class) - ->disableOriginalConstructor() - ->getMock(); - $controller = $this->getMockBuilder(Controller::class) - ->disableOriginalConstructor() - ->getMock(); - + public static function dataAfterController(): array { return [ - [$OCSController, new Http\Response(), false], - [$OCSController, new Http\JSONResponse(), false], - [$OCSController, new Http\JSONResponse(['message' => 'foo']), false], - [$OCSController, new Http\JSONResponse(['message' => 'foo'], Http::STATUS_UNAUTHORIZED), true, OCSController::RESPOND_UNAUTHORISED], - [$OCSController, new Http\JSONResponse(['message' => 'foo'], Http::STATUS_FORBIDDEN), true], - - [$controller, new Http\Response(), false], - [$controller, new Http\JSONResponse(), false], - [$controller, new Http\JSONResponse(['message' => 'foo']), false], - [$controller, new Http\JSONResponse(['message' => 'foo'], Http::STATUS_UNAUTHORIZED), false], - [$controller, new Http\JSONResponse(['message' => 'foo'], Http::STATUS_FORBIDDEN), false], + [OCSController::class, new Response(), false], + [OCSController::class, new JSONResponse(), false], + [OCSController::class, new JSONResponse(['message' => 'foo']), false], + [OCSController::class, new JSONResponse(['message' => 'foo'], Http::STATUS_UNAUTHORIZED), true, OCSController::RESPOND_UNAUTHORISED], + [OCSController::class, new JSONResponse(['message' => 'foo'], Http::STATUS_FORBIDDEN), true], + + [Controller::class, new Response(), false], + [Controller::class, new JSONResponse(), false], + [Controller::class, new JSONResponse(['message' => 'foo']), false], + [Controller::class, new JSONResponse(['message' => 'foo'], Http::STATUS_UNAUTHORIZED), false], + [Controller::class, new JSONResponse(['message' => 'foo'], Http::STATUS_FORBIDDEN), false], ]; } - /** - * @dataProvider dataAfterController - * - * @param Controller $controller - * @param Http\Response $response - * @param bool $converted - * @param int $convertedOCSStatus - */ - public function testAfterController($controller, $response, $converted, $convertedOCSStatus = 0) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataAfterController')] + public function testAfterController(string $controller, Response $response, bool $converted, int $convertedOCSStatus = 0): void { + $controller = $this->createMock($controller); $OCSMiddleware = new OCSMiddleware($this->request); $newResponse = $OCSMiddleware->afterController($controller, 'foo', $response); diff --git a/tests/lib/AppFramework/Middleware/PublicShare/PublicShareMiddlewareTest.php b/tests/lib/AppFramework/Middleware/PublicShare/PublicShareMiddlewareTest.php index 3e48078cbad..e87ee7fd565 100644 --- a/tests/lib/AppFramework/Middleware/PublicShare/PublicShareMiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/PublicShare/PublicShareMiddlewareTest.php @@ -1,41 +1,26 @@ <?php + /** - * @copyright 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 Test\AppFramework\Middleware\PublicShare; use OC\AppFramework\Middleware\PublicShare\Exceptions\NeedAuthenticationException; use OC\AppFramework\Middleware\PublicShare\PublicShareMiddleware; -use OC\Security\Bruteforce\Throttler; use OCP\AppFramework\AuthPublicShareController; use OCP\AppFramework\Controller; -use OCP\AppFramework\Http\NotFoundResponse; +use OCP\AppFramework\Http; use OCP\AppFramework\Http\RedirectResponse; +use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\PublicShareController; use OCP\Files\NotFoundException; use OCP\IConfig; use OCP\IRequest; use OCP\ISession; use OCP\IURLGenerator; +use OCP\Security\Bruteforce\IThrottler; class PublicShareMiddlewareTest extends \Test\TestCase { /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */ @@ -44,7 +29,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase { private $session; /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ private $config; - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IThrottler|\PHPUnit\Framework\MockObject\MockObject */ private $throttler; /** @var PublicShareMiddleware */ @@ -57,7 +42,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase { $this->request = $this->createMock(IRequest::class); $this->session = $this->createMock(ISession::class); $this->config = $this->createMock(IConfig::class); - $this->throttler = $this->createMock(Throttler::class); + $this->throttler = $this->createMock(IThrottler::class); $this->middleware = new PublicShareMiddleware( $this->request, @@ -67,14 +52,14 @@ class PublicShareMiddlewareTest extends \Test\TestCase { ); } - public function testBeforeControllerNoPublicShareController() { + public function testBeforeControllerNoPublicShareController(): void { $controller = $this->createMock(Controller::class); $this->middleware->beforeController($controller, 'method'); $this->assertTrue(true); } - public function dataShareApi() { + public static function dataShareApi(): array { return [ ['no', 'no',], ['no', 'yes',], @@ -82,10 +67,8 @@ class PublicShareMiddlewareTest extends \Test\TestCase { ]; } - /** - * @dataProvider dataShareApi - */ - public function testBeforeControllerShareApiDisabled(string $shareApi, string $shareLinks) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataShareApi')] + public function testBeforeControllerShareApiDisabled(string $shareApi, string $shareLinks): void { $controller = $this->createMock(PublicShareController::class); $this->config->method('getAppValue') @@ -98,7 +81,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase { $this->middleware->beforeController($controller, 'mehod'); } - public function testBeforeControllerNoTokenParam() { + public function testBeforeControllerNoTokenParam(): void { $controller = $this->createMock(PublicShareController::class); $this->config->method('getAppValue') @@ -111,7 +94,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase { $this->middleware->beforeController($controller, 'mehod'); } - public function testBeforeControllerInvalidToken() { + public function testBeforeControllerInvalidToken(): void { $controller = $this->createMock(PublicShareController::class); $this->config->method('getAppValue') @@ -133,7 +116,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase { $this->middleware->beforeController($controller, 'mehod'); } - public function testBeforeControllerValidTokenNotAuthenticated() { + public function testBeforeControllerValidTokenNotAuthenticated(): void { $controller = $this->getMockBuilder(PublicShareController::class) ->setConstructorArgs(['app', $this->request, $this->session]) ->getMock(); @@ -158,7 +141,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase { $this->middleware->beforeController($controller, 'mehod'); } - public function testBeforeControllerValidTokenAuthenticateMethod() { + public function testBeforeControllerValidTokenAuthenticateMethod(): void { $controller = $this->getMockBuilder(PublicShareController::class) ->setConstructorArgs(['app', $this->request, $this->session]) ->getMock(); @@ -183,7 +166,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase { $this->assertTrue(true); } - public function testBeforeControllerValidTokenShowAuthenticateMethod() { + public function testBeforeControllerValidTokenShowAuthenticateMethod(): void { $controller = $this->getMockBuilder(PublicShareController::class) ->setConstructorArgs(['app', $this->request, $this->session]) ->getMock(); @@ -208,7 +191,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase { $this->assertTrue(true); } - public function testBeforeControllerAuthPublicShareController() { + public function testBeforeControllerAuthPublicShareController(): void { $controller = $this->getMockBuilder(AuthPublicShareController::class) ->setConstructorArgs(['app', $this->request, $this->session, $this->createMock(IURLGenerator::class)]) ->getMock(); @@ -237,7 +220,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase { $this->middleware->beforeController($controller, 'method'); } - public function testAfterExceptionNoPublicShareController() { + public function testAfterExceptionNoPublicShareController(): void { $controller = $this->createMock(Controller::class); $exception = new \Exception(); @@ -248,15 +231,16 @@ class PublicShareMiddlewareTest extends \Test\TestCase { } } - public function testAfterExceptionPublicShareControllerNotFoundException() { + public function testAfterExceptionPublicShareControllerNotFoundException(): void { $controller = $this->createMock(PublicShareController::class); $exception = new NotFoundException(); $result = $this->middleware->afterException($controller, 'method', $exception); - $this->assertInstanceOf(NotFoundResponse::class, $result); + $this->assertInstanceOf(TemplateResponse::class, $result); + $this->assertEquals($result->getStatus(), Http::STATUS_NOT_FOUND); } - public function testAfterExceptionPublicShareController() { + public function testAfterExceptionPublicShareController(): void { $controller = $this->createMock(PublicShareController::class); $exception = new \Exception(); @@ -267,7 +251,7 @@ class PublicShareMiddlewareTest extends \Test\TestCase { } } - public function testAfterExceptionAuthPublicShareController() { + public function testAfterExceptionAuthPublicShareController(): void { $controller = $this->getMockBuilder(AuthPublicShareController::class) ->setConstructorArgs([ 'app', diff --git a/tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php index 7dfcfe22261..3fd2cb38a33 100644 --- a/tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/Security/BruteForceMiddlewareTest.php @@ -1,68 +1,70 @@ <?php + /** - * @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 Test\AppFramework\Middleware\Security; use OC\AppFramework\Middleware\Security\BruteForceMiddleware; use OC\AppFramework\Utility\ControllerMethodReflector; -use OC\Security\Bruteforce\Throttler; use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\BruteForceProtection; use OCP\AppFramework\Http\Response; use OCP\IRequest; +use OCP\Security\Bruteforce\IThrottler; +use Psr\Log\LoggerInterface; use Test\TestCase; +class TestController extends Controller { + /** + * @BruteForceProtection(action=login) + */ + public function testMethodWithAnnotation() { + } + + public function testMethodWithoutAnnotation() { + } + + #[BruteForceProtection(action: 'single')] + public function singleAttribute(): void { + } + + #[BruteForceProtection(action: 'first')] + #[BruteForceProtection(action: 'second')] + public function multipleAttributes(): void { + } +} + class BruteForceMiddlewareTest extends TestCase { - /** @var ControllerMethodReflector|\PHPUnit\Framework\MockObject\MockObject */ + /** @var ControllerMethodReflector */ private $reflector; - /** @var Throttler|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IThrottler|\PHPUnit\Framework\MockObject\MockObject */ private $throttler; /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */ private $request; + /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */ + private $logger; private BruteForceMiddleware $bruteForceMiddleware; protected function setUp(): void { parent::setUp(); - $this->reflector = $this->createMock(ControllerMethodReflector::class); - $this->throttler = $this->createMock(Throttler::class); + $this->reflector = new ControllerMethodReflector(); + $this->throttler = $this->createMock(IThrottler::class); $this->request = $this->createMock(IRequest::class); + $this->logger = $this->createMock(LoggerInterface::class); $this->bruteForceMiddleware = new BruteForceMiddleware( $this->reflector, $this->throttler, - $this->request + $this->request, + $this->logger, ); } - public function testBeforeControllerWithAnnotation() { - $this->reflector - ->expects($this->once()) - ->method('hasAnnotation') - ->with('BruteForceProtection') - ->willReturn(true); - $this->reflector - ->expects($this->once()) - ->method('getAnnotationParameter') - ->with('BruteForceProtection', 'action') - ->willReturn('login'); + public function testBeforeControllerWithAnnotation(): void { $this->request ->expects($this->once()) ->method('getRemoteAddress') @@ -72,20 +74,51 @@ class BruteForceMiddlewareTest extends TestCase { ->method('sleepDelayOrThrowOnMax') ->with('127.0.0.1', 'login'); - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); - $this->bruteForceMiddleware->beforeController($controller, 'testMethod'); + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'testMethodWithAnnotation'); + $this->bruteForceMiddleware->beforeController($controller, 'testMethodWithAnnotation'); } - public function testBeforeControllerWithoutAnnotation() { - $this->reflector + public function testBeforeControllerWithSingleAttribute(): void { + $this->request ->expects($this->once()) - ->method('hasAnnotation') - ->with('BruteForceProtection') - ->willReturn(false); - $this->reflector - ->expects($this->never()) - ->method('getAnnotationParameter'); + ->method('getRemoteAddress') + ->willReturn('::1'); + $this->throttler + ->expects($this->once()) + ->method('sleepDelayOrThrowOnMax') + ->with('::1', 'single'); + + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'singleAttribute'); + $this->bruteForceMiddleware->beforeController($controller, 'singleAttribute'); + } + + public function testBeforeControllerWithMultipleAttributes(): void { + $this->request + ->expects($this->once()) + ->method('getRemoteAddress') + ->willReturn('::1'); + + $calls = [ + ['::1', 'first'], + ['::1', 'second'], + ]; + $this->throttler + ->expects($this->exactly(2)) + ->method('sleepDelayOrThrowOnMax') + ->willReturnCallback(function () use (&$calls) { + $expected = array_shift($calls); + $this->assertEquals($expected, func_get_args()); + return 0; + }); + + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'multipleAttributes'); + $this->bruteForceMiddleware->beforeController($controller, 'multipleAttributes'); + } + + public function testBeforeControllerWithoutAnnotation(): void { $this->request ->expects($this->never()) ->method('getRemoteAddress'); @@ -93,19 +126,14 @@ class BruteForceMiddlewareTest extends TestCase { ->expects($this->never()) ->method('sleepDelayOrThrowOnMax'); - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); - $this->bruteForceMiddleware->beforeController($controller, 'testMethod'); + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'testMethodWithoutAnnotation'); + $this->bruteForceMiddleware->beforeController($controller, 'testMethodWithoutAnnotation'); } - public function testAfterControllerWithAnnotationAndThrottledRequest() { + public function testAfterControllerWithAnnotationAndThrottledRequest(): void { /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */ $response = $this->createMock(Response::class); - $this->reflector - ->expects($this->once()) - ->method('hasAnnotation') - ->with('BruteForceProtection') - ->willReturn(true); $response ->expects($this->once()) ->method('isThrottled') @@ -114,79 +142,187 @@ class BruteForceMiddlewareTest extends TestCase { ->expects($this->once()) ->method('getThrottleMetadata') ->willReturn([]); - $this->reflector - ->expects($this->once()) - ->method('getAnnotationParameter') - ->with('BruteForceProtection', 'action') - ->willReturn('login'); $this->request ->expects($this->once()) ->method('getRemoteAddress') ->willReturn('127.0.0.1'); $this->throttler ->expects($this->once()) - ->method('sleepDelay') + ->method('sleepDelayOrThrowOnMax') ->with('127.0.0.1', 'login'); $this->throttler ->expects($this->once()) ->method('registerAttempt') ->with('login', '127.0.0.1'); - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); - $this->bruteForceMiddleware->afterController($controller, 'testMethod', $response); + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'testMethodWithAnnotation'); + $this->bruteForceMiddleware->afterController($controller, 'testMethodWithAnnotation', $response); } - public function testAfterControllerWithAnnotationAndNotThrottledRequest() { + public function testAfterControllerWithAnnotationAndNotThrottledRequest(): void { /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */ $response = $this->createMock(Response::class); - $this->reflector - ->expects($this->once()) - ->method('hasAnnotation') - ->with('BruteForceProtection') - ->willReturn(true); $response ->expects($this->once()) ->method('isThrottled') ->willReturn(false); - $this->reflector - ->expects($this->never()) - ->method('getAnnotationParameter'); $this->request ->expects($this->never()) ->method('getRemoteAddress'); $this->throttler ->expects($this->never()) - ->method('sleepDelay'); + ->method('sleepDelayOrThrowOnMax'); $this->throttler ->expects($this->never()) ->method('registerAttempt'); - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); - $this->bruteForceMiddleware->afterController($controller, 'testMethod', $response); + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'testMethodWithAnnotation'); + $this->bruteForceMiddleware->afterController($controller, 'testMethodWithAnnotation', $response); } - public function testAfterControllerWithoutAnnotation() { - $this->reflector + public function testAfterControllerWithSingleAttribute(): void { + /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */ + $response = $this->createMock(Response::class); + $response ->expects($this->once()) - ->method('hasAnnotation') - ->with('BruteForceProtection') - ->willReturn(false); - $this->reflector + ->method('isThrottled') + ->willReturn(true); + $response + ->expects($this->once()) + ->method('getThrottleMetadata') + ->willReturn([]); + + $this->request + ->expects($this->once()) + ->method('getRemoteAddress') + ->willReturn('::1'); + $this->throttler + ->expects($this->once()) + ->method('sleepDelayOrThrowOnMax') + ->with('::1', 'single'); + $this->throttler + ->expects($this->once()) + ->method('registerAttempt') + ->with('single', '::1'); + + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'singleAttribute'); + $this->bruteForceMiddleware->afterController($controller, 'singleAttribute', $response); + } + + public function testAfterControllerWithMultipleAttributesGeneralMatch(): void { + /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */ + $response = $this->createMock(Response::class); + $response + ->expects($this->once()) + ->method('isThrottled') + ->willReturn(true); + $response + ->expects($this->once()) + ->method('getThrottleMetadata') + ->willReturn([]); + + $this->request + ->expects($this->once()) + ->method('getRemoteAddress') + ->willReturn('::1'); + + $sleepCalls = [ + ['::1', 'first'], + ['::1', 'second'], + ]; + $this->throttler + ->expects($this->exactly(2)) + ->method('sleepDelayOrThrowOnMax') + ->willReturnCallback(function () use (&$sleepCalls) { + $expected = array_shift($sleepCalls); + $this->assertEquals($expected, func_get_args()); + return 0; + }); + + $attemptCalls = [ + ['first', '::1', []], + ['second', '::1', []], + ]; + $this->throttler + ->expects($this->exactly(2)) + ->method('registerAttempt') + ->willReturnCallback(function () use (&$attemptCalls): void { + $expected = array_shift($attemptCalls); + $this->assertEquals($expected, func_get_args()); + }); + + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'multipleAttributes'); + $this->bruteForceMiddleware->afterController($controller, 'multipleAttributes', $response); + } + + public function testAfterControllerWithMultipleAttributesSpecificMatch(): void { + /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */ + $response = $this->createMock(Response::class); + $response + ->expects($this->once()) + ->method('isThrottled') + ->willReturn(true); + $response + ->expects($this->once()) + ->method('getThrottleMetadata') + ->willReturn(['action' => 'second']); + + $this->request + ->expects($this->once()) + ->method('getRemoteAddress') + ->willReturn('::1'); + $this->throttler + ->expects($this->once()) + ->method('sleepDelayOrThrowOnMax') + ->with('::1', 'second'); + $this->throttler + ->expects($this->once()) + ->method('registerAttempt') + ->with('second', '::1'); + + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'multipleAttributes'); + $this->bruteForceMiddleware->afterController($controller, 'multipleAttributes', $response); + } + + public function testAfterControllerWithoutAnnotation(): void { + $this->request + ->expects($this->never()) + ->method('getRemoteAddress'); + $this->throttler ->expects($this->never()) - ->method('getAnnotationParameter'); + ->method('sleepDelayOrThrowOnMax'); + + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'testMethodWithoutAnnotation'); + /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */ + $response = $this->createMock(Response::class); + $this->bruteForceMiddleware->afterController($controller, 'testMethodWithoutAnnotation', $response); + } + + public function testAfterControllerWithThrottledResponseButUnhandled(): void { $this->request ->expects($this->never()) ->method('getRemoteAddress'); $this->throttler ->expects($this->never()) - ->method('sleepDelay'); + ->method('sleepDelayOrThrowOnMax'); - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); + $controller = new TestController('test', $this->request); + $this->reflector->reflect($controller, 'testMethodWithoutAnnotation'); /** @var Response|\PHPUnit\Framework\MockObject\MockObject $response */ $response = $this->createMock(Response::class); - $this->bruteForceMiddleware->afterController($controller, 'testMethod', $response); + $response->method('isThrottled') + ->willReturn(true); + + $this->logger->expects($this->once()) + ->method('debug') + ->with('Response for Test\AppFramework\Middleware\Security\TestController::testMethodWithoutAnnotation got bruteforce throttled but has no annotation nor attribute defined.'); + + $this->bruteForceMiddleware->afterController($controller, 'testMethodWithoutAnnotation', $response); } } diff --git a/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php index f3c1f7934ef..c325ae638fb 100644 --- a/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php @@ -1,50 +1,60 @@ <?php + /** - * ownCloud - App Framework - * - * This file is licensed under the Affero General Public License version 3 or - * later. See the COPYING file. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @copyright Bernhard Posselt 2014 + * SPDX-FileCopyrightText: 2016-2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2014-2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace Test\AppFramework\Middleware\Security; use OC\AppFramework\Http\Request; use OC\AppFramework\Middleware\Security\CORSMiddleware; use OC\AppFramework\Middleware\Security\Exceptions\SecurityException; use OC\AppFramework\Utility\ControllerMethodReflector; -use OC\Security\Bruteforce\Throttler; +use OC\Authentication\Exceptions\PasswordLoginForbiddenException; use OC\User\Session; -use OCP\AppFramework\Controller; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\Response; use OCP\IConfig; +use OCP\IRequest; use OCP\IRequestId; +use OCP\Security\Bruteforce\IThrottler; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; +use Test\AppFramework\Middleware\Security\Mock\CORSMiddlewareController; class CORSMiddlewareTest extends \Test\TestCase { /** @var ControllerMethodReflector */ private $reflector; - /** @var Session|\PHPUnit\Framework\MockObject\MockObject */ + /** @var Session|MockObject */ private $session; - /** @var Throttler */ + /** @var IThrottler|MockObject */ private $throttler; - /** @var Controller */ + /** @var CORSMiddlewareController */ private $controller; + private LoggerInterface $logger; protected function setUp(): void { parent::setUp(); $this->reflector = new ControllerMethodReflector(); $this->session = $this->createMock(Session::class); - $this->throttler = $this->createMock(Throttler::class); - $this->controller = $this->createMock(Controller::class); + $this->throttler = $this->createMock(IThrottler::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->controller = new CORSMiddlewareController( + 'test', + $this->createMock(IRequest::class) + ); + } + + public static function dataSetCORSAPIHeader(): array { + return [ + ['testSetCORSAPIHeader'], + ['testSetCORSAPIHeaderAttribute'], + ]; } - /** - * @CORS - */ - public function testSetCORSAPIHeader() { + #[\PHPUnit\Framework\Attributes\DataProvider('dataSetCORSAPIHeader')] + public function testSetCORSAPIHeader(string $method): void { $request = new Request( [ 'server' => [ @@ -54,16 +64,15 @@ class CORSMiddlewareTest extends \Test\TestCase { $this->createMock(IRequestId::class), $this->createMock(IConfig::class) ); - $this->reflector->reflect($this, __FUNCTION__); - $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler); + $this->reflector->reflect($this->controller, $method); + $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger); - $response = $middleware->afterController($this->controller, __FUNCTION__, new Response()); + $response = $middleware->afterController($this->controller, $method, new Response()); $headers = $response->getHeaders(); $this->assertEquals('test', $headers['Access-Control-Allow-Origin']); } - - public function testNoAnnotationNoCORSHEADER() { + public function testNoAnnotationNoCORSHEADER(): void { $request = new Request( [ 'server' => [ @@ -73,37 +82,45 @@ class CORSMiddlewareTest extends \Test\TestCase { $this->createMock(IRequestId::class), $this->createMock(IConfig::class) ); - $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler); + $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger); $response = $middleware->afterController($this->controller, __FUNCTION__, new Response()); $headers = $response->getHeaders(); $this->assertFalse(array_key_exists('Access-Control-Allow-Origin', $headers)); } + public static function dataNoOriginHeaderNoCORSHEADER(): array { + return [ + ['testNoOriginHeaderNoCORSHEADER'], + ['testNoOriginHeaderNoCORSHEADERAttribute'], + ]; + } - /** - * @CORS - */ - public function testNoOriginHeaderNoCORSHEADER() { + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoOriginHeaderNoCORSHEADER')] + public function testNoOriginHeaderNoCORSHEADER(string $method): void { $request = new Request( [], $this->createMock(IRequestId::class), $this->createMock(IConfig::class) ); - $this->reflector->reflect($this, __FUNCTION__); - $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler); + $this->reflector->reflect($this->controller, $method); + $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger); - $response = $middleware->afterController($this->controller, __FUNCTION__, new Response()); + $response = $middleware->afterController($this->controller, $method, new Response()); $headers = $response->getHeaders(); $this->assertFalse(array_key_exists('Access-Control-Allow-Origin', $headers)); } + public static function dataCorsIgnoredIfWithCredentialsHeaderPresent(): array { + return [ + ['testCorsIgnoredIfWithCredentialsHeaderPresent'], + ['testCorsAttributeIgnoredIfWithCredentialsHeaderPresent'], + ]; + } - /** - * @CORS - */ - public function testCorsIgnoredIfWithCredentialsHeaderPresent() { - $this->expectException(\OC\AppFramework\Middleware\Security\Exceptions\SecurityException::class); + #[\PHPUnit\Framework\Attributes\DataProvider('dataCorsIgnoredIfWithCredentialsHeaderPresent')] + public function testCorsIgnoredIfWithCredentialsHeaderPresent(string $method): void { + $this->expectException(SecurityException::class); $request = new Request( [ @@ -114,41 +131,87 @@ class CORSMiddlewareTest extends \Test\TestCase { $this->createMock(IRequestId::class), $this->createMock(IConfig::class) ); - $this->reflector->reflect($this, __FUNCTION__); - $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler); + $this->reflector->reflect($this->controller, $method); + $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger); $response = new Response(); $response->addHeader('AcCess-control-Allow-Credentials ', 'TRUE'); - $middleware->afterController($this->controller, __FUNCTION__, $response); + $middleware->afterController($this->controller, $method, $response); } - /** - * @CORS - * @PublicPage - */ - public function testNoCORSShouldAllowCookieAuth() { + public static function dataNoCORSOnAnonymousPublicPage(): array { + return [ + ['testNoCORSOnAnonymousPublicPage'], + ['testNoCORSOnAnonymousPublicPageAttribute'], + ['testNoCORSAttributeOnAnonymousPublicPage'], + ['testNoCORSAttributeOnAnonymousPublicPageAttribute'], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCORSOnAnonymousPublicPage')] + public function testNoCORSOnAnonymousPublicPage(string $method): void { $request = new Request( [], $this->createMock(IRequestId::class), $this->createMock(IConfig::class) ); - $this->reflector->reflect($this, __FUNCTION__); - $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler); + $this->reflector->reflect($this->controller, $method); + $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger); + $this->session->expects($this->once()) + ->method('isLoggedIn') + ->willReturn(false); $this->session->expects($this->never()) ->method('logout'); $this->session->expects($this->never()) ->method('logClientIn') ->with($this->equalTo('user'), $this->equalTo('pass')) ->willReturn(true); - $this->reflector->reflect($this, __FUNCTION__); + $this->reflector->reflect($this->controller, $method); + + $middleware->beforeController($this->controller, $method); + } - $middleware->beforeController($this->controller, __FUNCTION__); + public static function dataCORSShouldNeverAllowCookieAuth(): array { + return [ + ['testCORSShouldNeverAllowCookieAuth'], + ['testCORSShouldNeverAllowCookieAuthAttribute'], + ['testCORSAttributeShouldNeverAllowCookieAuth'], + ['testCORSAttributeShouldNeverAllowCookieAuthAttribute'], + ]; } - /** - * @CORS - */ - public function testCORSShouldRelogin() { + #[\PHPUnit\Framework\Attributes\DataProvider('dataCORSShouldNeverAllowCookieAuth')] + public function testCORSShouldNeverAllowCookieAuth(string $method): void { + $request = new Request( + [], + $this->createMock(IRequestId::class), + $this->createMock(IConfig::class) + ); + $this->reflector->reflect($this->controller, $method); + $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger); + $this->session->expects($this->once()) + ->method('isLoggedIn') + ->willReturn(true); + $this->session->expects($this->once()) + ->method('logout'); + $this->session->expects($this->never()) + ->method('logClientIn') + ->with($this->equalTo('user'), $this->equalTo('pass')) + ->willReturn(true); + + $this->expectException(SecurityException::class); + $middleware->beforeController($this->controller, $method); + } + + public static function dataCORSShouldRelogin(): array { + return [ + ['testCORSShouldRelogin'], + ['testCORSAttributeShouldRelogin'], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataCORSShouldRelogin')] + public function testCORSShouldRelogin(string $method): void { $request = new Request( ['server' => [ 'PHP_AUTH_USER' => 'user', @@ -163,17 +226,22 @@ class CORSMiddlewareTest extends \Test\TestCase { ->method('logClientIn') ->with($this->equalTo('user'), $this->equalTo('pass')) ->willReturn(true); - $this->reflector->reflect($this, __FUNCTION__); - $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler); + $this->reflector->reflect($this->controller, $method); + $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger); - $middleware->beforeController($this->controller, __FUNCTION__); + $middleware->beforeController($this->controller, $method); } - /** - * @CORS - */ - public function testCORSShouldFailIfPasswordLoginIsForbidden() { - $this->expectException(\OC\AppFramework\Middleware\Security\Exceptions\SecurityException::class); + public static function dataCORSShouldFailIfPasswordLoginIsForbidden(): array { + return [ + ['testCORSShouldFailIfPasswordLoginIsForbidden'], + ['testCORSAttributeShouldFailIfPasswordLoginIsForbidden'], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataCORSShouldFailIfPasswordLoginIsForbidden')] + public function testCORSShouldFailIfPasswordLoginIsForbidden(string $method): void { + $this->expectException(SecurityException::class); $request = new Request( ['server' => [ @@ -188,18 +256,23 @@ class CORSMiddlewareTest extends \Test\TestCase { $this->session->expects($this->once()) ->method('logClientIn') ->with($this->equalTo('user'), $this->equalTo('pass')) - ->will($this->throwException(new \OC\Authentication\Exceptions\PasswordLoginForbiddenException)); - $this->reflector->reflect($this, __FUNCTION__); - $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler); + ->willThrowException(new PasswordLoginForbiddenException); + $this->reflector->reflect($this->controller, $method); + $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger); + + $middleware->beforeController($this->controller, $method); + } - $middleware->beforeController($this->controller, __FUNCTION__); + public static function dataCORSShouldNotAllowCookieAuth(): array { + return [ + ['testCORSShouldNotAllowCookieAuth'], + ['testCORSAttributeShouldNotAllowCookieAuth'], + ]; } - /** - * @CORS - */ - public function testCORSShouldNotAllowCookieAuth() { - $this->expectException(\OC\AppFramework\Middleware\Security\Exceptions\SecurityException::class); + #[\PHPUnit\Framework\Attributes\DataProvider('dataCORSShouldNotAllowCookieAuth')] + public function testCORSShouldNotAllowCookieAuth(string $method): void { + $this->expectException(SecurityException::class); $request = new Request( ['server' => [ @@ -215,13 +288,13 @@ class CORSMiddlewareTest extends \Test\TestCase { ->method('logClientIn') ->with($this->equalTo('user'), $this->equalTo('pass')) ->willReturn(false); - $this->reflector->reflect($this, __FUNCTION__); - $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler); + $this->reflector->reflect($this->controller, $method); + $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger); - $middleware->beforeController($this->controller, __FUNCTION__); + $middleware->beforeController($this->controller, $method); } - public function testAfterExceptionWithSecurityExceptionNoStatus() { + public function testAfterExceptionWithSecurityExceptionNoStatus(): void { $request = new Request( ['server' => [ 'PHP_AUTH_USER' => 'user', @@ -230,14 +303,14 @@ class CORSMiddlewareTest extends \Test\TestCase { $this->createMock(IRequestId::class), $this->createMock(IConfig::class) ); - $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler); + $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger); $response = $middleware->afterException($this->controller, __FUNCTION__, new SecurityException('A security exception')); $expected = new JSONResponse(['message' => 'A security exception'], 500); $this->assertEquals($expected, $response); } - public function testAfterExceptionWithSecurityExceptionWithStatus() { + public function testAfterExceptionWithSecurityExceptionWithStatus(): void { $request = new Request( ['server' => [ 'PHP_AUTH_USER' => 'user', @@ -246,15 +319,14 @@ class CORSMiddlewareTest extends \Test\TestCase { $this->createMock(IRequestId::class), $this->createMock(IConfig::class) ); - $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler); + $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger); $response = $middleware->afterException($this->controller, __FUNCTION__, new SecurityException('A security exception', 501)); $expected = new JSONResponse(['message' => 'A security exception'], 501); $this->assertEquals($expected, $response); } - - public function testAfterExceptionWithRegularException() { + public function testAfterExceptionWithRegularException(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('A regular exception'); @@ -266,7 +338,7 @@ class CORSMiddlewareTest extends \Test\TestCase { $this->createMock(IRequestId::class), $this->createMock(IConfig::class) ); - $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler); + $middleware = new CORSMiddleware($request, $this->reflector, $this->session, $this->throttler, $this->logger); $middleware->afterException($this->controller, __FUNCTION__, new \Exception('A regular exception')); } } diff --git a/tests/lib/AppFramework/Middleware/Security/CSPMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/CSPMiddlewareTest.php index 284634f7db2..b0b41b27cb9 100644 --- a/tests/lib/AppFramework/Middleware/Security/CSPMiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/Security/CSPMiddlewareTest.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\AppFramework\Middleware\Security; @@ -29,23 +12,19 @@ use OC\AppFramework\Middleware\Security\CSPMiddleware; use OC\Security\CSP\ContentSecurityPolicy; use OC\Security\CSP\ContentSecurityPolicyManager; use OC\Security\CSP\ContentSecurityPolicyNonceManager; -use OC\Security\CSRF\CsrfToken; -use OC\Security\CSRF\CsrfTokenManager; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\EmptyContentSecurityPolicy; use OCP\AppFramework\Http\Response; use PHPUnit\Framework\MockObject\MockObject; class CSPMiddlewareTest extends \Test\TestCase { - /** @var CSPMiddleware|MockObject */ + /** @var CSPMiddleware&MockObject */ private $middleware; - /** @var Controller|MockObject */ + /** @var Controller&MockObject */ private $controller; - /** @var ContentSecurityPolicyManager|MockObject */ + /** @var ContentSecurityPolicyManager&MockObject */ private $contentSecurityPolicyManager; - /** @var CsrfTokenManager|MockObject */ - private $csrfTokenManager; - /** @var ContentSecurityPolicyNonceManager|MockObject */ + /** @var ContentSecurityPolicyNonceManager&MockObject */ private $cspNonceManager; protected function setUp(): void { @@ -53,16 +32,14 @@ class CSPMiddlewareTest extends \Test\TestCase { $this->controller = $this->createMock(Controller::class); $this->contentSecurityPolicyManager = $this->createMock(ContentSecurityPolicyManager::class); - $this->csrfTokenManager = $this->createMock(CsrfTokenManager::class); $this->cspNonceManager = $this->createMock(ContentSecurityPolicyNonceManager::class); $this->middleware = new CSPMiddleware( $this->contentSecurityPolicyManager, $this->cspNonceManager, - $this->csrfTokenManager ); } - public function testAfterController() { + public function testAfterController(): void { $this->cspNonceManager ->expects($this->once()) ->method('browserSupportsCspV3') @@ -94,7 +71,7 @@ class CSPMiddlewareTest extends \Test\TestCase { $this->middleware->afterController($this->controller, 'test', $response); } - public function testAfterControllerEmptyCSP() { + public function testAfterControllerEmptyCSP(): void { $response = $this->createMock(Response::class); $emptyPolicy = new EmptyContentSecurityPolicy(); $response->expects($this->any()) @@ -106,19 +83,15 @@ class CSPMiddlewareTest extends \Test\TestCase { $this->middleware->afterController($this->controller, 'test', $response); } - public function testAfterControllerWithContentSecurityPolicy3Support() { + public function testAfterControllerWithContentSecurityPolicy3Support(): void { $this->cspNonceManager ->expects($this->once()) ->method('browserSupportsCspV3') ->willReturn(true); - $token = $this->createMock(CsrfToken::class); - $token - ->expects($this->once()) - ->method('getEncryptedValue') - ->willReturn('MyEncryptedToken'); - $this->csrfTokenManager + $token = base64_encode('the-nonce'); + $this->cspNonceManager ->expects($this->once()) - ->method('getToken') + ->method('getNonce') ->willReturn($token); $response = $this->createMock(Response::class); $defaultPolicy = new ContentSecurityPolicy(); diff --git a/tests/lib/AppFramework/Middleware/Security/FeaturePolicyMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/FeaturePolicyMiddlewareTest.php index 154b43f69a5..55a70d4c040 100644 --- a/tests/lib/AppFramework/Middleware/Security/FeaturePolicyMiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/Security/FeaturePolicyMiddlewareTest.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\AppFramework\Middleware\Security; @@ -51,7 +34,7 @@ class FeaturePolicyMiddlewareTest extends \Test\TestCase { ); } - public function testAfterController() { + public function testAfterController(): void { $response = $this->createMock(Response::class); $defaultPolicy = new FeaturePolicy(); $defaultPolicy->addAllowedCameraDomain('defaultpolicy'); @@ -73,7 +56,7 @@ class FeaturePolicyMiddlewareTest extends \Test\TestCase { $this->middleware->afterController($this->controller, 'test', $response); } - public function testAfterControllerEmptyCSP() { + public function testAfterControllerEmptyCSP(): void { $response = $this->createMock(Response::class); $emptyPolicy = new EmptyFeaturePolicy(); $response->method('getFeaturePolicy') diff --git a/tests/lib/AppFramework/Middleware/Security/Mock/CORSMiddlewareController.php b/tests/lib/AppFramework/Middleware/Security/Mock/CORSMiddlewareController.php new file mode 100644 index 00000000000..8ab3a48b62e --- /dev/null +++ b/tests/lib/AppFramework/Middleware/Security/Mock/CORSMiddlewareController.php @@ -0,0 +1,145 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\AppFramework\Middleware\Security\Mock; + +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\CORS; +use OCP\AppFramework\Http\Attribute\PublicPage; + +class CORSMiddlewareController extends Controller { + /** + * @CORS + */ + public function testSetCORSAPIHeader() { + } + + #[CORS] + public function testSetCORSAPIHeaderAttribute() { + } + + public function testNoAnnotationNoCORSHEADER() { + } + + /** + * @CORS + */ + public function testNoOriginHeaderNoCORSHEADER() { + } + + #[CORS] + public function testNoOriginHeaderNoCORSHEADERAttribute() { + } + + /** + * @CORS + */ + public function testCorsIgnoredIfWithCredentialsHeaderPresent() { + } + + #[CORS] + public function testCorsAttributeIgnoredIfWithCredentialsHeaderPresent() { + } + + /** + * CORS must not be enforced for anonymous users on public pages + * + * @CORS + * @PublicPage + */ + public function testNoCORSOnAnonymousPublicPage() { + } + + /** + * CORS must not be enforced for anonymous users on public pages + * + * @CORS + */ + #[PublicPage] + public function testNoCORSOnAnonymousPublicPageAttribute() { + } + + /** + * @PublicPage + */ + #[CORS] + public function testNoCORSAttributeOnAnonymousPublicPage() { + } + + #[CORS] + #[PublicPage] + public function testNoCORSAttributeOnAnonymousPublicPageAttribute() { + } + + /** + * @CORS + * @PublicPage + */ + public function testCORSShouldNeverAllowCookieAuth() { + } + + /** + * @CORS + */ + #[PublicPage] + public function testCORSShouldNeverAllowCookieAuthAttribute() { + } + + /** + * @PublicPage + */ + #[CORS] + public function testCORSAttributeShouldNeverAllowCookieAuth() { + } + + #[CORS] + #[PublicPage] + public function testCORSAttributeShouldNeverAllowCookieAuthAttribute() { + } + + /** + * @CORS + */ + public function testCORSShouldRelogin() { + } + + #[CORS] + public function testCORSAttributeShouldRelogin() { + } + + /** + * @CORS + */ + public function testCORSShouldFailIfPasswordLoginIsForbidden() { + } + + #[CORS] + public function testCORSAttributeShouldFailIfPasswordLoginIsForbidden() { + } + + /** + * @CORS + */ + public function testCORSShouldNotAllowCookieAuth() { + } + + #[CORS] + public function testCORSAttributeShouldNotAllowCookieAuth() { + } + + public function testAfterExceptionWithSecurityExceptionNoStatus() { + } + + public function testAfterExceptionWithSecurityExceptionWithStatus() { + } + + + public function testAfterExceptionWithRegularException() { + } +} diff --git a/tests/lib/AppFramework/Middleware/Security/Mock/NormalController.php b/tests/lib/AppFramework/Middleware/Security/Mock/NormalController.php new file mode 100644 index 00000000000..4d6778e98b9 --- /dev/null +++ b/tests/lib/AppFramework/Middleware/Security/Mock/NormalController.php @@ -0,0 +1,17 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\AppFramework\Middleware\Security\Mock; + +use OCP\AppFramework\Controller; + +class NormalController extends Controller { + public function foo() { + } +} diff --git a/tests/lib/AppFramework/Middleware/Security/Mock/OCSController.php b/tests/lib/AppFramework/Middleware/Security/Mock/OCSController.php new file mode 100644 index 00000000000..93e793ecca9 --- /dev/null +++ b/tests/lib/AppFramework/Middleware/Security/Mock/OCSController.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\AppFramework\Middleware\Security\Mock; + +class OCSController extends \OCP\AppFramework\OCSController { + public function foo() { + } +} diff --git a/tests/lib/AppFramework/Middleware/Security/Mock/PasswordConfirmationMiddlewareController.php b/tests/lib/AppFramework/Middleware/Security/Mock/PasswordConfirmationMiddlewareController.php new file mode 100644 index 00000000000..cd1cdaa49ca --- /dev/null +++ b/tests/lib/AppFramework/Middleware/Security/Mock/PasswordConfirmationMiddlewareController.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\AppFramework\Middleware\Security\Mock; + +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired; + +class PasswordConfirmationMiddlewareController extends Controller { + public function testNoAnnotationNorAttribute() { + } + + /** + * @TestAnnotation + */ + public function testDifferentAnnotation() { + } + + /** + * @PasswordConfirmationRequired + */ + public function testAnnotation() { + } + + #[PasswordConfirmationRequired] + public function testAttribute() { + } + + #[PasswordConfirmationRequired] + public function testSSO() { + } +} diff --git a/tests/lib/AppFramework/Middleware/Security/Mock/SecurityMiddlewareController.php b/tests/lib/AppFramework/Middleware/Security/Mock/SecurityMiddlewareController.php new file mode 100644 index 00000000000..c8f9878b0c1 --- /dev/null +++ b/tests/lib/AppFramework/Middleware/Security/Mock/SecurityMiddlewareController.php @@ -0,0 +1,171 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\AppFramework\Middleware\Security\Mock; + +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\ExAppRequired; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\NoCSRFRequired; +use OCP\AppFramework\Http\Attribute\PublicPage; +use OCP\AppFramework\Http\Attribute\StrictCookiesRequired; +use OCP\AppFramework\Http\Attribute\SubAdminRequired; + +class SecurityMiddlewareController extends Controller { + /** + * @PublicPage + * @NoCSRFRequired + */ + public function testAnnotationNoCSRFRequiredPublicPage() { + } + + /** + * @NoCSRFRequired + */ + #[PublicPage] + public function testAnnotationNoCSRFRequiredAttributePublicPage() { + } + + /** + * @PublicPage + */ + #[NoCSRFRequired] + public function testAnnotationPublicPageAttributeNoCSRFRequired() { + } + + #[NoCSRFRequired] + #[PublicPage] + public function testAttributeNoCSRFRequiredPublicPage() { + } + + public function testNoAnnotationNorAttribute() { + } + + /** + * @NoCSRFRequired + */ + public function testAnnotationNoCSRFRequired() { + } + + #[NoCSRFRequired] + public function testAttributeNoCSRFRequired() { + } + + /** + * @PublicPage + */ + public function testAnnotationPublicPage() { + } + + #[PublicPage] + public function testAttributePublicPage() { + } + + /** + * @PublicPage + * @StrictCookieRequired + */ + public function testAnnotationPublicPageStrictCookieRequired() { + } + + /** + * @StrictCookieRequired + */ + #[PublicPage] + public function testAnnotationStrictCookieRequiredAttributePublicPage() { + } + + /** + * @PublicPage + */ + #[StrictCookiesRequired] + public function testAnnotationPublicPageAttributeStrictCookiesRequired() { + } + + #[PublicPage] + #[StrictCookiesRequired] + public function testAttributePublicPageStrictCookiesRequired() { + } + + /** + * @PublicPage + * @NoCSRFRequired + * @StrictCookieRequired + */ + public function testAnnotationNoCSRFRequiredPublicPageStrictCookieRequired() { + } + + #[NoCSRFRequired] + #[PublicPage] + #[StrictCookiesRequired] + public function testAttributeNoCSRFRequiredPublicPageStrictCookiesRequired() { + } + + /** + * @NoCSRFRequired + * @NoAdminRequired + */ + public function testAnnotationNoAdminRequiredNoCSRFRequired() { + } + + #[NoAdminRequired] + #[NoCSRFRequired] + public function testAttributeNoAdminRequiredNoCSRFRequired() { + } + + /** + * @NoCSRFRequired + * @SubAdminRequired + */ + public function testAnnotationNoCSRFRequiredSubAdminRequired() { + } + + /** + * @SubAdminRequired + */ + #[NoCSRFRequired] + public function testAnnotationNoCSRFRequiredAttributeSubAdminRequired() { + } + + /** + * @NoCSRFRequired + */ + #[SubAdminRequired] + public function testAnnotationSubAdminRequiredAttributeNoCSRFRequired() { + } + + #[NoCSRFRequired] + #[SubAdminRequired] + public function testAttributeNoCSRFRequiredSubAdminRequired() { + } + + /** + * @PublicPage + * @NoAdminRequired + * @NoCSRFRequired + */ + public function testAnnotationNoAdminRequiredNoCSRFRequiredPublicPage() { + } + + #[NoAdminRequired] + #[NoCSRFRequired] + #[PublicPage] + public function testAttributeNoAdminRequiredNoCSRFRequiredPublicPage() { + } + + /** + * @ExAppRequired + */ + public function testAnnotationExAppRequired() { + } + + #[ExAppRequired] + public function testAttributeExAppRequired() { + } +} diff --git a/tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php index 3153d7f0b08..90e801ca471 100644 --- a/tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/Security/PasswordConfirmationMiddlewareTest.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright 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 Test\AppFramework\Middleware\Security; @@ -26,74 +10,90 @@ namespace Test\AppFramework\Middleware\Security; use OC\AppFramework\Middleware\Security\Exceptions\NotConfirmedException; use OC\AppFramework\Middleware\Security\PasswordConfirmationMiddleware; use OC\AppFramework\Utility\ControllerMethodReflector; -use OCP\AppFramework\Controller; +use OC\Authentication\Token\IProvider; +use OC\User\Manager; use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Authentication\Token\IToken; +use OCP\IRequest; use OCP\ISession; use OCP\IUser; use OCP\IUserSession; +use Psr\Log\LoggerInterface; +use Test\AppFramework\Middleware\Security\Mock\PasswordConfirmationMiddlewareController; use Test\TestCase; class PasswordConfirmationMiddlewareTest extends TestCase { /** @var ControllerMethodReflector */ private $reflector; - /** @var ISession|\PHPUnit\Framework\MockObject\MockObject */ + /** @var ISession&\PHPUnit\Framework\MockObject\MockObject */ private $session; - /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IUserSession&\PHPUnit\Framework\MockObject\MockObject */ private $userSession; - /** @var IUser|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IUser&\PHPUnit\Framework\MockObject\MockObject */ private $user; /** @var PasswordConfirmationMiddleware */ private $middleware; - /** @var Controller */ - private $contoller; - /** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */ + /** @var PasswordConfirmationMiddlewareController */ + private $controller; + /** @var ITimeFactory&\PHPUnit\Framework\MockObject\MockObject */ private $timeFactory; + private IProvider&\PHPUnit\Framework\MockObject\MockObject $tokenProvider; + private LoggerInterface $logger; + /** @var IRequest&\PHPUnit\Framework\MockObject\MockObject */ + private IRequest $request; + /** @var Manager&\PHPUnit\Framework\MockObject\MockObject */ + private Manager $userManager; protected function setUp(): void { $this->reflector = new ControllerMethodReflector(); $this->session = $this->createMock(ISession::class); $this->userSession = $this->createMock(IUserSession::class); $this->user = $this->createMock(IUser::class); - $this->contoller = $this->createMock(Controller::class); $this->timeFactory = $this->createMock(ITimeFactory::class); + $this->tokenProvider = $this->createMock(IProvider::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->request = $this->createMock(IRequest::class); + $this->userManager = $this->createMock(Manager::class); + $this->controller = new PasswordConfirmationMiddlewareController( + 'test', + $this->createMock(IRequest::class) + ); $this->middleware = new PasswordConfirmationMiddleware( $this->reflector, $this->session, $this->userSession, - $this->timeFactory + $this->timeFactory, + $this->tokenProvider, + $this->logger, + $this->request, + $this->userManager, ); } - public function testNoAnnotation() { - $this->reflector->reflect(__CLASS__, __FUNCTION__); + public function testNoAnnotationNorAttribute(): void { + $this->reflector->reflect($this->controller, __FUNCTION__); $this->session->expects($this->never()) ->method($this->anything()); $this->userSession->expects($this->never()) ->method($this->anything()); - $this->middleware->beforeController($this->contoller, __FUNCTION__); + $this->middleware->beforeController($this->controller, __FUNCTION__); } - /** - * @TestAnnotation - */ - public function testDifferentAnnotation() { - $this->reflector->reflect(__CLASS__, __FUNCTION__); + public function testDifferentAnnotation(): void { + $this->reflector->reflect($this->controller, __FUNCTION__); $this->session->expects($this->never()) ->method($this->anything()); $this->userSession->expects($this->never()) ->method($this->anything()); - $this->middleware->beforeController($this->contoller, __FUNCTION__); + $this->middleware->beforeController($this->controller, __FUNCTION__); } - /** - * @PasswordConfirmationRequired - * @dataProvider dataProvider - */ - public function testAnnotation($backend, $lastConfirm, $currentTime, $exception) { - $this->reflector->reflect(__CLASS__, __FUNCTION__); + #[\PHPUnit\Framework\Attributes\DataProvider('dataProvider')] + public function testAnnotation($backend, $lastConfirm, $currentTime, $exception): void { + $this->reflector->reflect($this->controller, __FUNCTION__); $this->user->method('getBackendClassName') ->willReturn($backend); @@ -107,9 +107,16 @@ class PasswordConfirmationMiddlewareTest extends TestCase { $this->timeFactory->method('getTime') ->willReturn($currentTime); + $token = $this->createMock(IToken::class); + $token->method('getScopeAsArray') + ->willReturn([]); + $this->tokenProvider->expects($this->once()) + ->method('getToken') + ->willReturn($token); + $thrown = false; try { - $this->middleware->beforeController($this->contoller, __FUNCTION__); + $this->middleware->beforeController($this->controller, __FUNCTION__); } catch (NotConfirmedException $e) { $thrown = true; } @@ -117,7 +124,42 @@ class PasswordConfirmationMiddlewareTest extends TestCase { $this->assertSame($exception, $thrown); } - public function dataProvider() { + #[\PHPUnit\Framework\Attributes\DataProvider('dataProvider')] + public function testAttribute($backend, $lastConfirm, $currentTime, $exception): void { + $this->reflector->reflect($this->controller, __FUNCTION__); + + $this->user->method('getBackendClassName') + ->willReturn($backend); + $this->userSession->method('getUser') + ->willReturn($this->user); + + $this->session->method('get') + ->with('last-password-confirm') + ->willReturn($lastConfirm); + + $this->timeFactory->method('getTime') + ->willReturn($currentTime); + + $token = $this->createMock(IToken::class); + $token->method('getScopeAsArray') + ->willReturn([]); + $this->tokenProvider->expects($this->once()) + ->method('getToken') + ->willReturn($token); + + $thrown = false; + try { + $this->middleware->beforeController($this->controller, __FUNCTION__); + } catch (NotConfirmedException $e) { + $thrown = true; + } + + $this->assertSame($exception, $thrown); + } + + + + public static function dataProvider(): array { return [ ['foo', 2000, 4000, true], ['foo', 2000, 3000, false], @@ -127,4 +169,41 @@ class PasswordConfirmationMiddlewareTest extends TestCase { ['foo', 2000, 3816, true], ]; } + + public function testSSO(): void { + static $sessionId = 'mySession1d'; + + $this->reflector->reflect($this->controller, __FUNCTION__); + + $this->user->method('getBackendClassName') + ->willReturn('fictional_backend'); + $this->userSession->method('getUser') + ->willReturn($this->user); + + $this->session->method('get') + ->with('last-password-confirm') + ->willReturn(0); + $this->session->method('getId') + ->willReturn($sessionId); + + $this->timeFactory->method('getTime') + ->willReturn(9876); + + $token = $this->createMock(IToken::class); + $token->method('getScopeAsArray') + ->willReturn([IToken::SCOPE_SKIP_PASSWORD_VALIDATION => true]); + $this->tokenProvider->expects($this->once()) + ->method('getToken') + ->with($sessionId) + ->willReturn($token); + + $thrown = false; + try { + $this->middleware->beforeController($this->controller, __FUNCTION__); + } catch (NotConfirmedException) { + $thrown = true; + } + + $this->assertSame(false, $thrown); + } } diff --git a/tests/lib/AppFramework/Middleware/Security/RateLimitingMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/RateLimitingMiddlewareTest.php index 38d01950f6a..c42baadcb1c 100644 --- a/tests/lib/AppFramework/Middleware/Security/RateLimitingMiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/Security/RateLimitingMiddlewareTest.php @@ -1,86 +1,113 @@ <?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 Test\AppFramework\Middleware\Security; use OC\AppFramework\Middleware\Security\RateLimitingMiddleware; use OC\AppFramework\Utility\ControllerMethodReflector; +use OC\Security\Ip\BruteforceAllowList; use OC\Security\RateLimiting\Exception\RateLimitExceededException; use OC\Security\RateLimiting\Limiter; use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\AnonRateLimit; +use OCP\AppFramework\Http\Attribute\UserRateLimit; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\TemplateResponse; +use OCP\IAppConfig; use OCP\IRequest; +use OCP\ISession; use OCP\IUser; use OCP\IUserSession; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; +class TestRateLimitController extends Controller { + /** + * @UserRateThrottle(limit=20, period=200) + * @AnonRateThrottle(limit=10, period=100) + */ + public function testMethodWithAnnotation() { + } + + /** + * @AnonRateThrottle(limit=10, period=100) + */ + public function testMethodWithAnnotationFallback() { + } + + public function testMethodWithoutAnnotation() { + } + + #[UserRateLimit(limit: 20, period: 200)] + #[AnonRateLimit(limit: 10, period: 100)] + public function testMethodWithAttributes() { + } + + #[AnonRateLimit(limit: 10, period: 100)] + public function testMethodWithAttributesFallback() { + } +} + /** * @group DB */ class RateLimitingMiddlewareTest extends TestCase { - /** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */ - private $request; - /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */ - private $userSession; - /** @var ControllerMethodReflector|\PHPUnit\Framework\MockObject\MockObject */ - private $reflector; - /** @var Limiter|\PHPUnit\Framework\MockObject\MockObject */ - private $limiter; - /** @var RateLimitingMiddleware */ - private $rateLimitingMiddleware; + private IRequest|MockObject $request; + private IUserSession|MockObject $userSession; + private ControllerMethodReflector $reflector; + private Limiter|MockObject $limiter; + private ISession|MockObject $session; + private IAppConfig|MockObject $appConfig; + private BruteforceAllowList|MockObject $bruteForceAllowList; + private RateLimitingMiddleware $rateLimitingMiddleware; protected function setUp(): void { parent::setUp(); $this->request = $this->createMock(IRequest::class); $this->userSession = $this->createMock(IUserSession::class); - $this->reflector = $this->createMock(ControllerMethodReflector::class); + $this->reflector = new ControllerMethodReflector(); $this->limiter = $this->createMock(Limiter::class); + $this->session = $this->createMock(ISession::class); + $this->appConfig = $this->createMock(IAppConfig::class); + $this->bruteForceAllowList = $this->createMock(BruteforceAllowList::class); $this->rateLimitingMiddleware = new RateLimitingMiddleware( $this->request, $this->userSession, $this->reflector, - $this->limiter + $this->limiter, + $this->session, + $this->appConfig, + $this->bruteForceAllowList, ); } - public function testBeforeControllerWithoutAnnotation() { - $this->reflector - ->expects($this->exactly(4)) - ->method('getAnnotationParameter') - ->withConsecutive( - ['AnonRateThrottle', 'limit'], - ['AnonRateThrottle', 'period'], - ['UserRateThrottle', 'limit'], - ['UserRateThrottle', 'period'] - ) - ->willReturnMap([ - ['AnonRateThrottle', 'limit', ''], - ['AnonRateThrottle', 'period', ''], - ['UserRateThrottle', 'limit', ''], - ['UserRateThrottle', 'period', ''], - ]); + public function testBeforeControllerWithoutAnnotationForAnon(): void { + $this->limiter + ->expects($this->never()) + ->method('registerUserRequest'); + $this->limiter + ->expects($this->never()) + ->method('registerAnonRequest'); + + $this->userSession->expects($this->once()) + ->method('isLoggedIn') + ->willReturn(false); + + /** @var TestRateLimitController|MockObject $controller */ + $controller = $this->createMock(TestRateLimitController::class); + $this->reflector->reflect($controller, 'testMethodWithoutAnnotation'); + $this->rateLimitingMiddleware->beforeController($controller, 'testMethodWithoutAnnotation'); + } + public function testBeforeControllerWithoutAnnotationForLoggedIn(): void { $this->limiter ->expects($this->never()) ->method('registerUserRequest'); @@ -88,34 +115,79 @@ class RateLimitingMiddlewareTest extends TestCase { ->expects($this->never()) ->method('registerAnonRequest'); - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); - $this->rateLimitingMiddleware->beforeController($controller, 'testMethod'); + $this->userSession->expects($this->once()) + ->method('isLoggedIn') + ->willReturn(true); + + /** @var TestRateLimitController|MockObject $controller */ + $controller = $this->createMock(TestRateLimitController::class); + $this->reflector->reflect($controller, 'testMethodWithoutAnnotation'); + $this->rateLimitingMiddleware->beforeController($controller, 'testMethodWithoutAnnotation'); + } + + public function testBeforeControllerForAnon(): void { + $controller = new TestRateLimitController('test', $this->request); + + $this->request + ->method('getRemoteAddress') + ->willReturn('127.0.0.1'); + + $this->userSession + ->expects($this->once()) + ->method('isLoggedIn') + ->willReturn(false); + + $this->limiter + ->expects($this->never()) + ->method('registerUserRequest'); + $this->limiter + ->expects($this->once()) + ->method('registerAnonRequest') + ->with(get_class($controller) . '::testMethodWithAnnotation', '10', '100', '127.0.0.1'); + + $this->reflector->reflect($controller, 'testMethodWithAnnotation'); + $this->rateLimitingMiddleware->beforeController($controller, 'testMethodWithAnnotation'); + } + + public function testBeforeControllerForLoggedIn(): void { + $controller = new TestRateLimitController('test', $this->request); + /** @var IUser|MockObject $user */ + $user = $this->createMock(IUser::class); + + $this->userSession + ->expects($this->once()) + ->method('isLoggedIn') + ->willReturn(true); + $this->userSession + ->expects($this->once()) + ->method('getUser') + ->willReturn($user); + + $this->limiter + ->expects($this->never()) + ->method('registerAnonRequest'); + $this->limiter + ->expects($this->once()) + ->method('registerUserRequest') + ->with(get_class($controller) . '::testMethodWithAnnotation', '20', '200', $user); + + + $this->reflector->reflect($controller, 'testMethodWithAnnotation'); + $this->rateLimitingMiddleware->beforeController($controller, 'testMethodWithAnnotation'); } - public function testBeforeControllerForAnon() { - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); + public function testBeforeControllerAnonWithFallback(): void { + $controller = new TestRateLimitController('test', $this->request); $this->request ->expects($this->once()) ->method('getRemoteAddress') ->willReturn('127.0.0.1'); - $this->reflector - ->expects($this->exactly(4)) - ->method('getAnnotationParameter') - ->withConsecutive( - ['AnonRateThrottle', 'limit'], - ['AnonRateThrottle', 'period'], - ['UserRateThrottle', 'limit'], - ['UserRateThrottle', 'period'] - ) - ->willReturnMap([ - ['AnonRateThrottle', 'limit', '100'], - ['AnonRateThrottle', 'period', '10'], - ['UserRateThrottle', 'limit', ''], - ['UserRateThrottle', 'period', ''], - ]); + $this->userSession + ->expects($this->once()) + ->method('isLoggedIn') + ->willReturn(true); + $this->limiter ->expects($this->never()) @@ -123,16 +195,39 @@ class RateLimitingMiddlewareTest extends TestCase { $this->limiter ->expects($this->once()) ->method('registerAnonRequest') - ->with(get_class($controller) . '::testMethod', '100', '10', '127.0.0.1'); + ->with(get_class($controller) . '::testMethodWithAnnotationFallback', '10', '100', '127.0.0.1'); + + $this->reflector->reflect($controller, 'testMethodWithAnnotationFallback'); + $this->rateLimitingMiddleware->beforeController($controller, 'testMethodWithAnnotationFallback'); + } + + public function testBeforeControllerAttributesForAnon(): void { + $controller = new TestRateLimitController('test', $this->request); + + $this->request + ->method('getRemoteAddress') + ->willReturn('127.0.0.1'); + $this->userSession + ->expects($this->once()) + ->method('isLoggedIn') + ->willReturn(false); - $this->rateLimitingMiddleware->beforeController($controller, 'testMethod'); + $this->limiter + ->expects($this->never()) + ->method('registerUserRequest'); + $this->limiter + ->expects($this->once()) + ->method('registerAnonRequest') + ->with(get_class($controller) . '::testMethodWithAttributes', '10', '100', '127.0.0.1'); + + $this->reflector->reflect($controller, 'testMethodWithAttributes'); + $this->rateLimitingMiddleware->beforeController($controller, 'testMethodWithAttributes'); } - public function testBeforeControllerForLoggedIn() { - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); - /** @var IUser|\PHPUnit\Framework\MockObject\MockObject $user */ + public function testBeforeControllerAttributesForLoggedIn(): void { + $controller = new TestRateLimitController('test', $this->request); + /** @var IUser|MockObject $user */ $user = $this->createMock(IUser::class); $this->userSession @@ -144,37 +239,21 @@ class RateLimitingMiddlewareTest extends TestCase { ->method('getUser') ->willReturn($user); - $this->reflector - ->expects($this->exactly(4)) - ->method('getAnnotationParameter') - ->withConsecutive( - ['AnonRateThrottle', 'limit'], - ['AnonRateThrottle', 'period'], - ['UserRateThrottle', 'limit'], - ['UserRateThrottle', 'period'] - ) - ->willReturnMap([ - ['AnonRateThrottle', 'limit', ''], - ['AnonRateThrottle', 'period', ''], - ['UserRateThrottle', 'limit', '100'], - ['UserRateThrottle', 'period', '10'], - ]); - $this->limiter ->expects($this->never()) ->method('registerAnonRequest'); $this->limiter ->expects($this->once()) ->method('registerUserRequest') - ->with(get_class($controller) . '::testMethod', '100', '10', $user); + ->with(get_class($controller) . '::testMethodWithAttributes', '20', '200', $user); - $this->rateLimitingMiddleware->beforeController($controller, 'testMethod'); + $this->reflector->reflect($controller, 'testMethodWithAttributes'); + $this->rateLimitingMiddleware->beforeController($controller, 'testMethodWithAttributes'); } - public function testBeforeControllerAnonWithFallback() { - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); + public function testBeforeControllerAttributesAnonWithFallback(): void { + $controller = new TestRateLimitController('test', $this->request); $this->request ->expects($this->once()) ->method('getRemoteAddress') @@ -183,23 +262,8 @@ class RateLimitingMiddlewareTest extends TestCase { $this->userSession ->expects($this->once()) ->method('isLoggedIn') - ->willReturn(false); + ->willReturn(true); - $this->reflector - ->expects($this->exactly(4)) - ->method('getAnnotationParameter') - ->withConsecutive( - ['AnonRateThrottle', 'limit'], - ['AnonRateThrottle', 'period'], - ['UserRateThrottle', 'limit'], - ['UserRateThrottle', 'period'] - ) - ->willReturnMap([ - ['AnonRateThrottle', 'limit', '200'], - ['AnonRateThrottle', 'period', '20'], - ['UserRateThrottle', 'limit', '100'], - ['UserRateThrottle', 'period', '10'], - ]); $this->limiter ->expects($this->never()) @@ -207,25 +271,23 @@ class RateLimitingMiddlewareTest extends TestCase { $this->limiter ->expects($this->once()) ->method('registerAnonRequest') - ->with(get_class($controller) . '::testMethod', '200', '20', '127.0.0.1'); + ->with(get_class($controller) . '::testMethodWithAttributesFallback', '10', '100', '127.0.0.1'); - $this->rateLimitingMiddleware->beforeController($controller, 'testMethod'); + $this->reflector->reflect($controller, 'testMethodWithAttributesFallback'); + $this->rateLimitingMiddleware->beforeController($controller, 'testMethodWithAttributesFallback'); } - - public function testAfterExceptionWithOtherException() { + public function testAfterExceptionWithOtherException(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('My test exception'); - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); + $controller = new TestRateLimitController('test', $this->request); $this->rateLimitingMiddleware->afterException($controller, 'testMethod', new \Exception('My test exception')); } - public function testAfterExceptionWithJsonBody() { - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); + public function testAfterExceptionWithJsonBody(): void { + $controller = new TestRateLimitController('test', $this->request); $this->request ->expects($this->once()) ->method('getHeader') @@ -238,9 +300,8 @@ class RateLimitingMiddlewareTest extends TestCase { $this->assertEquals($expected, $result); } - public function testAfterExceptionWithHtmlBody() { - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject $controller */ - $controller = $this->createMock(Controller::class); + public function testAfterExceptionWithHtmlBody(): void { + $controller = new TestRateLimitController('test', $this->request); $this->request ->expects($this->once()) ->method('getHeader') diff --git a/tests/lib/AppFramework/Middleware/Security/SameSiteCookieMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/SameSiteCookieMiddlewareTest.php index 787f5c92fd7..7800371f68f 100644 --- a/tests/lib/AppFramework/Middleware/Security/SameSiteCookieMiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/Security/SameSiteCookieMiddlewareTest.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 Test\AppFramework\Middleware\Security; @@ -50,7 +34,7 @@ class SameSiteCookieMiddlewareTest extends TestCase { $this->middleware = new SameSiteCookieMiddleware($this->request, $this->reflector); } - public function testBeforeControllerNoIndex() { + public function testBeforeControllerNoIndex(): void { $this->request->method('getScriptName') ->willReturn('/ocs/v2.php'); @@ -58,7 +42,7 @@ class SameSiteCookieMiddlewareTest extends TestCase { $this->addToAssertionCount(1); } - public function testBeforeControllerIndexHasAnnotation() { + public function testBeforeControllerIndexHasAnnotation(): void { $this->request->method('getScriptName') ->willReturn('/index.php'); @@ -70,7 +54,7 @@ class SameSiteCookieMiddlewareTest extends TestCase { $this->addToAssertionCount(1); } - public function testBeforeControllerIndexNoAnnotationPassingCheck() { + public function testBeforeControllerIndexNoAnnotationPassingCheck(): void { $this->request->method('getScriptName') ->willReturn('/index.php'); @@ -85,7 +69,7 @@ class SameSiteCookieMiddlewareTest extends TestCase { $this->addToAssertionCount(1); } - public function testBeforeControllerIndexNoAnnotationFailingCheck() { + public function testBeforeControllerIndexNoAnnotationFailingCheck(): void { $this->expectException(LaxSameSiteCookieFailedException::class); $this->request->method('getScriptName') @@ -101,7 +85,7 @@ class SameSiteCookieMiddlewareTest extends TestCase { $this->middleware->beforeController($this->createMock(Controller::class), 'foo'); } - public function testAfterExceptionNoLaxCookie() { + public function testAfterExceptionNoLaxCookie(): void { $ex = new SecurityException(); try { @@ -112,7 +96,7 @@ class SameSiteCookieMiddlewareTest extends TestCase { } } - public function testAfterExceptionLaxCookie() { + public function testAfterExceptionLaxCookie(): void { $ex = new LaxSameSiteCookieFailedException(); $this->request->method('getRequestUri') @@ -120,7 +104,7 @@ class SameSiteCookieMiddlewareTest extends TestCase { $middleware = $this->getMockBuilder(SameSiteCookieMiddleware::class) ->setConstructorArgs([$this->request, $this->reflector]) - ->setMethods(['setSameSiteCookie']) + ->onlyMethods(['setSameSiteCookie']) ->getMock(); $middleware->expects($this->once()) diff --git a/tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php index c68ada87657..0c6fc21357d 100644 --- a/tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php @@ -1,23 +1,9 @@ <?php + /** - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @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: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace Test\AppFramework\Middleware\Security; @@ -26,6 +12,7 @@ use OC\AppFramework\Http; use OC\AppFramework\Http\Request; use OC\AppFramework\Middleware\Security\Exceptions\AppNotEnabledException; use OC\AppFramework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException; +use OC\AppFramework\Middleware\Security\Exceptions\ExAppRequiredException; use OC\AppFramework\Middleware\Security\Exceptions\NotAdminException; use OC\AppFramework\Middleware\Security\Exceptions\NotLoggedInException; use OC\AppFramework\Middleware\Security\Exceptions\SecurityException; @@ -33,24 +20,32 @@ use OC\Appframework\Middleware\Security\Exceptions\StrictCookieMissingException; use OC\AppFramework\Middleware\Security\SecurityMiddleware; use OC\AppFramework\Utility\ControllerMethodReflector; use OC\Settings\AuthorizedGroupMapper; +use OC\User\Session; use OCP\App\IAppManager; -use OCP\AppFramework\Controller; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\TemplateResponse; +use OCP\Group\ISubAdmin; use OCP\IConfig; +use OCP\IGroupManager; use OCP\IL10N; use OCP\INavigationManager; use OCP\IRequest; use OCP\IRequestId; +use OCP\ISession; use OCP\IURLGenerator; +use OCP\IUser; use OCP\IUserSession; +use OCP\Security\Ip\IRemoteAddress; use Psr\Log\LoggerInterface; +use Test\AppFramework\Middleware\Security\Mock\NormalController; +use Test\AppFramework\Middleware\Security\Mock\OCSController; +use Test\AppFramework\Middleware\Security\Mock\SecurityMiddlewareController; class SecurityMiddlewareTest extends \Test\TestCase { /** @var SecurityMiddleware|\PHPUnit\Framework\MockObject\MockObject */ private $middleware; - /** @var Controller|\PHPUnit\Framework\MockObject\MockObject */ + /** @var SecurityMiddlewareController */ private $controller; /** @var SecurityException */ private $secException; @@ -79,13 +74,19 @@ class SecurityMiddlewareTest extends \Test\TestCase { parent::setUp(); $this->authorizedGroupMapper = $this->createMock(AuthorizedGroupMapper::class); - $this->userSession = $this->createMock(IUserSession::class); - $this->controller = $this->createMock(Controller::class); + $this->userSession = $this->createMock(Session::class); + $user = $this->createMock(IUser::class); + $user->method('getUID')->willReturn('test'); + $this->userSession->method('getUser')->willReturn($user); + $this->request = $this->createMock(IRequest::class); + $this->controller = new SecurityMiddlewareController( + 'test', + $this->request + ); $this->reader = new ControllerMethodReflector(); $this->logger = $this->createMock(LoggerInterface::class); $this->navigationManager = $this->createMock(INavigationManager::class); $this->urlGenerator = $this->createMock(IURLGenerator::class); - $this->request = $this->createMock(IRequest::class); $this->l10n = $this->createMock(IL10N::class); $this->middleware = $this->getMiddleware(true, true, false); $this->secException = new SecurityException('hey', false); @@ -97,6 +98,15 @@ class SecurityMiddlewareTest extends \Test\TestCase { $this->appManager->expects($this->any()) ->method('isEnabledForUser') ->willReturn($isAppEnabledForUser); + $remoteIpAddress = $this->createMock(IRemoteAddress::class); + $remoteIpAddress->method('allowsAdminActions')->willReturn(true); + + $groupManager = $this->createMock(IGroupManager::class); + $groupManager->method('isAdmin') + ->willReturn($isAdminUser); + $subAdminManager = $this->createMock(ISubAdmin::class); + $subAdminManager->method('isSubAdmin') + ->willReturn($isSubAdmin); return new SecurityMiddleware( $this->request, @@ -106,27 +116,93 @@ class SecurityMiddlewareTest extends \Test\TestCase { $this->logger, 'files', $isLoggedIn, - $isAdminUser, - $isSubAdmin, + $groupManager, + $subAdminManager, $this->appManager, $this->l10n, $this->authorizedGroupMapper, - $this->userSession + $this->userSession, + $remoteIpAddress ); } + public static function dataNoCSRFRequiredPublicPage(): array { + return [ + ['testAnnotationNoCSRFRequiredPublicPage'], + ['testAnnotationNoCSRFRequiredAttributePublicPage'], + ['testAnnotationPublicPageAttributeNoCSRFRequired'], + ['testAttributeNoCSRFRequiredPublicPage'], + ]; + } - /** - * @PublicPage - * @NoCSRFRequired - */ - public function testSetNavigationEntry() { + public static function dataPublicPage(): array { + return [ + ['testAnnotationPublicPage'], + ['testAttributePublicPage'], + ]; + } + + public static function dataNoCSRFRequired(): array { + return [ + ['testAnnotationNoCSRFRequired'], + ['testAttributeNoCSRFRequired'], + ]; + } + + public static function dataPublicPageStrictCookieRequired(): array { + return [ + ['testAnnotationPublicPageStrictCookieRequired'], + ['testAnnotationStrictCookieRequiredAttributePublicPage'], + ['testAnnotationPublicPageAttributeStrictCookiesRequired'], + ['testAttributePublicPageStrictCookiesRequired'], + ]; + } + + public static function dataNoCSRFRequiredPublicPageStrictCookieRequired(): array { + return [ + ['testAnnotationNoCSRFRequiredPublicPageStrictCookieRequired'], + ['testAttributeNoCSRFRequiredPublicPageStrictCookiesRequired'], + ]; + } + + public static function dataNoAdminRequiredNoCSRFRequired(): array { + return [ + ['testAnnotationNoAdminRequiredNoCSRFRequired'], + ['testAttributeNoAdminRequiredNoCSRFRequired'], + ]; + } + + public static function dataNoAdminRequiredNoCSRFRequiredPublicPage(): array { + return [ + ['testAnnotationNoAdminRequiredNoCSRFRequiredPublicPage'], + ['testAttributeNoAdminRequiredNoCSRFRequiredPublicPage'], + ]; + } + + public static function dataNoCSRFRequiredSubAdminRequired(): array { + return [ + ['testAnnotationNoCSRFRequiredSubAdminRequired'], + ['testAnnotationNoCSRFRequiredAttributeSubAdminRequired'], + ['testAnnotationSubAdminRequiredAttributeNoCSRFRequired'], + ['testAttributeNoCSRFRequiredSubAdminRequired'], + ]; + } + + public static function dataExAppRequired(): array { + return [ + ['testAnnotationExAppRequired'], + ['testAttributeExAppRequired'], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredPublicPage')] + public function testSetNavigationEntry(string $method): void { $this->navigationManager->expects($this->once()) ->method('setActiveEntry') ->with($this->equalTo('files')); - $this->reader->reflect(__CLASS__, __FUNCTION__); - $this->middleware->beforeController($this->controller, __FUNCTION__); + $this->reader->reflect($this->controller, $method); + $this->middleware->beforeController($this->controller, $method); } @@ -146,7 +222,7 @@ class SecurityMiddlewareTest extends \Test\TestCase { $sec = $this->getMiddleware($isLoggedIn, $isAdminUser, false); try { - $this->reader->reflect(__CLASS__, $method); + $this->reader->reflect($this->controller, $method); $sec->beforeController($this->controller, $method); } catch (SecurityException $ex) { $this->assertEquals($status, $ex->getCode()); @@ -159,75 +235,63 @@ class SecurityMiddlewareTest extends \Test\TestCase { } } - public function testAjaxStatusLoggedInCheck() { + public function testAjaxStatusLoggedInCheck(): void { $this->ajaxExceptionStatus( - __FUNCTION__, + 'testNoAnnotationNorAttribute', 'isLoggedIn', Http::STATUS_UNAUTHORIZED ); } - /** - * @NoCSRFRequired - */ - public function testAjaxNotAdminCheck() { + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequired')] + public function testAjaxNotAdminCheck(string $method): void { $this->ajaxExceptionStatus( - __FUNCTION__, + $method, 'isAdminUser', Http::STATUS_FORBIDDEN ); } - /** - * @PublicPage - */ - public function testAjaxStatusCSRFCheck() { + #[\PHPUnit\Framework\Attributes\DataProvider('dataPublicPage')] + public function testAjaxStatusCSRFCheck(string $method): void { $this->ajaxExceptionStatus( - __FUNCTION__, + $method, 'passesCSRFCheck', Http::STATUS_PRECONDITION_FAILED ); } - /** - * @PublicPage - * @NoCSRFRequired - */ - public function testAjaxStatusAllGood() { + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredPublicPage')] + public function testAjaxStatusAllGood(string $method): void { $this->ajaxExceptionStatus( - __FUNCTION__, + $method, 'isLoggedIn', 0 ); $this->ajaxExceptionStatus( - __FUNCTION__, + $method, 'isAdminUser', 0 ); $this->ajaxExceptionStatus( - __FUNCTION__, + $method, 'passesCSRFCheck', 0 ); } - - /** - * @PublicPage - * @NoCSRFRequired - */ - public function testNoChecks() { + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredPublicPage')] + public function testNoChecks(string $method): void { $this->request->expects($this->never()) ->method('passesCSRFCheck') ->willReturn(false); $sec = $this->getMiddleware(false, false, false); - $this->reader->reflect(__CLASS__, __FUNCTION__); - $sec->beforeController($this->controller, __FUNCTION__); + $this->reader->reflect($this->controller, $method); + $sec->beforeController($this->controller, $method); } - /** * @param string $method * @param string $expects @@ -250,16 +314,14 @@ class SecurityMiddlewareTest extends \Test\TestCase { $this->addToAssertionCount(1); } - $this->reader->reflect(__CLASS__, $method); + $this->reader->reflect($this->controller, $method); $sec->beforeController($this->controller, $method); } - /** - * @PublicPage - */ - public function testCsrfCheck() { - $this->expectException(\OC\AppFramework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException::class); + #[\PHPUnit\Framework\Attributes\DataProvider('dataPublicPage')] + public function testCsrfCheck(string $method): void { + $this->expectException(CrossSiteRequestForgeryException::class); $this->request->expects($this->once()) ->method('passesCSRFCheck') @@ -267,28 +329,22 @@ class SecurityMiddlewareTest extends \Test\TestCase { $this->request->expects($this->once()) ->method('passesStrictCookieCheck') ->willReturn(true); - $this->reader->reflect(__CLASS__, __FUNCTION__); - $this->middleware->beforeController($this->controller, __FUNCTION__); + $this->reader->reflect($this->controller, $method); + $this->middleware->beforeController($this->controller, $method); } - - /** - * @PublicPage - * @NoCSRFRequired - */ - public function testNoCsrfCheck() { + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredPublicPage')] + public function testNoCsrfCheck(string $method): void { $this->request->expects($this->never()) ->method('passesCSRFCheck') ->willReturn(false); - $this->reader->reflect(__CLASS__, __FUNCTION__); - $this->middleware->beforeController($this->controller, __FUNCTION__); + $this->reader->reflect($this->controller, $method); + $this->middleware->beforeController($this->controller, $method); } - /** - * @PublicPage - */ - public function testPassesCsrfCheck() { + #[\PHPUnit\Framework\Attributes\DataProvider('dataPublicPage')] + public function testPassesCsrfCheck(string $method): void { $this->request->expects($this->once()) ->method('passesCSRFCheck') ->willReturn(true); @@ -296,15 +352,13 @@ class SecurityMiddlewareTest extends \Test\TestCase { ->method('passesStrictCookieCheck') ->willReturn(true); - $this->reader->reflect(__CLASS__, __FUNCTION__); - $this->middleware->beforeController($this->controller, __FUNCTION__); + $this->reader->reflect($this->controller, $method); + $this->middleware->beforeController($this->controller, $method); } - /** - * @PublicPage - */ - public function testFailCsrfCheck() { - $this->expectException(\OC\AppFramework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException::class); + #[\PHPUnit\Framework\Attributes\DataProvider('dataPublicPage')] + public function testFailCsrfCheck(string $method): void { + $this->expectException(CrossSiteRequestForgeryException::class); $this->request->expects($this->once()) ->method('passesCSRFCheck') @@ -313,16 +367,13 @@ class SecurityMiddlewareTest extends \Test\TestCase { ->method('passesStrictCookieCheck') ->willReturn(true); - $this->reader->reflect(__CLASS__, __FUNCTION__); - $this->middleware->beforeController($this->controller, __FUNCTION__); + $this->reader->reflect($this->controller, $method); + $this->middleware->beforeController($this->controller, $method); } - /** - * @PublicPage - * @StrictCookieRequired - */ - public function testStrictCookieRequiredCheck() { - $this->expectException(\OC\Appframework\Middleware\Security\Exceptions\StrictCookieMissingException::class); + #[\PHPUnit\Framework\Attributes\DataProvider('dataPublicPageStrictCookieRequired')] + public function testStrictCookieRequiredCheck(string $method): void { + $this->expectException(\OC\AppFramework\Middleware\Security\Exceptions\StrictCookieMissingException::class); $this->request->expects($this->never()) ->method('passesCSRFCheck'); @@ -330,68 +381,53 @@ class SecurityMiddlewareTest extends \Test\TestCase { ->method('passesStrictCookieCheck') ->willReturn(false); - $this->reader->reflect(__CLASS__, __FUNCTION__); - $this->middleware->beforeController($this->controller, __FUNCTION__); + $this->reader->reflect($this->controller, $method); + $this->middleware->beforeController($this->controller, $method); } - - /** - * @PublicPage - * @NoCSRFRequired - */ - public function testNoStrictCookieRequiredCheck() { + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredPublicPage')] + public function testNoStrictCookieRequiredCheck(string $method): void { $this->request->expects($this->never()) ->method('passesStrictCookieCheck') ->willReturn(false); - $this->reader->reflect(__CLASS__, __FUNCTION__); - $this->middleware->beforeController($this->controller, __FUNCTION__); + $this->reader->reflect($this->controller, $method); + $this->middleware->beforeController($this->controller, $method); } - /** - * @PublicPage - * @NoCSRFRequired - * @StrictCookieRequired - */ - public function testPassesStrictCookieRequiredCheck() { + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredPublicPageStrictCookieRequired')] + public function testPassesStrictCookieRequiredCheck(string $method): void { $this->request ->expects($this->once()) ->method('passesStrictCookieCheck') ->willReturn(true); - $this->reader->reflect(__CLASS__, __FUNCTION__); - $this->middleware->beforeController($this->controller, __FUNCTION__); + $this->reader->reflect($this->controller, $method); + $this->middleware->beforeController($this->controller, $method); } - public function dataCsrfOcsController() { - $controller = $this->getMockBuilder('OCP\AppFramework\Controller') - ->disableOriginalConstructor() - ->getMock(); - $ocsController = $this->getMockBuilder('OCP\AppFramework\OCSController') - ->disableOriginalConstructor() - ->getMock(); - + public static function dataCsrfOcsController(): array { return [ - [$controller, false, false, true], - [$controller, false, true, true], - [$controller, true, false, true], - [$controller, true, true, true], - - [$ocsController, false, false, true], - [$ocsController, false, true, false], - [$ocsController, true, false, false], - [$ocsController, true, true, false], + [NormalController::class, false, false, true], + [NormalController::class, false, true, true], + [NormalController::class, true, false, true], + [NormalController::class, true, true, true], + + [OCSController::class, false, false, true], + [OCSController::class, false, true, false], + [OCSController::class, true, false, false], + [OCSController::class, true, true, false], ]; } /** - * @dataProvider dataCsrfOcsController - * @param Controller $controller + * @param string $controllerClass * @param bool $hasOcsApiHeader * @param bool $hasBearerAuth * @param bool $exception */ - public function testCsrfOcsController(Controller $controller, bool $hasOcsApiHeader, bool $hasBearerAuth, bool $exception) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataCsrfOcsController')] + public function testCsrfOcsController(string $controllerClass, bool $hasOcsApiHeader, bool $hasBearerAuth, bool $exception): void { $this->request ->method('getHeader') ->willReturnCallback(function ($header) use ($hasOcsApiHeader, $hasBearerAuth) { @@ -407,6 +443,8 @@ class SecurityMiddlewareTest extends \Test\TestCase { ->method('passesStrictCookieCheck') ->willReturn(true); + $controller = new $controllerClass('test', $this->request); + try { $this->middleware->beforeController($controller, 'foo'); $this->assertFalse($exception); @@ -415,86 +453,112 @@ class SecurityMiddlewareTest extends \Test\TestCase { } } - /** - * @NoCSRFRequired - * @NoAdminRequired - */ - public function testLoggedInCheck() { - $this->securityCheck(__FUNCTION__, 'isLoggedIn'); + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoAdminRequiredNoCSRFRequired')] + public function testLoggedInCheck(string $method): void { + $this->securityCheck($method, 'isLoggedIn'); } - - /** - * @NoCSRFRequired - * @NoAdminRequired - */ - public function testFailLoggedInCheck() { - $this->securityCheck(__FUNCTION__, 'isLoggedIn', true); + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoAdminRequiredNoCSRFRequired')] + public function testFailLoggedInCheck(string $method): void { + $this->securityCheck($method, 'isLoggedIn', true); } - - /** - * @NoCSRFRequired - */ - public function testIsAdminCheck() { - $this->securityCheck(__FUNCTION__, 'isAdminUser'); + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequired')] + public function testIsAdminCheck(string $method): void { + $this->securityCheck($method, 'isAdminUser'); } - /** - * @NoCSRFRequired - * @SubAdminRequired - */ - public function testIsNotSubAdminCheck() { - $this->reader->reflect(__CLASS__, __FUNCTION__); + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredSubAdminRequired')] + public function testIsNotSubAdminCheck(string $method): void { + $this->reader->reflect($this->controller, $method); $sec = $this->getMiddleware(true, false, false); $this->expectException(SecurityException::class); - $sec->beforeController($this, __METHOD__); + $sec->beforeController($this->controller, $method); } - /** - * @NoCSRFRequired - * @SubAdminRequired - */ - public function testIsSubAdminCheck() { - $this->reader->reflect(__CLASS__, __FUNCTION__); + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredSubAdminRequired')] + public function testIsSubAdminCheck(string $method): void { + $this->reader->reflect($this->controller, $method); $sec = $this->getMiddleware(true, false, true); - $sec->beforeController($this, __METHOD__); + $sec->beforeController($this->controller, $method); $this->addToAssertionCount(1); } - /** - * @NoCSRFRequired - * @SubAdminRequired - */ - public function testIsSubAdminAndAdminCheck() { - $this->reader->reflect(__CLASS__, __FUNCTION__); + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequiredSubAdminRequired')] + public function testIsSubAdminAndAdminCheck(string $method): void { + $this->reader->reflect($this->controller, $method); $sec = $this->getMiddleware(true, true, true); - $sec->beforeController($this, __METHOD__); + $sec->beforeController($this->controller, $method); $this->addToAssertionCount(1); } - /** - * @NoCSRFRequired - */ - public function testFailIsAdminCheck() { - $this->securityCheck(__FUNCTION__, 'isAdminUser', true); + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoCSRFRequired')] + public function testFailIsAdminCheck(string $method): void { + $this->securityCheck($method, 'isAdminUser', true); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoAdminRequiredNoCSRFRequiredPublicPage')] + public function testRestrictedAppLoggedInPublicPage(string $method): void { + $middleware = $this->getMiddleware(true, false, false); + $this->reader->reflect($this->controller, $method); + + $this->appManager->method('getAppPath') + ->with('files') + ->willReturn('foo'); + + $this->appManager->method('isEnabledForUser') + ->with('files') + ->willReturn(false); + + $middleware->beforeController($this->controller, $method); + $this->addToAssertionCount(1); } + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoAdminRequiredNoCSRFRequiredPublicPage')] + public function testRestrictedAppNotLoggedInPublicPage(string $method): void { + $middleware = $this->getMiddleware(false, false, false); + $this->reader->reflect($this->controller, $method); + + $this->appManager->method('getAppPath') + ->with('files') + ->willReturn('foo'); + + $this->appManager->method('isEnabledForUser') + ->with('files') + ->willReturn(false); + + $middleware->beforeController($this->controller, $method); + $this->addToAssertionCount(1); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataNoAdminRequiredNoCSRFRequired')] + public function testRestrictedAppLoggedIn(string $method): void { + $middleware = $this->getMiddleware(true, false, false, false); + $this->reader->reflect($this->controller, $method); + + $this->appManager->method('getAppPath') + ->with('files') + ->willReturn('foo'); + + $this->expectException(AppNotEnabledException::class); + $middleware->beforeController($this->controller, $method); + } - public function testAfterExceptionNotCaughtThrowsItAgain() { + + public function testAfterExceptionNotCaughtThrowsItAgain(): void { $ex = new \Exception(); $this->expectException(\Exception::class); $this->middleware->afterException($this->controller, 'test', $ex); } - public function testAfterExceptionReturnsRedirectForNotLoggedInUser() { + public function testAfterExceptionReturnsRedirectForNotLoggedInUser(): void { $this->request = new Request( [ - 'server' => - [ + 'server' + => [ 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'REQUEST_URI' => 'nextcloud/index.php/apps/specialapp' ] @@ -525,7 +589,7 @@ class SecurityMiddlewareTest extends \Test\TestCase { $this->assertEquals($expected, $response); } - public function testAfterExceptionRedirectsToWebRootAfterStrictCookieFail() { + public function testAfterExceptionRedirectsToWebRootAfterStrictCookieFail(): void { $this->request = new Request( [ 'server' => [ @@ -552,7 +616,7 @@ class SecurityMiddlewareTest extends \Test\TestCase { /** * @return array */ - public function exceptionProvider() { + public static function exceptionProvider(): array { return [ [ new AppNotEnabledException(), @@ -567,14 +631,14 @@ class SecurityMiddlewareTest extends \Test\TestCase { } /** - * @dataProvider exceptionProvider * @param SecurityException $exception */ - public function testAfterExceptionReturnsTemplateResponse(SecurityException $exception) { + #[\PHPUnit\Framework\Attributes\DataProvider('exceptionProvider')] + public function testAfterExceptionReturnsTemplateResponse(SecurityException $exception): void { $this->request = new Request( [ - 'server' => - [ + 'server' + => [ 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'REQUEST_URI' => 'nextcloud/index.php/apps/specialapp' ] @@ -596,81 +660,42 @@ class SecurityMiddlewareTest extends \Test\TestCase { $this->assertEquals($expected, $response); } - public function testAfterAjaxExceptionReturnsJSONError() { + public function testAfterAjaxExceptionReturnsJSONError(): void { $response = $this->middleware->afterException($this->controller, 'test', $this->secAjaxException); $this->assertTrue($response instanceof JSONResponse); } - public function dataRestrictedApp() { - return [ - [false, false, false,], - [false, false, true,], - [false, true, false,], - [false, true, true,], - [ true, false, false,], - [ true, false, true,], - [ true, true, false,], - [ true, true, true,], - ]; - } - - /** - * @PublicPage - * @NoAdminRequired - * @NoCSRFRequired - */ - public function testRestrictedAppLoggedInPublicPage() { + #[\PHPUnit\Framework\Attributes\DataProvider('dataExAppRequired')] + public function testExAppRequired(string $method): void { $middleware = $this->getMiddleware(true, false, false); - $this->reader->reflect(__CLASS__, __FUNCTION__); - - $this->appManager->method('getAppPath') - ->with('files') - ->willReturn('foo'); + $this->reader->reflect($this->controller, $method); - $this->appManager->method('isEnabledForUser') - ->with('files') - ->willReturn(false); - - $middleware->beforeController($this->controller, __FUNCTION__); - $this->addToAssertionCount(1); - } - - /** - * @PublicPage - * @NoAdminRequired - * @NoCSRFRequired - */ - public function testRestrictedAppNotLoggedInPublicPage() { - $middleware = $this->getMiddleware(false, false, false); - $this->reader->reflect(__CLASS__, __FUNCTION__); + $session = $this->createMock(ISession::class); + $session->method('get')->with('app_api')->willReturn(true); + $this->userSession->method('getSession')->willReturn($session); - $this->appManager->method('getAppPath') - ->with('files') - ->willReturn('foo'); - - $this->appManager->method('isEnabledForUser') - ->with('files') - ->willReturn(false); + $this->request->expects($this->once()) + ->method('passesStrictCookieCheck') + ->willReturn(true); + $this->request->expects($this->once()) + ->method('passesCSRFCheck') + ->willReturn(true); - $middleware->beforeController($this->controller, __FUNCTION__); - $this->addToAssertionCount(1); + $middleware->beforeController($this->controller, $method); } - /** - * @NoAdminRequired - * @NoCSRFRequired - */ - public function testRestrictedAppLoggedIn() { + #[\PHPUnit\Framework\Attributes\DataProvider('dataExAppRequired')] + public function testExAppRequiredError(string $method): void { $middleware = $this->getMiddleware(true, false, false, false); - $this->reader->reflect(__CLASS__, __FUNCTION__); + $this->reader->reflect($this->controller, $method); - $this->appManager->method('getAppPath') - ->with('files') - ->willReturn('foo'); + $session = $this->createMock(ISession::class); + $session->method('get')->with('app_api')->willReturn(false); + $this->userSession->method('getSession')->willReturn($session); - $this->expectException(AppNotEnabledException::class); - $middleware->beforeController($this->controller, __FUNCTION__); + $this->expectException(ExAppRequiredException::class); + $middleware->beforeController($this->controller, $method); } } diff --git a/tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php b/tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php index 09838423e85..8ecc73791c9 100644 --- a/tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php +++ b/tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php @@ -1,17 +1,11 @@ <?php declare(strict_types=1); - /** - * ownCloud - App Framework - * - * This file is licensed under the Affero General Public License version 3 or - * later. See the COPYING file. - * - * @author Thomas Müller <deepdiver@owncloud.com> - * @copyright Thomas Müller 2014 + * SPDX-FileCopyrightText: 2016-2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-or-later */ - namespace Test\AppFramework\Middleware; use OC\AppFramework\Middleware\SessionMiddleware; diff --git a/tests/lib/AppFramework/OCS/BaseResponseTest.php b/tests/lib/AppFramework/OCS/BaseResponseTest.php index 9038aee6baf..e04f7856623 100644 --- a/tests/lib/AppFramework/OCS/BaseResponseTest.php +++ b/tests/lib/AppFramework/OCS/BaseResponseTest.php @@ -3,31 +3,25 @@ declare(strict_types=1); /** - * @copyright 2020 Daniel Kesselberg <mail@danielkesselberg.de> - * - * @author 2020 Daniel Kesselberg <mail@danielkesselberg.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: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace Test\AppFramework\Middleware; +namespace Test\AppFramework\OCS; use OC\AppFramework\OCS\BaseResponse; +class ArrayValue implements \JsonSerializable { + public function __construct( + private array $array, + ) { + } + + public function jsonSerialize(): mixed { + return $this->array; + } +} + class BaseResponseTest extends \Test\TestCase { public function testToXml(): void { /** @var BaseResponse $response */ @@ -45,13 +39,42 @@ class BaseResponseTest extends \Test\TestCase { 'someElement' => 'withAttribute', ], 'value without key', + 'object' => new \stdClass(), + ]; + + $this->invokePrivate($response, 'toXml', [$data, $writer]); + $writer->endDocument(); + + $this->assertEquals( + "<?xml version=\"1.0\"?>\n<hello>hello</hello><information test=\"some data\"><someElement>withAttribute</someElement></information><element>value without key</element><object/>\n", + $writer->outputMemory(true) + ); + } + + public function testToXmlJsonSerializable(): void { + /** @var BaseResponse $response */ + $response = $this->createMock(BaseResponse::class); + + $writer = new \XMLWriter(); + $writer->openMemory(); + $writer->setIndent(false); + $writer->startDocument(); + + $data = [ + 'hello' => 'hello', + 'information' => new ArrayValue([ + '@test' => 'some data', + 'someElement' => 'withAttribute', + ]), + 'value without key', + 'object' => new \stdClass(), ]; $this->invokePrivate($response, 'toXml', [$data, $writer]); $writer->endDocument(); $this->assertEquals( - "<?xml version=\"1.0\"?>\n<hello>hello</hello><information test=\"some data\"><someElement>withAttribute</someElement></information><element>value without key</element>\n", + "<?xml version=\"1.0\"?>\n<hello>hello</hello><information test=\"some data\"><someElement>withAttribute</someElement></information><element>value without key</element><object/>\n", $writer->outputMemory(true) ); } diff --git a/tests/lib/AppFramework/OCS/V2ResponseTest.php b/tests/lib/AppFramework/OCS/V2ResponseTest.php new file mode 100644 index 00000000000..7a70ad6d633 --- /dev/null +++ b/tests/lib/AppFramework/OCS/V2ResponseTest.php @@ -0,0 +1,36 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\AppFramework\OCS; + +use OC\AppFramework\OCS\V2Response; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\OCSController; + +class V2ResponseTest extends \Test\TestCase { + #[\PHPUnit\Framework\Attributes\DataProvider('providesStatusCodes')] + public function testStatusCodeMapper(int $expected, int $sc): void { + $response = new V2Response(new DataResponse([], $sc)); + $this->assertEquals($expected, $response->getStatus()); + } + + public static function providesStatusCodes(): array { + return [ + [Http::STATUS_OK, 200], + [Http::STATUS_BAD_REQUEST, 104], + [Http::STATUS_BAD_REQUEST, 1000], + [201, 201], + [Http::STATUS_UNAUTHORIZED, OCSController::RESPOND_UNAUTHORISED], + [Http::STATUS_INTERNAL_SERVER_ERROR, OCSController::RESPOND_SERVER_ERROR], + [Http::STATUS_NOT_FOUND, OCSController::RESPOND_NOT_FOUND], + [Http::STATUS_INTERNAL_SERVER_ERROR, OCSController::RESPOND_UNKNOWN_ERROR], + ]; + } +} diff --git a/tests/lib/AppFramework/Routing/RouteParserTest.php b/tests/lib/AppFramework/Routing/RouteParserTest.php new file mode 100644 index 00000000000..406c5f1f3a5 --- /dev/null +++ b/tests/lib/AppFramework/Routing/RouteParserTest.php @@ -0,0 +1,347 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace Test\AppFramework\Routing; + +use OC\AppFramework\Routing\RouteParser; +use Symfony\Component\Routing\Route as RoutingRoute; +use Symfony\Component\Routing\RouteCollection; + +class RouteParserTest extends \Test\TestCase { + + protected RouteParser $parser; + + protected function setUp(): void { + $this->parser = new RouteParser(); + } + + public function testParseRoutes(): void { + $routes = ['routes' => [ + ['name' => 'folders#open', 'url' => '/{folderId}/open', 'verb' => 'GET'], + ['name' => 'folders#create', 'url' => '/{folderId}/create', 'verb' => 'POST'] + ]]; + + $collection = $this->parser->parseDefaultRoutes($routes, 'app1'); + $this->assertArrayHasKey('app1.folders.open', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/open', 'GET', 'FoldersController', 'open', route: $collection->get('app1.folders.open')); + $this->assertArrayHasKey('app1.folders.create', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/create', 'POST', 'FoldersController', 'create', route: $collection->get('app1.folders.create')); + } + + public function testParseRoutesRootApps(): void { + $routes = ['routes' => [ + ['name' => 'folders#open', 'url' => '/{folderId}/open', 'verb' => 'GET'], + ['name' => 'folders#create', 'url' => '/{folderId}/create', 'verb' => 'POST'] + ]]; + + $collection = $this->parser->parseDefaultRoutes($routes, 'core'); + $this->assertArrayHasKey('core.folders.open', $collection->all()); + $this->assertSimpleRoute('/{folderId}/open', 'GET', 'FoldersController', 'open', app: 'core', route: $collection->get('core.folders.open')); + $this->assertArrayHasKey('core.folders.create', $collection->all()); + $this->assertSimpleRoute('/{folderId}/create', 'POST', 'FoldersController', 'create', app: 'core', route: $collection->get('core.folders.create')); + } + + public function testParseRoutesWithResources(): void { + $routes = ['routes' => [ + ['name' => 'folders#open', 'url' => '/{folderId}/open', 'verb' => 'GET'], + ], 'resources' => [ + 'names' => ['url' => '/names'], + 'folder_names' => ['url' => '/folder/names'], + ]]; + + $collection = $this->parser->parseDefaultRoutes($routes, 'app1'); + $this->assertArrayHasKey('app1.folders.open', $collection->all()); + $this->assertSimpleResource('/apps/app1/folder/names', 'folder_names', 'FolderNamesController', 'app1', $collection); + $this->assertSimpleResource('/apps/app1/names', 'names', 'NamesController', 'app1', $collection); + } + + public function testParseRoutesWithPostfix(): void { + $routes = ['routes' => [ + ['name' => 'folders#update', 'url' => '/{folderId}/update', 'verb' => 'POST'], + ['name' => 'folders#update', 'url' => '/{folderId}/update', 'verb' => 'PUT', 'postfix' => '-edit'] + ]]; + + $collection = $this->parser->parseDefaultRoutes($routes, 'app1'); + $this->assertArrayHasKey('app1.folders.update', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/update', 'POST', 'FoldersController', 'update', route: $collection->get('app1.folders.update')); + $this->assertArrayHasKey('app1.folders.update-edit', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/update', 'PUT', 'FoldersController', 'update', route: $collection->get('app1.folders.update-edit')); + } + + public function testParseRoutesKebabCaseAction(): void { + $routes = ['routes' => [ + ['name' => 'folders#open_folder', 'url' => '/{folderId}/open', 'verb' => 'GET'] + ]]; + + $collection = $this->parser->parseDefaultRoutes($routes, 'app1'); + $this->assertArrayHasKey('app1.folders.open_folder', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/open', 'GET', 'FoldersController', 'openFolder', route: $collection->get('app1.folders.open_folder')); + } + + public function testParseRoutesKebabCaseController(): void { + $routes = ['routes' => [ + ['name' => 'my_folders#open', 'url' => '/{folderId}/open', 'verb' => 'GET'] + ]]; + + $collection = $this->parser->parseDefaultRoutes($routes, 'app1'); + $this->assertArrayHasKey('app1.my_folders.open', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/open', 'GET', 'MyFoldersController', 'open', route: $collection->get('app1.my_folders.open')); + } + + public function testParseRoutesLowercaseVerb(): void { + $routes = ['routes' => [ + ['name' => 'folders#delete', 'url' => '/{folderId}/delete', 'verb' => 'delete'] + ]]; + + $collection = $this->parser->parseDefaultRoutes($routes, 'app1'); + $this->assertArrayHasKey('app1.folders.delete', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/delete', 'DELETE', 'FoldersController', 'delete', route: $collection->get('app1.folders.delete')); + } + + public function testParseRoutesMissingVerb(): void { + $routes = ['routes' => [ + ['name' => 'folders#open', 'url' => '/{folderId}/open'] + ]]; + + $collection = $this->parser->parseDefaultRoutes($routes, 'app1'); + $this->assertArrayHasKey('app1.folders.open', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/open', 'GET', 'FoldersController', 'open', route: $collection->get('app1.folders.open')); + } + + public function testParseRoutesWithRequirements(): void { + $routes = ['routes' => [ + ['name' => 'folders#open', 'url' => '/{folderId}/open', 'verb' => 'GET', 'requirements' => ['folderId' => '\d+']] + ]]; + + $collection = $this->parser->parseDefaultRoutes($routes, 'app1'); + $this->assertArrayHasKey('app1.folders.open', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/open', 'GET', 'FoldersController', 'open', requirements: ['folderId' => '\d+'], route: $collection->get('app1.folders.open')); + } + + public function testParseRoutesWithDefaults(): void { + $routes = ['routes' => [ + ['name' => 'folders#open', 'url' => '/{folderId}/open', 'verb' => 'GET', 'defaults' => ['hello' => 'world']] + ]]; + + $collection = $this->parser->parseDefaultRoutes($routes, 'app1'); + $this->assertArrayHasKey('app1.folders.open', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/open', 'GET', 'FoldersController', 'open', defaults: ['hello' => 'world'], route: $collection->get('app1.folders.open')); + } + + public function testParseRoutesInvalidName(): void { + $routes = ['routes' => [ + ['name' => 'folders', 'url' => '/{folderId}/open', 'verb' => 'GET'] + ]]; + + $this->expectException(\UnexpectedValueException::class); + $this->parser->parseDefaultRoutes($routes, 'app1'); + } + + public function testParseRoutesInvalidName2(): void { + $routes = ['routes' => [ + ['name' => 'folders#open#action', 'url' => '/{folderId}/open', 'verb' => 'GET'] + ]]; + + $this->expectException(\UnexpectedValueException::class); + $this->parser->parseDefaultRoutes($routes, 'app1'); + } + + public function testParseRoutesEmpty(): void { + $routes = ['routes' => []]; + + $collection = $this->parser->parseDefaultRoutes($routes, 'app1'); + $this->assertEquals(0, $collection->count()); + } + + // OCS routes + + public function testParseOcsRoutes(): void { + $routes = ['ocs' => [ + ['name' => 'folders#open', 'url' => '/{folderId}/open', 'verb' => 'GET'], + ['name' => 'folders#create', 'url' => '/{folderId}/create', 'verb' => 'POST'] + ]]; + + $collection = $this->parser->parseOCSRoutes($routes, 'app1'); + $this->assertArrayHasKey('ocs.app1.folders.open', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/open', 'GET', 'FoldersController', 'open', route: $collection->get('ocs.app1.folders.open')); + $this->assertArrayHasKey('ocs.app1.folders.create', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/create', 'POST', 'FoldersController', 'create', route: $collection->get('ocs.app1.folders.create')); + } + + public function testParseOcsRoutesRootApps(): void { + $routes = ['ocs' => [ + ['name' => 'folders#open', 'url' => '/{folderId}/open', 'verb' => 'GET'], + ['name' => 'folders#create', 'url' => '/{folderId}/create', 'verb' => 'POST'] + ]]; + + $collection = $this->parser->parseOCSRoutes($routes, 'core'); + $this->assertArrayHasKey('ocs.core.folders.open', $collection->all()); + $this->assertSimpleRoute('/{folderId}/open', 'GET', 'FoldersController', 'open', app: 'core', route: $collection->get('ocs.core.folders.open')); + $this->assertArrayHasKey('ocs.core.folders.create', $collection->all()); + $this->assertSimpleRoute('/{folderId}/create', 'POST', 'FoldersController', 'create', app: 'core', route: $collection->get('ocs.core.folders.create')); + } + + public function testParseOcsRoutesWithPostfix(): void { + $routes = ['ocs' => [ + ['name' => 'folders#update', 'url' => '/{folderId}/update', 'verb' => 'POST'], + ['name' => 'folders#update', 'url' => '/{folderId}/update', 'verb' => 'PUT', 'postfix' => '-edit'] + ]]; + + $collection = $this->parser->parseOCSRoutes($routes, 'app1'); + $this->assertArrayHasKey('ocs.app1.folders.update', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/update', 'POST', 'FoldersController', 'update', route: $collection->get('ocs.app1.folders.update')); + $this->assertArrayHasKey('ocs.app1.folders.update-edit', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/update', 'PUT', 'FoldersController', 'update', route: $collection->get('ocs.app1.folders.update-edit')); + } + + public function testParseOcsRoutesKebabCaseAction(): void { + $routes = ['ocs' => [ + ['name' => 'folders#open_folder', 'url' => '/{folderId}/open', 'verb' => 'GET'] + ]]; + + $collection = $this->parser->parseOCSRoutes($routes, 'app1'); + $this->assertArrayHasKey('ocs.app1.folders.open_folder', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/open', 'GET', 'FoldersController', 'openFolder', route: $collection->get('ocs.app1.folders.open_folder')); + } + + public function testParseOcsRoutesKebabCaseController(): void { + $routes = ['ocs' => [ + ['name' => 'my_folders#open', 'url' => '/{folderId}/open', 'verb' => 'GET'] + ]]; + + $collection = $this->parser->parseOCSRoutes($routes, 'app1'); + $this->assertArrayHasKey('ocs.app1.my_folders.open', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/open', 'GET', 'MyFoldersController', 'open', route: $collection->get('ocs.app1.my_folders.open')); + } + + public function testParseOcsRoutesLowercaseVerb(): void { + $routes = ['ocs' => [ + ['name' => 'folders#delete', 'url' => '/{folderId}/delete', 'verb' => 'delete'] + ]]; + + $collection = $this->parser->parseOCSRoutes($routes, 'app1'); + $this->assertArrayHasKey('ocs.app1.folders.delete', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/delete', 'DELETE', 'FoldersController', 'delete', route: $collection->get('ocs.app1.folders.delete')); + } + + public function testParseOcsRoutesMissingVerb(): void { + $routes = ['ocs' => [ + ['name' => 'folders#open', 'url' => '/{folderId}/open'] + ]]; + + $collection = $this->parser->parseOCSRoutes($routes, 'app1'); + $this->assertArrayHasKey('ocs.app1.folders.open', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/open', 'GET', 'FoldersController', 'open', route: $collection->get('ocs.app1.folders.open')); + } + + public function testParseOcsRoutesWithRequirements(): void { + $routes = ['ocs' => [ + ['name' => 'folders#open', 'url' => '/{folderId}/open', 'verb' => 'GET', 'requirements' => ['folderId' => '\d+']] + ]]; + + $collection = $this->parser->parseOCSRoutes($routes, 'app1'); + $this->assertArrayHasKey('ocs.app1.folders.open', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/open', 'GET', 'FoldersController', 'open', requirements: ['folderId' => '\d+'], route: $collection->get('ocs.app1.folders.open')); + } + + public function testParseOcsRoutesWithDefaults(): void { + $routes = ['ocs' => [ + ['name' => 'folders#open', 'url' => '/{folderId}/open', 'verb' => 'GET', 'defaults' => ['hello' => 'world']] + ]]; + + $collection = $this->parser->parseOCSRoutes($routes, 'app1'); + $this->assertArrayHasKey('ocs.app1.folders.open', $collection->all()); + $this->assertSimpleRoute('/apps/app1/{folderId}/open', 'GET', 'FoldersController', 'open', defaults: ['hello' => 'world'], route: $collection->get('ocs.app1.folders.open')); + } + + public function testParseOcsRoutesInvalidName(): void { + $routes = ['ocs' => [ + ['name' => 'folders', 'url' => '/{folderId}/open', 'verb' => 'GET'] + ]]; + + $this->expectException(\UnexpectedValueException::class); + $this->parser->parseOCSRoutes($routes, 'app1'); + } + + public function testParseOcsRoutesEmpty(): void { + $routes = ['ocs' => []]; + + $collection = $this->parser->parseOCSRoutes($routes, 'app1'); + $this->assertEquals(0, $collection->count()); + } + + public function testParseOcsRoutesWithResources(): void { + $routes = ['ocs' => [ + ['name' => 'folders#open', 'url' => '/{folderId}/open', 'verb' => 'GET'], + ], 'ocs-resources' => [ + 'names' => ['url' => '/names', 'root' => '/core/something'], + 'folder_names' => ['url' => '/folder/names'], + ]]; + + $collection = $this->parser->parseOCSRoutes($routes, 'app1'); + $this->assertArrayHasKey('ocs.app1.folders.open', $collection->all()); + $this->assertOcsResource('/apps/app1/folder/names', 'folder_names', 'FolderNamesController', 'app1', $collection); + $this->assertOcsResource('/core/something/names', 'names', 'NamesController', 'app1', $collection); + } + + protected function assertSimpleRoute( + string $path, + string $method, + string $controller, + string $action, + string $app = 'app1', + array $requirements = [], + array $defaults = [], + ?RoutingRoute $route = null, + ): void { + self::assertEquals($path, $route->getPath()); + self::assertEqualsCanonicalizing([$method], $route->getMethods()); + self::assertEqualsCanonicalizing($requirements, $route->getRequirements()); + self::assertEquals([...$defaults, 'action' => null, 'caller' => [$app, $controller, $action]], $route->getDefaults()); + } + + protected function assertSimpleResource( + string $path, + string $resourceName, + string $controller, + string $app, + RouteCollection $collection, + ): void { + self::assertArrayHasKey("$app.$resourceName.index", $collection->all()); + self::assertArrayHasKey("$app.$resourceName.show", $collection->all()); + self::assertArrayHasKey("$app.$resourceName.create", $collection->all()); + self::assertArrayHasKey("$app.$resourceName.update", $collection->all()); + self::assertArrayHasKey("$app.$resourceName.destroy", $collection->all()); + + $this->assertSimpleRoute($path, 'GET', $controller, 'index', $app, route: $collection->get("$app.$resourceName.index")); + $this->assertSimpleRoute($path, 'POST', $controller, 'create', $app, route: $collection->get("$app.$resourceName.create")); + $this->assertSimpleRoute("$path/{id}", 'GET', $controller, 'show', $app, route: $collection->get("$app.$resourceName.show")); + $this->assertSimpleRoute("$path/{id}", 'PUT', $controller, 'update', $app, route: $collection->get("$app.$resourceName.update")); + $this->assertSimpleRoute("$path/{id}", 'DELETE', $controller, 'destroy', $app, route: $collection->get("$app.$resourceName.destroy")); + } + + protected function assertOcsResource( + string $path, + string $resourceName, + string $controller, + string $app, + RouteCollection $collection, + ): void { + self::assertArrayHasKey("ocs.$app.$resourceName.index", $collection->all()); + self::assertArrayHasKey("ocs.$app.$resourceName.show", $collection->all()); + self::assertArrayHasKey("ocs.$app.$resourceName.create", $collection->all()); + self::assertArrayHasKey("ocs.$app.$resourceName.update", $collection->all()); + self::assertArrayHasKey("ocs.$app.$resourceName.destroy", $collection->all()); + + $this->assertSimpleRoute($path, 'GET', $controller, 'index', $app, route: $collection->get("ocs.$app.$resourceName.index")); + $this->assertSimpleRoute($path, 'POST', $controller, 'create', $app, route: $collection->get("ocs.$app.$resourceName.create")); + $this->assertSimpleRoute("$path/{id}", 'GET', $controller, 'show', $app, route: $collection->get("ocs.$app.$resourceName.show")); + $this->assertSimpleRoute("$path/{id}", 'PUT', $controller, 'update', $app, route: $collection->get("ocs.$app.$resourceName.update")); + $this->assertSimpleRoute("$path/{id}", 'DELETE', $controller, 'destroy', $app, route: $collection->get("ocs.$app.$resourceName.destroy")); + } +} diff --git a/tests/lib/AppFramework/Routing/RoutingTest.php b/tests/lib/AppFramework/Routing/RoutingTest.php deleted file mode 100644 index 22037c31d0d..00000000000 --- a/tests/lib/AppFramework/Routing/RoutingTest.php +++ /dev/null @@ -1,425 +0,0 @@ -<?php - -namespace Test\AppFramework\Routing; - -use OC\AppFramework\DependencyInjection\DIContainer; -use OC\AppFramework\Routing\RouteConfig; -use OC\Route\Route; -use OC\Route\Router; -use OCP\Route\IRouter; -use PHPUnit\Framework\MockObject\MockObject; -use Psr\Log\LoggerInterface; - -class RoutingTest extends \Test\TestCase { - public function testSimpleRoute() { - $routes = ['routes' => [ - ['name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'GET'] - ]]; - - $this->assertSimpleRoute($routes, 'folders.open', 'GET', '/apps/app1/folders/{folderId}/open', 'FoldersController', 'open'); - } - - public function testSimpleRouteWithUnderScoreNames() { - $routes = ['routes' => [ - ['name' => 'admin_folders#open_current', 'url' => '/folders/{folderId}/open', 'verb' => 'delete', 'root' => ''] - ]]; - - $this->assertSimpleRoute($routes, 'admin_folders.open_current', 'DELETE', '/folders/{folderId}/open', 'AdminFoldersController', 'openCurrent', [], [], '', true); - } - - public function testSimpleOCSRoute() { - $routes = ['ocs' => [ - ['name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'GET'] - ] - ]; - - $this->assertSimpleOCSRoute($routes, 'folders.open', 'GET', '/apps/app1/folders/{folderId}/open', 'FoldersController', 'open'); - } - - public function testSimpleRouteWithMissingVerb() { - $routes = ['routes' => [ - ['name' => 'folders#open', 'url' => '/folders/{folderId}/open'] - ]]; - - $this->assertSimpleRoute($routes, 'folders.open', 'GET', '/apps/app1/folders/{folderId}/open', 'FoldersController', 'open'); - } - - public function testSimpleOCSRouteWithMissingVerb() { - $routes = ['ocs' => [ - ['name' => 'folders#open', 'url' => '/folders/{folderId}/open'] - ] - ]; - - $this->assertSimpleOCSRoute($routes, 'folders.open', 'GET', '/apps/app1/folders/{folderId}/open', 'FoldersController', 'open'); - } - - public function testSimpleRouteWithLowercaseVerb() { - $routes = ['routes' => [ - ['name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete'] - ]]; - - $this->assertSimpleRoute($routes, 'folders.open', 'DELETE', '/apps/app1/folders/{folderId}/open', 'FoldersController', 'open'); - } - - public function testSimpleOCSRouteWithLowercaseVerb() { - $routes = ['ocs' => [ - ['name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete'] - ] - ]; - - $this->assertSimpleOCSRoute($routes, 'folders.open', 'DELETE', '/apps/app1/folders/{folderId}/open', 'FoldersController', 'open'); - } - - public function testSimpleRouteWithRequirements() { - $routes = ['routes' => [ - ['name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete', 'requirements' => ['something']] - ]]; - - $this->assertSimpleRoute($routes, 'folders.open', 'DELETE', '/apps/app1/folders/{folderId}/open', 'FoldersController', 'open', ['something']); - } - - public function testSimpleOCSRouteWithRequirements() { - $routes = ['ocs' => [ - ['name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete', 'requirements' => ['something']] - ] - ]; - - $this->assertSimpleOCSRoute($routes, 'folders.open', 'DELETE', '/apps/app1/folders/{folderId}/open', 'FoldersController', 'open', ['something']); - } - - public function testSimpleRouteWithDefaults() { - $routes = ['routes' => [ - ['name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete', [], 'defaults' => ['param' => 'foobar']] - ]]; - - $this->assertSimpleRoute($routes, 'folders.open', 'DELETE', '/apps/app1/folders/{folderId}/open', 'FoldersController', 'open', [], ['param' => 'foobar']); - } - - - public function testSimpleOCSRouteWithDefaults() { - $routes = ['ocs' => [ - ['name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete', 'defaults' => ['param' => 'foobar']] - ] - ]; - - $this->assertSimpleOCSRoute($routes, 'folders.open', 'DELETE', '/apps/app1/folders/{folderId}/open', 'FoldersController', 'open', [], ['param' => 'foobar']); - } - - public function testSimpleRouteWithPostfix() { - $routes = ['routes' => [ - ['name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete', 'postfix' => '_something'] - ]]; - - $this->assertSimpleRoute($routes, 'folders.open', 'DELETE', '/apps/app1/folders/{folderId}/open', 'FoldersController', 'open', [], [], '_something'); - } - - public function testSimpleOCSRouteWithPostfix() { - $routes = ['ocs' => [ - ['name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete', 'postfix' => '_something'] - ] - ]; - - $this->assertSimpleOCSRoute($routes, 'folders.open', 'DELETE', '/apps/app1/folders/{folderId}/open', 'FoldersController', 'open', [], [], '_something'); - } - - - public function testSimpleRouteWithBrokenName() { - $this->expectException(\UnexpectedValueException::class); - - $routes = ['routes' => [ - ['name' => 'folders_open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete'] - ]]; - - /** @var IRouter|MockObject $router */ - $router = $this->getMockBuilder(Router::class) - ->onlyMethods(['create']) - ->setConstructorArgs([$this->createMock(LoggerInterface::class)]) - ->getMock(); - - // load route configuration - $container = new DIContainer('app1'); - $config = new RouteConfig($container, $router, $routes); - - $config->register(); - } - - - public function testSimpleOCSRouteWithBrokenName() { - $this->expectException(\UnexpectedValueException::class); - - $routes = ['ocs' => [ - ['name' => 'folders_open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete'] - ]]; - - /** @var IRouter|MockObject $router */ - $router = $this->getMockBuilder(Router::class) - ->onlyMethods(['create']) - ->setConstructorArgs([$this->createMock(LoggerInterface::class)]) - ->getMock(); - - // load route configuration - $container = new DIContainer('app1'); - $config = new RouteConfig($container, $router, $routes); - - $config->register(); - } - - public function testSimpleOCSRouteWithUnderScoreNames() { - $routes = ['ocs' => [ - ['name' => 'admin_folders#open_current', 'url' => '/folders/{folderId}/open', 'verb' => 'delete'] - ]]; - - $this->assertSimpleOCSRoute($routes, 'admin_folders.open_current', 'DELETE', '/apps/app1/folders/{folderId}/open', 'AdminFoldersController', 'openCurrent'); - } - - public function testOCSResource() { - $routes = ['ocs-resources' => ['account' => ['url' => '/accounts']]]; - - $this->assertOCSResource($routes, 'account', '/apps/app1/accounts', 'AccountController', 'id'); - } - - public function testOCSResourceWithUnderScoreName() { - $routes = ['ocs-resources' => ['admin_accounts' => ['url' => '/admin/accounts']]]; - - $this->assertOCSResource($routes, 'admin_accounts', '/apps/app1/admin/accounts', 'AdminAccountsController', 'id'); - } - - public function testOCSResourceWithRoot() { - $routes = ['ocs-resources' => ['admin_accounts' => ['url' => '/admin/accounts', 'root' => '/core/endpoint']]]; - - $this->assertOCSResource($routes, 'admin_accounts', '/core/endpoint/admin/accounts', 'AdminAccountsController', 'id'); - } - - public function testResource() { - $routes = ['resources' => ['account' => ['url' => '/accounts']]]; - - $this->assertResource($routes, 'account', '/apps/app1/accounts', 'AccountController', 'id'); - } - - public function testResourceWithUnderScoreName() { - $routes = ['resources' => ['admin_accounts' => ['url' => '/admin/accounts']]]; - - $this->assertResource($routes, 'admin_accounts', '/apps/app1/admin/accounts', 'AdminAccountsController', 'id'); - } - - private function assertSimpleRoute($routes, $name, $verb, $url, $controllerName, $actionName, array $requirements = [], array $defaults = [], $postfix = '', $allowRootUrl = false): void { - if ($postfix) { - $name .= $postfix; - } - - // route mocks - $container = new DIContainer('app1'); - $route = $this->mockRoute($container, $verb, $controllerName, $actionName, $requirements, $defaults); - - /** @var IRouter|MockObject $router */ - $router = $this->getMockBuilder(Router::class) - ->onlyMethods(['create']) - ->setConstructorArgs([$this->createMock(LoggerInterface::class)]) - ->getMock(); - - // we expect create to be called once: - $router - ->expects($this->once()) - ->method('create') - ->with($this->equalTo('app1.' . $name), $this->equalTo($url)) - ->willReturn($route); - - // load route configuration - $config = new RouteConfig($container, $router, $routes); - if ($allowRootUrl) { - self::invokePrivate($config, 'rootUrlApps', [['app1']]); - } - - $config->register(); - } - - /** - * @param $routes - * @param string $name - * @param string $verb - * @param string $url - * @param string $controllerName - * @param string $actionName - * @param array $requirements - * @param array $defaults - * @param string $postfix - */ - private function assertSimpleOCSRoute($routes, - $name, - $verb, - $url, - $controllerName, - $actionName, - array $requirements = [], - array $defaults = [], - $postfix = '') { - if ($postfix) { - $name .= $postfix; - } - - // route mocks - $container = new DIContainer('app1'); - $route = $this->mockRoute($container, $verb, $controllerName, $actionName, $requirements, $defaults); - - /** @var IRouter|MockObject $router */ - $router = $this->getMockBuilder(Router::class) - ->onlyMethods(['create']) - ->setConstructorArgs([$this->createMock(LoggerInterface::class)]) - ->getMock(); - - // we expect create to be called once: - $router - ->expects($this->once()) - ->method('create') - ->with($this->equalTo('ocs.app1.' . $name), $this->equalTo($url)) - ->willReturn($route); - - // load route configuration - $config = new RouteConfig($container, $router, $routes); - - $config->register(); - } - - /** - * @param array $yaml - * @param string $resourceName - * @param string $url - * @param string $controllerName - * @param string $paramName - */ - private function assertOCSResource($yaml, $resourceName, $url, $controllerName, $paramName): void { - /** @var IRouter|MockObject $router */ - $router = $this->getMockBuilder(Router::class) - ->onlyMethods(['create']) - ->setConstructorArgs([$this->createMock(LoggerInterface::class)]) - ->getMock(); - - // route mocks - $container = new DIContainer('app1'); - $indexRoute = $this->mockRoute($container, 'GET', $controllerName, 'index'); - $showRoute = $this->mockRoute($container, 'GET', $controllerName, 'show'); - $createRoute = $this->mockRoute($container, 'POST', $controllerName, 'create'); - $updateRoute = $this->mockRoute($container, 'PUT', $controllerName, 'update'); - $destroyRoute = $this->mockRoute($container, 'DELETE', $controllerName, 'destroy'); - - $urlWithParam = $url . '/{' . $paramName . '}'; - - // we expect create to be called five times: - $router - ->expects($this->exactly(5)) - ->method('create') - ->withConsecutive( - [$this->equalTo('ocs.app1.' . $resourceName . '.index'), $this->equalTo($url)], - [$this->equalTo('ocs.app1.' . $resourceName . '.show'), $this->equalTo($urlWithParam)], - [$this->equalTo('ocs.app1.' . $resourceName . '.create'), $this->equalTo($url)], - [$this->equalTo('ocs.app1.' . $resourceName . '.update'), $this->equalTo($urlWithParam)], - [$this->equalTo('ocs.app1.' . $resourceName . '.destroy'), $this->equalTo($urlWithParam)], - )->willReturnOnConsecutiveCalls( - $indexRoute, - $showRoute, - $createRoute, - $updateRoute, - $destroyRoute, - ); - - // load route configuration - $config = new RouteConfig($container, $router, $yaml); - - $config->register(); - } - - /** - * @param string $resourceName - * @param string $url - * @param string $controllerName - * @param string $paramName - */ - private function assertResource($yaml, $resourceName, $url, $controllerName, $paramName) { - /** @var IRouter|MockObject $router */ - $router = $this->getMockBuilder(Router::class) - ->onlyMethods(['create']) - ->setConstructorArgs([$this->createMock(LoggerInterface::class)]) - ->getMock(); - - // route mocks - $container = new DIContainer('app1'); - $indexRoute = $this->mockRoute($container, 'GET', $controllerName, 'index'); - $showRoute = $this->mockRoute($container, 'GET', $controllerName, 'show'); - $createRoute = $this->mockRoute($container, 'POST', $controllerName, 'create'); - $updateRoute = $this->mockRoute($container, 'PUT', $controllerName, 'update'); - $destroyRoute = $this->mockRoute($container, 'DELETE', $controllerName, 'destroy'); - - $urlWithParam = $url . '/{' . $paramName . '}'; - - // we expect create to be called five times: - $router - ->expects($this->exactly(5)) - ->method('create') - ->withConsecutive( - [$this->equalTo('app1.' . $resourceName . '.index'), $this->equalTo($url)], - [$this->equalTo('app1.' . $resourceName . '.show'), $this->equalTo($urlWithParam)], - [$this->equalTo('app1.' . $resourceName . '.create'), $this->equalTo($url)], - [$this->equalTo('app1.' . $resourceName . '.update'), $this->equalTo($urlWithParam)], - [$this->equalTo('app1.' . $resourceName . '.destroy'), $this->equalTo($urlWithParam)], - )->willReturnOnConsecutiveCalls( - $indexRoute, - $showRoute, - $createRoute, - $updateRoute, - $destroyRoute, - ); - - // load route configuration - $config = new RouteConfig($container, $router, $yaml); - - $config->register(); - } - - /** - * @param DIContainer $container - * @param string $verb - * @param string $controllerName - * @param string $actionName - * @param array $requirements - * @param array $defaults - * @return MockObject - */ - private function mockRoute( - DIContainer $container, - $verb, - $controllerName, - $actionName, - array $requirements = [], - array $defaults = [] - ) { - $route = $this->getMockBuilder(Route::class) - ->onlyMethods(['method', 'requirements', 'defaults']) - ->disableOriginalConstructor() - ->getMock(); - $route - ->expects($this->once()) - ->method('method') - ->with($this->equalTo($verb)) - ->willReturn($route); - - if (count($requirements) > 0) { - $route - ->expects($this->once()) - ->method('requirements') - ->with($this->equalTo($requirements)) - ->willReturn($route); - } - - $route->expects($this->once()) - ->method('defaults') - ->with($this->callback(function (array $def) use ($defaults, $controllerName, $actionName) { - $defaults['caller'] = ['app1', $controllerName, $actionName]; - - $this->assertEquals($defaults, $def); - return true; - })) - ->willReturn($route); - - return $route; - } -} diff --git a/tests/lib/AppFramework/Services/AppConfigTest.php b/tests/lib/AppFramework/Services/AppConfigTest.php new file mode 100644 index 00000000000..38fa6bdcac6 --- /dev/null +++ b/tests/lib/AppFramework/Services/AppConfigTest.php @@ -0,0 +1,668 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace Test\AppFramework\Services; + +use OC\AppConfig as AppConfigCore; +use OC\AppFramework\Services\AppConfig; +use OCP\Exceptions\AppConfigTypeConflictException; +use OCP\Exceptions\AppConfigUnknownKeyException; +use OCP\IAppConfig as IAppConfigCore; +use OCP\IConfig; +use PHPUnit\Framework\MockObject\MockObject; +use Test\TestCase; + +class AppConfigTest extends TestCase { + private IConfig|MockObject $config; + private IAppConfigCore|MockObject $appConfigCore; + private AppConfig $appConfig; + + private const TEST_APPID = 'appconfig-test'; + + protected function setUp(): void { + parent::setUp(); + $this->config = $this->createMock(IConfig::class); + $this->appConfigCore = $this->createMock(AppConfigCore::class); + + $this->appConfig = new AppConfig($this->config, $this->appConfigCore, self::TEST_APPID); + } + + public function testGetAppKeys(): void { + $expected = ['key1', 'key2', 'key3', 'key4', 'key5', 'key6', 'key7', 'test8']; + $this->appConfigCore->expects($this->once()) + ->method('getKeys') + ->with(self::TEST_APPID) + ->willReturn($expected); + $this->assertSame($expected, $this->appConfig->getAppKeys()); + } + + + /** + * @return array + * @see testHasAppKey + */ + public static function providerHasAppKey(): array { + return [ + // lazy, expected + [false, true], + [true, true], + [false, false], + [true, false], + ]; + } + + /** + * + * @param bool $lazy + * @param bool $expected + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerHasAppKey')] + public function testHasAppKey(bool $lazy, bool $expected): void { + $key = 'key'; + $this->appConfigCore->expects($this->once()) + ->method('hasKey') + ->with(self::TEST_APPID, $key, $lazy) + ->willReturn($expected); + $this->assertSame($expected, $this->appConfig->hasAppKey($key, $lazy)); + } + + + /** + * @return array + * @see testIsSensitive + */ + public static function providerIsSensitive(): array { + return [ + // lazy, expected + [false, true], + [true, true], + [false, false], + [true, false], + ]; + } + + /** + * + * @param bool $lazy + * @param bool $expected + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerIsSensitive')] + public function testIsSensitive(bool $lazy, bool $expected): void { + $key = 'key'; + $this->appConfigCore->expects($this->once()) + ->method('isSensitive') + ->with(self::TEST_APPID, $key, $lazy) + ->willReturn($expected); + + $this->assertSame($expected, $this->appConfig->isSensitive($key, $lazy)); + } + + /** + * + * @param bool $lazy + * @param bool $expected + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerIsSensitive')] + public function testIsSensitiveException(bool $lazy, bool $expected): void { + $key = 'unknown-key'; + $this->appConfigCore->expects($this->once()) + ->method('isSensitive') + ->with(self::TEST_APPID, $key, $lazy) + ->willThrowException(new AppConfigUnknownKeyException()); + + $this->expectException(AppConfigUnknownKeyException::class); + $this->appConfig->isSensitive($key, $lazy); + } + + /** + * @return array + * @see testIsLazy + */ + public static function providerIsLazy(): array { + return [ + // expected + [true], + [false], + ]; + } + + /** + * @param bool $expected + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerIsLazy')] + public function testIsLazy(bool $expected): void { + $key = 'key'; + $this->appConfigCore->expects($this->once()) + ->method('isLazy') + ->with(self::TEST_APPID, $key) + ->willReturn($expected); + + $this->assertSame($expected, $this->appConfig->isLazy($key)); + } + + public function testIsLazyException(): void { + $key = 'unknown-key'; + $this->appConfigCore->expects($this->once()) + ->method('isLazy') + ->with(self::TEST_APPID, $key) + ->willThrowException(new AppConfigUnknownKeyException()); + + $this->expectException(AppConfigUnknownKeyException::class); + $this->appConfig->isLazy($key); + } + + /** + * @return array + * @see testGetAllAppValues + */ + public static function providerGetAllAppValues(): array { + return [ + // key, filtered + ['', false], + ['', true], + ['key', false], + ['key', true], + ]; + } + + /** + * + * @param string $key + * @param bool $filtered + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerGetAllAppValues')] + public function testGetAllAppValues(string $key, bool $filtered): void { + $expected = [ + 'key1' => 'value1', + 'key2' => 3, + 'key3' => 3.14, + 'key4' => true + ]; + + $this->appConfigCore->expects($this->once()) + ->method('getAllValues') + ->with(self::TEST_APPID, $key, $filtered) + ->willReturn($expected); + + $this->assertSame($expected, $this->appConfig->getAllAppValues($key, $filtered)); + } + + public function testSetAppValue(): void { + $key = 'key'; + $value = 'value'; + $this->appConfigCore->expects($this->once()) + ->method('setValueMixed') + ->with(self::TEST_APPID, $key, $value); + + $this->appConfig->setAppValue($key, $value); + } + + /** + * @return array + * @see testSetAppValueString + * @see testSetAppValueStringException + * @see testSetAppValueInt + * @see testSetAppValueIntException + * @see testSetAppValueFloat + * @see testSetAppValueFloatException + * @see testSetAppValueArray + * @see testSetAppValueArrayException + */ + public static function providerSetAppValue(): array { + return [ + // lazy, sensitive, expected + [false, false, true], + [false, true, true], + [true, true, true], + [true, false, true], + [false, false, false], + [false, true, false], + [true, true, false], + [true, false, false], + ]; + } + + /** + * + * @param bool $lazy + * @param bool $sensitive + * @param bool $expected + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerSetAppValue')] + public function testSetAppValueString(bool $lazy, bool $sensitive, bool $expected): void { + $key = 'key'; + $value = 'valueString'; + $this->appConfigCore->expects($this->once()) + ->method('setValueString') + ->with(self::TEST_APPID, $key, $value, $lazy, $sensitive) + ->willReturn($expected); + + $this->assertSame($expected, $this->appConfig->setAppValueString($key, $value, $lazy, $sensitive)); + } + + /** + * + * @param bool $lazy + * @param bool $sensitive + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerSetAppValue')] + public function testSetAppValueStringException(bool $lazy, bool $sensitive): void { + $key = 'key'; + $value = 'valueString'; + $this->appConfigCore->expects($this->once()) + ->method('setValueString') + ->with(self::TEST_APPID, $key, $value, $lazy, $sensitive) + ->willThrowException(new AppConfigTypeConflictException()); + + $this->expectException(AppConfigTypeConflictException::class); + $this->appConfig->setAppValueString($key, $value, $lazy, $sensitive); + } + + /** + * + * @param bool $lazy + * @param bool $sensitive + * @param bool $expected + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerSetAppValue')] + public function testSetAppValueInt(bool $lazy, bool $sensitive, bool $expected): void { + $key = 'key'; + $value = 42; + $this->appConfigCore->expects($this->once()) + ->method('setValueInt') + ->with(self::TEST_APPID, $key, $value, $lazy, $sensitive) + ->willReturn($expected); + + $this->assertSame($expected, $this->appConfig->setAppValueInt($key, $value, $lazy, $sensitive)); + } + + /** + * + * @param bool $lazy + * @param bool $sensitive + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerSetAppValue')] + public function testSetAppValueIntException(bool $lazy, bool $sensitive): void { + $key = 'key'; + $value = 42; + $this->appConfigCore->expects($this->once()) + ->method('setValueInt') + ->with(self::TEST_APPID, $key, $value, $lazy, $sensitive) + ->willThrowException(new AppConfigTypeConflictException()); + + $this->expectException(AppConfigTypeConflictException::class); + $this->appConfig->setAppValueInt($key, $value, $lazy, $sensitive); + } + + /** + * + * @param bool $lazy + * @param bool $sensitive + * @param bool $expected + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerSetAppValue')] + public function testSetAppValueFloat(bool $lazy, bool $sensitive, bool $expected): void { + $key = 'key'; + $value = 3.14; + $this->appConfigCore->expects($this->once()) + ->method('setValueFloat') + ->with(self::TEST_APPID, $key, $value, $lazy, $sensitive) + ->willReturn($expected); + + $this->assertSame($expected, $this->appConfig->setAppValueFloat($key, $value, $lazy, $sensitive)); + } + + /** + * + * @param bool $lazy + * @param bool $sensitive + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerSetAppValue')] + public function testSetAppValueFloatException(bool $lazy, bool $sensitive): void { + $key = 'key'; + $value = 3.14; + $this->appConfigCore->expects($this->once()) + ->method('setValueFloat') + ->with(self::TEST_APPID, $key, $value, $lazy, $sensitive) + ->willThrowException(new AppConfigTypeConflictException()); + + $this->expectException(AppConfigTypeConflictException::class); + $this->appConfig->setAppValueFloat($key, $value, $lazy, $sensitive); + } + + /** + * @return array + * @see testSetAppValueBool + */ + public static function providerSetAppValueBool(): array { + return [ + // lazy, expected + [false, true], + [false, false], + [true, true], + [true, false], + ]; + } + + /** + * + * @param bool $lazy + * @param bool $expected + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerSetAppValueBool')] + public function testSetAppValueBool(bool $lazy, bool $expected): void { + $key = 'key'; + $value = true; + $this->appConfigCore->expects($this->once()) + ->method('setValueBool') + ->with(self::TEST_APPID, $key, $value, $lazy) + ->willReturn($expected); + + $this->assertSame($expected, $this->appConfig->setAppValueBool($key, $value, $lazy)); + } + + /** + * @param bool $lazy + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerSetAppValueBool')] + public function testSetAppValueBoolException(bool $lazy): void { + $key = 'key'; + $value = true; + $this->appConfigCore->expects($this->once()) + ->method('setValueBool') + ->with(self::TEST_APPID, $key, $value, $lazy) + ->willThrowException(new AppConfigTypeConflictException()); + + $this->expectException(AppConfigTypeConflictException::class); + $this->appConfig->setAppValueBool($key, $value, $lazy); + } + + /** + * + * @param bool $lazy + * @param bool $sensitive + * @param bool $expected + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerSetAppValue')] + public function testSetAppValueArray(bool $lazy, bool $sensitive, bool $expected): void { + $key = 'key'; + $value = ['item' => true]; + $this->appConfigCore->expects($this->once()) + ->method('setValueArray') + ->with(self::TEST_APPID, $key, $value, $lazy, $sensitive) + ->willReturn($expected); + + $this->assertSame($expected, $this->appConfig->setAppValueArray($key, $value, $lazy, $sensitive)); + } + + /** + * + * @param bool $lazy + * @param bool $sensitive + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerSetAppValue')] + public function testSetAppValueArrayException(bool $lazy, bool $sensitive): void { + $key = 'key'; + $value = ['item' => true]; + $this->appConfigCore->expects($this->once()) + ->method('setValueArray') + ->with(self::TEST_APPID, $key, $value, $lazy, $sensitive) + ->willThrowException(new AppConfigTypeConflictException()); + + $this->expectException(AppConfigTypeConflictException::class); + $this->appConfig->setAppValueArray($key, $value, $lazy, $sensitive); + } + + public function testGetAppValue(): void { + $key = 'key'; + $value = 'value'; + $default = 'default'; + $this->appConfigCore->expects($this->once()) + ->method('getValueMixed') + ->with(self::TEST_APPID, $key, $default) + ->willReturn($value); + + $this->assertSame($value, $this->appConfig->getAppValue($key, $default)); + } + + public function testGetAppValueDefault(): void { + $key = 'key'; + $default = 'default'; + $this->appConfigCore->expects($this->once()) + ->method('getValueMixed') + ->with(self::TEST_APPID, $key, $default) + ->willReturn($default); + + $this->assertSame($default, $this->appConfig->getAppValue($key, $default)); + } + + /** + * @return array + * @see testGetAppValueString + * @see testGetAppValueStringException + * @see testGetAppValueInt + * @see testGetAppValueIntException + * @see testGetAppValueFloat + * @see testGetAppValueFloatException + * @see testGetAppValueBool + * @see testGetAppValueBoolException + * @see testGetAppValueArray + * @see testGetAppValueArrayException + */ + public static function providerGetAppValue(): array { + return [ + // lazy, exist + [false, false], + [false, true], + [true, true], + [true, false] + ]; + } + + /** + * + * @param bool $lazy + * @param bool $exist + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerGetAppValue')] + public function testGetAppValueString(bool $lazy, bool $exist): void { + $key = 'key'; + $value = 'valueString'; + $default = 'default'; + + $expected = ($exist) ? $value : $default; + $this->appConfigCore->expects($this->once()) + ->method('getValueString') + ->with(self::TEST_APPID, $key, $default, $lazy) + ->willReturn($expected); + + $this->assertSame($expected, $this->appConfig->getAppValueString($key, $default, $lazy)); + } + + /** + * @param bool $lazy + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerGetAppValue')] + public function testGetAppValueStringException(bool $lazy): void { + $key = 'key'; + $default = 'default'; + + $this->appConfigCore->expects($this->once()) + ->method('getValueString') + ->with(self::TEST_APPID, $key, $default, $lazy) + ->willThrowException(new AppConfigTypeConflictException()); + + $this->expectException(AppConfigTypeConflictException::class); + $this->appConfig->getAppValueString($key, $default, $lazy); + } + + /** + * + * @param bool $lazy + * @param bool $exist + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerGetAppValue')] + public function testGetAppValueInt(bool $lazy, bool $exist): void { + $key = 'key'; + $value = 42; + $default = 17; + + $expected = ($exist) ? $value : $default; + $this->appConfigCore->expects($this->once()) + ->method('getValueInt') + ->with(self::TEST_APPID, $key, $default, $lazy) + ->willReturn($expected); + + $this->assertSame($expected, $this->appConfig->getAppValueInt($key, $default, $lazy)); + } + + /** + * @param bool $lazy + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerGetAppValue')] + public function testGetAppValueIntException(bool $lazy): void { + $key = 'key'; + $default = 17; + + $this->appConfigCore->expects($this->once()) + ->method('getValueInt') + ->with(self::TEST_APPID, $key, $default, $lazy) + ->willThrowException(new AppConfigTypeConflictException()); + + $this->expectException(AppConfigTypeConflictException::class); + $this->appConfig->getAppValueInt($key, $default, $lazy); + } + + /** + * + * @param bool $lazy + * @param bool $exist + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerGetAppValue')] + public function testGetAppValueFloat(bool $lazy, bool $exist): void { + $key = 'key'; + $value = 3.14; + $default = 17.04; + + $expected = ($exist) ? $value : $default; + $this->appConfigCore->expects($this->once()) + ->method('getValueFloat') + ->with(self::TEST_APPID, $key, $default, $lazy) + ->willReturn($expected); + + $this->assertSame($expected, $this->appConfig->getAppValueFloat($key, $default, $lazy)); + } + + /** + * @param bool $lazy + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerGetAppValue')] + public function testGetAppValueFloatException(bool $lazy): void { + $key = 'key'; + $default = 17.04; + + $this->appConfigCore->expects($this->once()) + ->method('getValueFloat') + ->with(self::TEST_APPID, $key, $default, $lazy) + ->willThrowException(new AppConfigTypeConflictException()); + + $this->expectException(AppConfigTypeConflictException::class); + $this->appConfig->getAppValueFloat($key, $default, $lazy); + } + + /** + * + * @param bool $lazy + * @param bool $exist + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerGetAppValue')] + public function testGetAppValueBool(bool $lazy, bool $exist): void { + $key = 'key'; + $value = true; + $default = false; + + $expected = ($exist) ? $value : $default; // yes, it can be simplified + $this->appConfigCore->expects($this->once()) + ->method('getValueBool') + ->with(self::TEST_APPID, $key, $default, $lazy) + ->willReturn($expected); + + $this->assertSame($expected, $this->appConfig->getAppValueBool($key, $default, $lazy)); + } + + /** + * @param bool $lazy + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerGetAppValue')] + public function testGetAppValueBoolException(bool $lazy): void { + $key = 'key'; + $default = false; + + $this->appConfigCore->expects($this->once()) + ->method('getValueBool') + ->with(self::TEST_APPID, $key, $default, $lazy) + ->willThrowException(new AppConfigTypeConflictException()); + + $this->expectException(AppConfigTypeConflictException::class); + $this->appConfig->getAppValueBool($key, $default, $lazy); + } + + /** + * + * @param bool $lazy + * @param bool $exist + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerGetAppValue')] + public function testGetAppValueArray(bool $lazy, bool $exist): void { + $key = 'key'; + $value = ['item' => true]; + $default = []; + + $expected = ($exist) ? $value : $default; + $this->appConfigCore->expects($this->once()) + ->method('getValueArray') + ->with(self::TEST_APPID, $key, $default, $lazy) + ->willReturn($expected); + + $this->assertSame($expected, $this->appConfig->getAppValueArray($key, $default, $lazy)); + } + + /** + * @param bool $lazy + */ + #[\PHPUnit\Framework\Attributes\DataProvider('providerGetAppValue')] + public function testGetAppValueArrayException(bool $lazy): void { + $key = 'key'; + $default = []; + + $this->appConfigCore->expects($this->once()) + ->method('getValueArray') + ->with(self::TEST_APPID, $key, $default, $lazy) + ->willThrowException(new AppConfigTypeConflictException()); + + $this->expectException(AppConfigTypeConflictException::class); + $this->appConfig->getAppValueArray($key, $default, $lazy); + } + + public function testDeleteAppValue(): void { + $key = 'key'; + $this->appConfigCore->expects($this->once()) + ->method('deleteKey') + ->with(self::TEST_APPID, $key); + + $this->appConfig->deleteAppValue($key); + } + + public function testDeleteAppValues(): void { + $this->appConfigCore->expects($this->once()) + ->method('deleteApp') + ->with(self::TEST_APPID); + + $this->appConfig->deleteAppValues(); + } +} diff --git a/tests/lib/AppFramework/Utility/ControllerMethodReflectorTest.php b/tests/lib/AppFramework/Utility/ControllerMethodReflectorTest.php index 5452fb853b9..00ae4792824 100644 --- a/tests/lib/AppFramework/Utility/ControllerMethodReflectorTest.php +++ b/tests/lib/AppFramework/Utility/ControllerMethodReflectorTest.php @@ -1,24 +1,9 @@ <?php /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Utility; @@ -54,6 +39,16 @@ class MiddleController extends BaseController { public function test3() { } + + /** + * @psalm-param int<-4, 42> $rangedOne + * @psalm-param int<min, max> $rangedTwo + * @psalm-param int<1, 6>|null $rangedThree + * @psalm-param ?int<-70, -30> $rangedFour + * @return void + */ + public function test4(int $rangedOne, int $rangedTwo, ?int $rangedThree, ?int $rangedFour) { + } } class EndController extends MiddleController { @@ -63,7 +58,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { /** * @Annotation */ - public function testReadAnnotation() { + public function testReadAnnotation(): void { $reader = new ControllerMethodReflector(); $reader->reflect( '\Test\AppFramework\Utility\ControllerMethodReflectorTest', @@ -76,10 +71,10 @@ class ControllerMethodReflectorTest extends \Test\TestCase { /** * @Annotation(parameter=value) */ - public function testGetAnnotationParameterSingle() { + public function testGetAnnotationParameterSingle(): void { $reader = new ControllerMethodReflector(); $reader->reflect( - __CLASS__, + self::class, __FUNCTION__ ); @@ -89,10 +84,10 @@ class ControllerMethodReflectorTest extends \Test\TestCase { /** * @Annotation(parameter1=value1, parameter2=value2,parameter3=value3) */ - public function testGetAnnotationParameterMultiple() { + public function testGetAnnotationParameterMultiple(): void { $reader = new ControllerMethodReflector(); $reader->reflect( - __CLASS__, + self::class, __FUNCTION__ ); @@ -105,7 +100,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { * @Annotation * @param test */ - public function testReadAnnotationNoLowercase() { + public function testReadAnnotationNoLowercase(): void { $reader = new ControllerMethodReflector(); $reader->reflect( '\Test\AppFramework\Utility\ControllerMethodReflectorTest', @@ -121,7 +116,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { * @Annotation * @param int $test */ - public function testReadTypeIntAnnotations() { + public function testReadTypeIntAnnotations(): void { $reader = new ControllerMethodReflector(); $reader->reflect( '\Test\AppFramework\Utility\ControllerMethodReflectorTest', @@ -142,7 +137,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { /** * @requires PHP 7 */ - public function testReadTypeIntAnnotationsScalarTypes() { + public function testReadTypeIntAnnotationsScalarTypes(): void { $reader = new ControllerMethodReflector(); $reader->reflect( '\Test\AppFramework\Utility\ControllerMethodReflectorTest', @@ -160,7 +155,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { * @Annotation * @param double $test something special */ - public function testReadTypeDoubleAnnotations() { + public function testReadTypeDoubleAnnotations(): void { $reader = new ControllerMethodReflector(); $reader->reflect( '\Test\AppFramework\Utility\ControllerMethodReflectorTest', @@ -172,9 +167,9 @@ class ControllerMethodReflectorTest extends \Test\TestCase { /** * @Annotation - * @param string $foo + * @param string $foo */ - public function testReadTypeWhitespaceAnnotations() { + public function testReadTypeWhitespaceAnnotations(): void { $reader = new ControllerMethodReflector(); $reader->reflect( '\Test\AppFramework\Utility\ControllerMethodReflectorTest', @@ -187,7 +182,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { public function arguments($arg, $arg2 = 'hi') { } - public function testReflectParameters() { + public function testReflectParameters(): void { $reader = new ControllerMethodReflector(); $reader->reflect( '\Test\AppFramework\Utility\ControllerMethodReflectorTest', @@ -200,7 +195,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { public function arguments2($arg) { } - public function testReflectParameters2() { + public function testReflectParameters2(): void { $reader = new ControllerMethodReflector(); $reader->reflect( '\Test\AppFramework\Utility\ControllerMethodReflectorTest', @@ -211,7 +206,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { } - public function testInheritance() { + public function testInheritance(): void { $reader = new ControllerMethodReflector(); $reader->reflect('Test\AppFramework\Utility\EndController', 'test'); @@ -219,7 +214,7 @@ class ControllerMethodReflectorTest extends \Test\TestCase { } - public function testInheritanceOverride() { + public function testInheritanceOverride(): void { $reader = new ControllerMethodReflector(); $reader->reflect('Test\AppFramework\Utility\EndController', 'test2'); @@ -228,10 +223,31 @@ class ControllerMethodReflectorTest extends \Test\TestCase { } - public function testInheritanceOverrideNoDocblock() { + public function testInheritanceOverrideNoDocblock(): void { $reader = new ControllerMethodReflector(); $reader->reflect('Test\AppFramework\Utility\EndController', 'test3'); $this->assertFalse($reader->hasAnnotation('Annotation')); } + + public function testRangeDetection(): void { + $reader = new ControllerMethodReflector(); + $reader->reflect('Test\AppFramework\Utility\EndController', 'test4'); + + $rangeInfo1 = $reader->getRange('rangedOne'); + $this->assertSame(-4, $rangeInfo1['min']); + $this->assertSame(42, $rangeInfo1['max']); + + $rangeInfo2 = $reader->getRange('rangedTwo'); + $this->assertSame(PHP_INT_MIN, $rangeInfo2['min']); + $this->assertSame(PHP_INT_MAX, $rangeInfo2['max']); + + $rangeInfo3 = $reader->getRange('rangedThree'); + $this->assertSame(1, $rangeInfo3['min']); + $this->assertSame(6, $rangeInfo3['max']); + + $rangeInfo3 = $reader->getRange('rangedFour'); + $this->assertSame(-70, $rangeInfo3['min']); + $this->assertSame(-30, $rangeInfo3['max']); + } } diff --git a/tests/lib/AppFramework/Utility/SimpleContainerTest.php b/tests/lib/AppFramework/Utility/SimpleContainerTest.php index 8caaf517f5c..33800c7376f 100644 --- a/tests/lib/AppFramework/Utility/SimpleContainerTest.php +++ b/tests/lib/AppFramework/Utility/SimpleContainerTest.php @@ -3,29 +3,16 @@ declare(strict_types=1); /** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2014 Bernhard Posselt <dev@bernhard-posselt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library 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 library. 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 Test\AppFramework\Utility; use OC\AppFramework\Utility\SimpleContainer; +use OCP\AppFramework\QueryException; +use Psr\Container\NotFoundExceptionInterface; interface TestInterface { } @@ -34,29 +21,40 @@ class ClassEmptyConstructor implements IInterfaceConstructor { } class ClassSimpleConstructor implements IInterfaceConstructor { - public $test; - public function __construct($test) { - $this->test = $test; + public function __construct( + public $test, + ) { } } class ClassComplexConstructor { - public $class; - public $test; - public function __construct(ClassSimpleConstructor $class, $test) { - $this->class = $class; - $this->test = $test; + public function __construct( + public ClassSimpleConstructor $class, + public $test, + ) { + } +} + +class ClassNullableUntypedConstructorArg { + public function __construct( + public $class, + ) { + } +} +class ClassNullableTypedConstructorArg { + public function __construct( + public ?\Some\Class $class, + ) { } } interface IInterfaceConstructor { } class ClassInterfaceConstructor { - public $class; - public $test; - public function __construct(IInterfaceConstructor $class, $test) { - $this->class = $class; - $this->test = $test; + public function __construct( + public IInterfaceConstructor $class, + public $test, + ) { } } @@ -70,41 +68,61 @@ class SimpleContainerTest extends \Test\TestCase { - public function testRegister() { + public function testRegister(): void { $this->container->registerParameter('test', 'abc'); $this->assertEquals('abc', $this->container->query('test')); } + /** + * Test querying a class that is not registered without autoload enabled + */ + public function testNothingRegistered(): void { + try { + $this->container->query('something really hard', false); + $this->fail('Expected `QueryException` exception was not thrown'); + } catch (\Throwable $exception) { + $this->assertInstanceOf(QueryException::class, $exception); + $this->assertInstanceOf(NotFoundExceptionInterface::class, $exception); + } + } - public function testNothingRegistered() { - $this->expectException(\OCP\AppFramework\QueryException::class); - $this->container->query('something really hard'); + /** + * Test querying a class that is not registered with autoload enabled + */ + public function testNothingRegistered_autoload(): void { + try { + $this->container->query('something really hard'); + $this->fail('Expected `QueryException` exception was not thrown'); + } catch (\Throwable $exception) { + $this->assertInstanceOf(QueryException::class, $exception); + $this->assertInstanceOf(NotFoundExceptionInterface::class, $exception); + } } - public function testNotAClass() { - $this->expectException(\OCP\AppFramework\QueryException::class); + public function testNotAClass(): void { + $this->expectException(QueryException::class); $this->container->query('Test\AppFramework\Utility\TestInterface'); } - public function testNoConstructorClass() { + public function testNoConstructorClass(): void { $object = $this->container->query('Test\AppFramework\Utility\ClassEmptyConstructor'); $this->assertTrue($object instanceof ClassEmptyConstructor); } - public function testInstancesOnlyOnce() { + public function testInstancesOnlyOnce(): void { $object = $this->container->query('Test\AppFramework\Utility\ClassEmptyConstructor'); $object2 = $this->container->query('Test\AppFramework\Utility\ClassEmptyConstructor'); $this->assertSame($object, $object2); } - public function testConstructorSimple() { + public function testConstructorSimple(): void { $this->container->registerParameter('test', 'abc'); $object = $this->container->query( 'Test\AppFramework\Utility\ClassSimpleConstructor' @@ -114,7 +132,7 @@ class SimpleContainerTest extends \Test\TestCase { } - public function testConstructorComplex() { + public function testConstructorComplex(): void { $this->container->registerParameter('test', 'abc'); $object = $this->container->query( 'Test\AppFramework\Utility\ClassComplexConstructor' @@ -125,7 +143,7 @@ class SimpleContainerTest extends \Test\TestCase { } - public function testConstructorComplexInterface() { + public function testConstructorComplexInterface(): void { $this->container->registerParameter('test', 'abc'); $this->container->registerService( 'Test\AppFramework\Utility\IInterfaceConstructor', function ($c) { @@ -140,7 +158,7 @@ class SimpleContainerTest extends \Test\TestCase { } - public function testOverrideService() { + public function testOverrideService(): void { $this->container->registerService( 'Test\AppFramework\Utility\IInterfaceConstructor', function ($c) { return $c->query('Test\AppFramework\Utility\ClassSimpleConstructor'); @@ -155,13 +173,13 @@ class SimpleContainerTest extends \Test\TestCase { $this->assertTrue($object instanceof ClassEmptyConstructor); } - public function testRegisterAliasParamter() { + public function testRegisterAliasParamter(): void { $this->container->registerParameter('test', 'abc'); $this->container->registerAlias('test1', 'test'); $this->assertEquals('abc', $this->container->query('test1')); } - public function testRegisterAliasService() { + public function testRegisterAliasService(): void { $this->container->registerService('test', function () { return new \StdClass; }, true); @@ -174,7 +192,7 @@ class SimpleContainerTest extends \Test\TestCase { $this->container->query('test'), $this->container->query('test1')); } - public function sanitizeNameProvider() { + public static function sanitizeNameProvider(): array { return [ ['ABC\\Foo', 'ABC\\Foo'], ['\\ABC\\Foo', '\\ABC\\Foo'], @@ -183,10 +201,8 @@ class SimpleContainerTest extends \Test\TestCase { ]; } - /** - * @dataProvider sanitizeNameProvider - */ - public function testSanitizeName($register, $query) { + #[\PHPUnit\Framework\Attributes\DataProvider('sanitizeNameProvider')] + public function testSanitizeName($register, $query): void { $this->container->registerService($register, function () { return 'abc'; }); @@ -194,15 +210,17 @@ class SimpleContainerTest extends \Test\TestCase { } - public function testConstructorComplexNoTestParameterFound() { - $this->expectException(\OCP\AppFramework\QueryException::class); + public function testConstructorComplexNoTestParameterFound(): void { + $this->expectException(QueryException::class); $object = $this->container->query( 'Test\AppFramework\Utility\ClassComplexConstructor' ); + /* Use the object to trigger DI on PHP >= 8.4 */ + get_object_vars($object); } - public function testRegisterFactory() { + public function testRegisterFactory(): void { $this->container->registerService('test', function () { return new \StdClass(); }, false); @@ -210,7 +228,7 @@ class SimpleContainerTest extends \Test\TestCase { $this->container->query('test'), $this->container->query('test')); } - public function testRegisterAliasFactory() { + public function testRegisterAliasFactory(): void { $this->container->registerService('test', function () { return new \StdClass(); }, false); @@ -222,4 +240,21 @@ class SimpleContainerTest extends \Test\TestCase { $this->assertNotSame( $this->container->query('test'), $this->container->query('test1')); } + + public function testQueryUntypedNullable(): void { + $this->expectException(QueryException::class); + + $object = $this->container->query( + ClassNullableUntypedConstructorArg::class + ); + /* Use the object to trigger DI on PHP >= 8.4 */ + get_object_vars($object); + } + + public function testQueryTypedNullable(): void { + /** @var ClassNullableTypedConstructorArg $service */ + $service = $this->container->query(ClassNullableTypedConstructorArg::class); + + self::assertNull($service->class); + } } diff --git a/tests/lib/AppFramework/Utility/TimeFactoryTest.php b/tests/lib/AppFramework/Utility/TimeFactoryTest.php new file mode 100644 index 00000000000..276b2d6da4f --- /dev/null +++ b/tests/lib/AppFramework/Utility/TimeFactoryTest.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +namespace Test\AppFramework\Utility; + +use OC\AppFramework\Utility\TimeFactory; + +class TimeFactoryTest extends \Test\TestCase { + protected TimeFactory $timeFactory; + + protected function setUp(): void { + $this->timeFactory = new TimeFactory(); + } + + public function testNow(): void { + $now = $this->timeFactory->now(); + self::assertSame('UTC', $now->getTimezone()->getName()); + } + + public function testNowWithTimeZone(): void { + $timezone = new \DateTimeZone('Europe/Berlin'); + $withTimeZone = $this->timeFactory->withTimeZone($timezone); + + $now = $withTimeZone->now(); + self::assertSame('Europe/Berlin', $now->getTimezone()->getName()); + } + + public function testGetTimeZone(): void { + $expected = new \DateTimeZone('Europe/Berlin'); + $actual = $this->timeFactory->getTimeZone('Europe/Berlin'); + self::assertEquals($expected, $actual); + } + + public function testGetTimeZoneUTC(): void { + $expected = new \DateTimeZone('UTC'); + $actual = $this->timeFactory->getTimeZone(); + self::assertEquals($expected, $actual); + } + + public function testGetTimeZoneInvalid(): void { + $this->expectException(\Exception::class); + $this->timeFactory->getTimeZone('blubblub'); + } +} |