aboutsummaryrefslogtreecommitdiffstats
path: root/apps/theming/tests/Controller/ThemingControllerTest.php
diff options
context:
space:
mode:
Diffstat (limited to 'apps/theming/tests/Controller/ThemingControllerTest.php')
-rw-r--r--apps/theming/tests/Controller/ThemingControllerTest.php308
1 files changed, 142 insertions, 166 deletions
diff --git a/apps/theming/tests/Controller/ThemingControllerTest.php b/apps/theming/tests/Controller/ThemingControllerTest.php
index 5bc27069c6e..fb461f03a28 100644
--- a/apps/theming/tests/Controller/ThemingControllerTest.php
+++ b/apps/theming/tests/Controller/ThemingControllerTest.php
@@ -1,35 +1,9 @@
<?php
+
+declare(strict_types=1);
/**
- * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
- *
- * @author Bjoern Schiessle <bjoern@schiessle.org>
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @author Daniel Calviño Sánchez <danxuliu@gmail.com>
- * @author Joas Schilling <coding@schilljs.com>
- * @author John Molakvoæ <skjnldsv@protonmail.com>
- * @author Julius Haertl <jus@bitgrid.net>
- * @author Julius Härtl <jus@bitgrid.net>
- * @author Kyle Fazzari <kyrofa@ubuntu.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Michael Weimann <mail@michael-weimann.eu>
- * @author rakekniven <mark.ziegler@rakekniven.de>
- * @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 OCA\Theming\Tests\Controller;
@@ -40,54 +14,51 @@ use OCA\Theming\Service\ThemesService;
use OCA\Theming\ThemingDefaults;
use OCP\App\IAppManager;
use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\FileDisplayResponse;
+use OCP\AppFramework\Http\JSONResponse;
+use OCP\AppFramework\Http\NotFoundResponse;
+use OCP\AppFramework\Services\IAppConfig;
use OCP\AppFramework\Utility\ITimeFactory;
-use OCP\Files\IAppData;
use OCP\Files\NotFoundException;
use OCP\Files\SimpleFS\ISimpleFile;
use OCP\IConfig;
use OCP\IL10N;
+use OCP\INavigationManager;
use OCP\IRequest;
use OCP\ITempManager;
use OCP\IURLGenerator;
+use OCP\Server;
use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;
class ThemingControllerTest extends TestCase {
- /** @var IRequest|MockObject */
- private $request;
- /** @var IConfig|MockObject */
- private $config;
- /** @var ThemingDefaults|MockObject */
- private $themingDefaults;
- /** @var IL10N|MockObject */
- private $l10n;
- /** @var ThemingController */
- private $themingController;
- /** @var ITempManager */
- private $tempManager;
- /** @var IAppManager|MockObject */
- private $appManager;
- /** @var IAppData|MockObject */
- private $appData;
- /** @var ImageManager|MockObject */
- private $imageManager;
- /** @var IURLGenerator|MockObject */
- private $urlGenerator;
- /** @var ThemeService|MockObject */
- private $themesService;
+
+ private IRequest&MockObject $request;
+ private IConfig&MockObject $config;
+ private IAppConfig&MockObject $appConfig;
+ private ThemingDefaults&MockObject $themingDefaults;
+ private IL10N&MockObject $l10n;
+ private IAppManager&MockObject $appManager;
+ private ImageManager&MockObject $imageManager;
+ private IURLGenerator&MockObject $urlGenerator;
+ private ThemesService&MockObject $themesService;
+ private INavigationManager&MockObject $navigationManager;
+
+ private ThemingController $themingController;
protected function setUp(): void {
$this->request = $this->createMock(IRequest::class);
$this->config = $this->createMock(IConfig::class);
+ $this->appConfig = $this->createMock(IAppConfig::class);
$this->themingDefaults = $this->createMock(ThemingDefaults::class);
$this->l10n = $this->createMock(L10N::class);
- $this->appData = $this->createMock(IAppData::class);
$this->appManager = $this->createMock(IAppManager::class);
- $this->tempManager = \OC::$server->getTempManager();
$this->urlGenerator = $this->createMock(IURLGenerator::class);
$this->imageManager = $this->createMock(ImageManager::class);
$this->themesService = $this->createMock(ThemesService::class);
+ $this->navigationManager = $this->createMock(INavigationManager::class);
$timeFactory = $this->createMock(ITimeFactory::class);
$timeFactory->expects($this->any())
@@ -100,20 +71,20 @@ class ThemingControllerTest extends TestCase {
'theming',
$this->request,
$this->config,
+ $this->appConfig,
$this->themingDefaults,
$this->l10n,
- $this->tempManager,
- $this->appData,
$this->urlGenerator,
$this->appManager,
$this->imageManager,
$this->themesService,
+ $this->navigationManager,
);
parent::setUp();
}
- public function dataUpdateStylesheetSuccess() {
+ public static function dataUpdateStylesheetSuccess(): array {
return [
['name', str_repeat('a', 250), 'Saved'],
['url', 'https://nextcloud.com/' . str_repeat('a', 478), 'Saved'],
@@ -126,14 +97,8 @@ class ThemingControllerTest extends TestCase {
];
}
- /**
- * @dataProvider dataUpdateStylesheetSuccess
- *
- * @param string $setting
- * @param string $value
- * @param string $message
- */
- public function testUpdateStylesheetSuccess($setting, $value, $message) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataUpdateStylesheetSuccess')]
+ public function testUpdateStylesheetSuccess(string $setting, string $value, string $message): void {
$this->themingDefaults
->expects($this->once())
->method('set')
@@ -147,8 +112,8 @@ class ThemingControllerTest extends TestCase {
$expected = new DataResponse(
[
- 'data' =>
- [
+ 'data'
+ => [
'message' => $message,
],
'status' => 'success',
@@ -157,31 +122,39 @@ class ThemingControllerTest extends TestCase {
$this->assertEquals($expected, $this->themingController->updateStylesheet($setting, $value));
}
- public function dataUpdateStylesheetError() {
+ public static function dataUpdateStylesheetError(): array {
+ $urls = [
+ 'url' => 'web address',
+ 'imprintUrl' => 'legal notice address',
+ 'privacyUrl' => 'privacy policy address',
+ ];
+
+ $urlTests = [];
+ foreach ($urls as $urlKey => $urlName) {
+ // Check length limit
+ $urlTests[] = [$urlKey, 'http://example.com/' . str_repeat('a', 501), "The given {$urlName} is too long"];
+ // Check potential evil javascript
+ $urlTests[] = [$urlKey, 'javascript:alert(1)', "The given {$urlName} is not a valid URL"];
+ // Check XSS
+ $urlTests[] = [$urlKey, 'https://example.com/"><script/src="alert(\'1\')"><a/href/="', "The given {$urlName} is not a valid URL"];
+ }
+
return [
['name', str_repeat('a', 251), 'The given name is too long'],
- ['url', 'http://example.com/' . str_repeat('a', 501), 'The given web address is too long'],
- ['url', str_repeat('a', 501), 'The given web address is not a valid URL'],
- ['url', 'javascript:alert(1)', 'The given web address is not a valid URL'],
['slogan', str_repeat('a', 501), 'The given slogan is too long'],
- ['color', '0082C9', 'The given color is invalid'],
- ['color', '#0082Z9', 'The given color is invalid'],
- ['color', 'Nextcloud', 'The given color is invalid'],
- ['imprintUrl', '0082C9', 'The given legal notice address is not a valid URL'],
- ['imprintUrl', '0082C9', 'The given legal notice address is not a valid URL'],
- ['imprintUrl', 'javascript:foo', 'The given legal notice address is not a valid URL'],
- ['privacyUrl', '#0082Z9', 'The given privacy policy address is not a valid URL'],
+ ['primary_color', '0082C9', 'The given color is invalid'],
+ ['primary_color', '#0082Z9', 'The given color is invalid'],
+ ['primary_color', 'Nextcloud', 'The given color is invalid'],
+ ['background_color', '0082C9', 'The given color is invalid'],
+ ['background_color', '#0082Z9', 'The given color is invalid'],
+ ['background_color', 'Nextcloud', 'The given color is invalid'],
+
+ ...$urlTests,
];
}
- /**
- * @dataProvider dataUpdateStylesheetError
- *
- * @param string $setting
- * @param string $value
- * @param string $message
- */
- public function testUpdateStylesheetError($setting, $value, $message) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataUpdateStylesheetError')]
+ public function testUpdateStylesheetError(string $setting, string $value, string $message): void {
$this->themingDefaults
->expects($this->never())
->method('set')
@@ -195,8 +168,8 @@ class ThemingControllerTest extends TestCase {
$expected = new DataResponse(
[
- 'data' =>
- [
+ 'data'
+ => [
'message' => $message,
],
'status' => 'error',
@@ -206,7 +179,7 @@ class ThemingControllerTest extends TestCase {
$this->assertEquals($expected, $this->themingController->updateStylesheet($setting, $value));
}
- public function testUpdateLogoNoData() {
+ public function testUpdateLogoNoData(): void {
$this->request
->expects($this->once())
->method('getParam')
@@ -226,8 +199,8 @@ class ThemingControllerTest extends TestCase {
$expected = new DataResponse(
[
- 'data' =>
- [
+ 'data'
+ => [
'message' => 'No file uploaded',
],
'status' => 'failure',
@@ -238,7 +211,7 @@ class ThemingControllerTest extends TestCase {
$this->assertEquals($expected, $this->themingController->uploadImage());
}
- public function testUploadInvalidUploadKey() {
+ public function testUploadInvalidUploadKey(): void {
$this->request
->expects($this->once())
->method('getParam')
@@ -256,8 +229,8 @@ class ThemingControllerTest extends TestCase {
$expected = new DataResponse(
[
- 'data' =>
- [
+ 'data'
+ => [
'message' => 'Invalid key',
],
'status' => 'failure',
@@ -271,11 +244,8 @@ class ThemingControllerTest extends TestCase {
/**
* Checks that trying to upload an SVG favicon without imagemagick
* results in an unsupported media type response.
- *
- * @test
- * @return void
*/
- public function testUploadSVGFaviconWithoutImagemagick() {
+ public function testUploadSVGFaviconWithoutImagemagick(): void {
$this->imageManager
->method('shouldReplaceIcons')
->willReturn(false);
@@ -290,7 +260,7 @@ class ThemingControllerTest extends TestCase {
->method('getUploadedFile')
->with('image')
->willReturn([
- 'tmp_name' => __DIR__ . '/../../../../tests/data/testimagelarge.svg',
+ 'tmp_name' => __DIR__ . '/../../../../tests/data/testimagelarge.svg',
'type' => 'image/svg',
'name' => 'testimagelarge.svg',
'error' => 0,
@@ -308,8 +278,8 @@ class ThemingControllerTest extends TestCase {
$expected = new DataResponse(
[
- 'data' =>
- [
+ 'data'
+ => [
'message' => 'Unsupported image type',
],
'status' => 'failure'
@@ -320,7 +290,7 @@ class ThemingControllerTest extends TestCase {
$this->assertEquals($expected, $this->themingController->uploadImage());
}
- public function testUpdateLogoInvalidMimeType() {
+ public function testUpdateLogoInvalidMimeType(): void {
$this->request
->expects($this->once())
->method('getParam')
@@ -331,7 +301,7 @@ class ThemingControllerTest extends TestCase {
->method('getUploadedFile')
->with('image')
->willReturn([
- 'tmp_name' => __DIR__ . '/../../../../tests/data/lorem.txt',
+ 'tmp_name' => __DIR__ . '/../../../../tests/data/lorem.txt',
'type' => 'application/pdf',
'name' => 'logo.pdf',
'error' => 0,
@@ -349,8 +319,8 @@ class ThemingControllerTest extends TestCase {
$expected = new DataResponse(
[
- 'data' =>
- [
+ 'data'
+ => [
'message' => 'Unsupported image type',
],
'status' => 'failure'
@@ -361,7 +331,7 @@ class ThemingControllerTest extends TestCase {
$this->assertEquals($expected, $this->themingController->uploadImage());
}
- public function dataUpdateImages() {
+ public static function dataUpdateImages(): array {
return [
['image/jpeg', false],
['image/jpeg', true],
@@ -372,10 +342,10 @@ class ThemingControllerTest extends TestCase {
];
}
- /** @dataProvider dataUpdateImages */
- public function testUpdateLogoNormalLogoUpload($mimeType, $folderExists = true) {
- $tmpLogo = \OC::$server->getTempManager()->getTemporaryFolder() . '/logo.svg';
- $destination = \OC::$server->getTempManager()->getTemporaryFolder();
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataUpdateImages')]
+ public function testUpdateLogoNormalLogoUpload(string $mimeType, bool $folderExists = true): void {
+ $tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder() . '/logo.svg';
+ $destination = Server::get(ITempManager::class)->getTemporaryFolder();
touch($tmpLogo);
copy(__DIR__ . '/../../../../tests/data/testimage.png', $tmpLogo);
@@ -411,8 +381,8 @@ class ThemingControllerTest extends TestCase {
$expected = new DataResponse(
[
- 'data' =>
- [
+ 'data'
+ => [
'name' => 'logo.svg',
'message' => 'Saved',
'url' => 'imageUrl',
@@ -424,9 +394,8 @@ class ThemingControllerTest extends TestCase {
$this->assertEquals($expected, $this->themingController->uploadImage());
}
- /** @dataProvider dataUpdateImages */
- public function testUpdateLogoLoginScreenUpload($folderExists) {
- $tmpLogo = \OC::$server->getTempManager()->getTemporaryFolder() . 'logo.png';
+ public function testUpdateLogoLoginScreenUpload(): void {
+ $tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder() . 'logo.png';
touch($tmpLogo);
copy(__DIR__ . '/../../../../tests/data/desktopapp.png', $tmpLogo);
@@ -461,8 +430,8 @@ class ThemingControllerTest extends TestCase {
->willReturn('imageUrl');
$expected = new DataResponse(
[
- 'data' =>
- [
+ 'data'
+ => [
'name' => 'logo.svg',
'message' => 'Saved',
'url' => 'imageUrl',
@@ -473,11 +442,11 @@ class ThemingControllerTest extends TestCase {
$this->assertEquals($expected, $this->themingController->uploadImage());
}
- public function testUpdateLogoLoginScreenUploadWithInvalidImage() {
- $tmpLogo = \OC::$server->getTempManager()->getTemporaryFolder() . '/logo.svg';
+ public function testUpdateLogoLoginScreenUploadWithInvalidImage(): void {
+ $tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder() . '/logo.svg';
touch($tmpLogo);
- file_put_contents($tmpLogo, file_get_contents(__DIR__ . '/../../../../tests/data/data.zip'));
+ file_put_contents($tmpLogo, file_get_contents(__DIR__ . '/../../../../tests/data/data.zip'));
$this->request
->expects($this->once())
->method('getParam')
@@ -506,8 +475,8 @@ class ThemingControllerTest extends TestCase {
$expected = new DataResponse(
[
- 'data' =>
- [
+ 'data'
+ => [
'message' => 'Unsupported image type',
],
'status' => 'failure'
@@ -517,7 +486,7 @@ class ThemingControllerTest extends TestCase {
$this->assertEquals($expected, $this->themingController->uploadImage());
}
- public function dataPhpUploadErrors() {
+ public static function dataPhpUploadErrors(): array {
return [
[UPLOAD_ERR_INI_SIZE, 'The uploaded file exceeds the upload_max_filesize directive in php.ini'],
[UPLOAD_ERR_FORM_SIZE, 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'],
@@ -529,10 +498,8 @@ class ThemingControllerTest extends TestCase {
];
}
- /**
- * @dataProvider dataPhpUploadErrors
- */
- public function testUpdateLogoLoginScreenUploadWithInvalidImageUpload($error, $expectedErrorMessage) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataPhpUploadErrors')]
+ public function testUpdateLogoLoginScreenUploadWithInvalidImageUpload(int $error, string $expectedErrorMessage): void {
$this->request
->expects($this->once())
->method('getParam')
@@ -557,8 +524,8 @@ class ThemingControllerTest extends TestCase {
$expected = new DataResponse(
[
- 'data' =>
- [
+ 'data'
+ => [
'message' => $expectedErrorMessage,
],
'status' => 'failure'
@@ -568,10 +535,8 @@ class ThemingControllerTest extends TestCase {
$this->assertEquals($expected, $this->themingController->uploadImage());
}
- /**
- * @dataProvider dataPhpUploadErrors
- */
- public function testUpdateLogoUploadWithInvalidImageUpload($error, $expectedErrorMessage) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataPhpUploadErrors')]
+ public function testUpdateLogoUploadWithInvalidImageUpload($error, $expectedErrorMessage): void {
$this->request
->expects($this->once())
->method('getParam')
@@ -596,8 +561,8 @@ class ThemingControllerTest extends TestCase {
$expected = new DataResponse(
[
- 'data' =>
- [
+ 'data'
+ => [
'message' => $expectedErrorMessage
],
'status' => 'failure'
@@ -607,7 +572,7 @@ class ThemingControllerTest extends TestCase {
$this->assertEquals($expected, $this->themingController->uploadImage());
}
- public function testUndo() {
+ public function testUndo(): void {
$this->l10n
->expects($this->once())
->method('t')
@@ -621,8 +586,8 @@ class ThemingControllerTest extends TestCase {
$expected = new DataResponse(
[
- 'data' =>
- [
+ 'data'
+ => [
'value' => 'MyValue',
'message' => 'Saved'
],
@@ -632,15 +597,15 @@ class ThemingControllerTest extends TestCase {
$this->assertEquals($expected, $this->themingController->undo('MySetting'));
}
- public function dataUndoDelete() {
+ public static function dataUndoDelete(): array {
return [
[ 'backgroundMime', 'background' ],
[ 'logoMime', 'logo' ]
];
}
- /** @dataProvider dataUndoDelete */
- public function testUndoDelete($value, $filename) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataUndoDelete')]
+ public function testUndoDelete(string $value, string $filename): void {
$this->l10n
->expects($this->once())
->method('t')
@@ -654,8 +619,8 @@ class ThemingControllerTest extends TestCase {
$expected = new DataResponse(
[
- 'data' =>
- [
+ 'data'
+ => [
'value' => $value,
'message' => 'Saved',
],
@@ -667,16 +632,16 @@ class ThemingControllerTest extends TestCase {
- public function testGetLogoNotExistent() {
+ public function testGetLogoNotExistent(): void {
$this->imageManager->method('getImage')
->with($this->equalTo('logo'))
->willThrowException(new NotFoundException());
- $expected = new Http\NotFoundResponse();
+ $expected = new NotFoundResponse();
$this->assertEquals($expected, $this->themingController->getImage('logo'));
}
- public function testGetLogo() {
+ public function testGetLogo(): void {
$file = $this->createMock(ISimpleFile::class);
$file->method('getName')->willReturn('logo.svg');
$file->method('getMTime')->willReturn(42);
@@ -689,26 +654,26 @@ class ThemingControllerTest extends TestCase {
->with('theming', 'logoMime', '')
->willReturn('text/svg');
- @$expected = new Http\FileDisplayResponse($file);
+ @$expected = new FileDisplayResponse($file);
$expected->cacheFor(3600);
$expected->addHeader('Content-Type', 'text/svg');
$expected->addHeader('Content-Disposition', 'attachment; filename="logo"');
- $csp = new Http\ContentSecurityPolicy();
+ $csp = new ContentSecurityPolicy();
$csp->allowInlineStyle();
$expected->setContentSecurityPolicy($csp);
@$this->assertEquals($expected, $this->themingController->getImage('logo'));
}
- public function testGetLoginBackgroundNotExistent() {
+ public function testGetLoginBackgroundNotExistent(): void {
$this->imageManager->method('getImage')
->with($this->equalTo('background'))
->willThrowException(new NotFoundException());
- $expected = new Http\NotFoundResponse();
+ $expected = new NotFoundResponse();
$this->assertEquals($expected, $this->themingController->getImage('background'));
}
- public function testGetLoginBackground() {
+ public function testGetLoginBackground(): void {
$file = $this->createMock(ISimpleFile::class);
$file->method('getName')->willReturn('background.png');
$file->method('getMTime')->willReturn(42);
@@ -722,17 +687,25 @@ class ThemingControllerTest extends TestCase {
->with('theming', 'backgroundMime', '')
->willReturn('image/png');
- @$expected = new Http\FileDisplayResponse($file);
+ @$expected = new FileDisplayResponse($file);
$expected->cacheFor(3600);
$expected->addHeader('Content-Type', 'image/png');
$expected->addHeader('Content-Disposition', 'attachment; filename="background"');
- $csp = new Http\ContentSecurityPolicy();
+ $csp = new ContentSecurityPolicy();
$csp->allowInlineStyle();
$expected->setContentSecurityPolicy($csp);
@$this->assertEquals($expected, $this->themingController->getImage('background'));
}
- public function testGetManifest() {
+ public static function dataGetManifest(): array {
+ return [
+ [true],
+ [false],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataGetManifest')]
+ public function testGetManifest(bool $standalone): void {
$this->config
->expects($this->once())
->method('getAppValue')
@@ -749,18 +722,20 @@ class ThemingControllerTest extends TestCase {
$this->urlGenerator
->expects($this->exactly(2))
->method('linkToRoute')
- ->withConsecutive(
- ['theming.Icon.getTouchIcon', ['app' => 'core']],
- ['theming.Icon.getFavicon', ['app' => 'core']],
- )->willReturnOnConsecutiveCalls(
- 'touchicon',
- 'favicon',
- );
- $response = new Http\JSONResponse([
+ ->willReturnMap([
+ ['theming.Icon.getTouchIcon', ['app' => 'core'], 'touchicon'],
+ ['theming.Icon.getFavicon', ['app' => 'core'], 'favicon'],
+ ]);
+ $this->config
+ ->expects($this->exactly(2))
+ ->method('getSystemValueBool')
+ ->with('theming.standalone_window.enabled', true)
+ ->willReturn($standalone);
+ $response = new JSONResponse([
'name' => 'Nextcloud',
'start_url' => 'localhost',
- 'icons' =>
- [
+ 'icons'
+ => [
[
'src' => 'touchicon?v=0',
'type' => 'image/png',
@@ -772,7 +747,8 @@ class ThemingControllerTest extends TestCase {
'sizes' => '16x16'
]
],
- 'display' => 'standalone',
+ 'display_override' => [$standalone ? 'minimal-ui' : ''],
+ 'display' => $standalone ? 'standalone' : 'browser',
'short_name' => 'Nextcloud',
'theme_color' => null,
'background_color' => null,