Signed-off-by: Julius Haertl <jus@bitgrid.net>tags/v11.0RC2
@@ -23,13 +23,16 @@ | |||
namespace OCA\Theming\Controller; | |||
use OCA\Theming\IconBuilder; | |||
use OCA\Theming\ImageManager; | |||
use OCA\Theming\ThemingDefaults; | |||
use OCP\AppFramework\Controller; | |||
use OCP\AppFramework\Http; | |||
use OCP\AppFramework\Http\DataDisplayResponse; | |||
use OCP\AppFramework\Http\FileDisplayResponse; | |||
use OCP\AppFramework\Utility\ITimeFactory; | |||
use OCP\IRequest; | |||
use OCA\Theming\Util; | |||
use OCP\IConfig; | |||
class IconController extends Controller { | |||
/** @var ThemingDefaults */ | |||
@@ -38,8 +41,12 @@ class IconController extends Controller { | |||
private $util; | |||
/** @var ITimeFactory */ | |||
private $timeFactory; | |||
/** @var IConfig */ | |||
private $config; | |||
/** @var IconBuilder */ | |||
private $iconBuilder; | |||
/** @var ImageManager */ | |||
private $imageManager; | |||
/** | |||
* IconController constructor. | |||
@@ -49,7 +56,9 @@ class IconController extends Controller { | |||
* @param ThemingDefaults $themingDefaults | |||
* @param Util $util | |||
* @param ITimeFactory $timeFactory | |||
* @param IConfig $config | |||
* @param IconBuilder $iconBuilder | |||
* @param ImageManager $imageManager | |||
*/ | |||
public function __construct( | |||
$appName, | |||
@@ -57,14 +66,18 @@ class IconController extends Controller { | |||
ThemingDefaults $themingDefaults, | |||
Util $util, | |||
ITimeFactory $timeFactory, | |||
IconBuilder $iconBuilder | |||
IConfig $config, | |||
IconBuilder $iconBuilder, | |||
ImageManager $imageManager | |||
) { | |||
parent::__construct($appName, $request); | |||
$this->themingDefaults = $themingDefaults; | |||
$this->util = $util; | |||
$this->timeFactory = $timeFactory; | |||
$this->config = $config; | |||
$this->iconBuilder = $iconBuilder; | |||
$this->imageManager = $imageManager; | |||
} | |||
/** | |||
@@ -73,14 +86,15 @@ class IconController extends Controller { | |||
* | |||
* @param $app string app name | |||
* @param $image string image file name (svg required) | |||
* @return DataDisplayResponse | |||
* @return FileDisplayResponse | |||
*/ | |||
public function getThemedIcon($app, $image) { | |||
$image = $this->util->getAppImage($app, $image); | |||
$svg = file_get_contents($image); | |||
$color = $this->util->elementColor($this->themingDefaults->getMailHeaderColor()); | |||
$svg = $this->util->colorizeSvg($svg, $color); | |||
$response = new DataDisplayResponse($svg, Http::STATUS_OK, ['Content-Type' => 'image/svg+xml']); | |||
$iconFile = $this->imageManager->getCachedImage("icon-" . $app . '-' . str_replace("/","_",$image)); | |||
if ($iconFile === null) { | |||
$icon = $this->iconBuilder->colorSvg($app, $image); | |||
$iconFile = $this->imageManager->setCachedImage("icon-" . $app . '-' . str_replace("/","_",$image), $icon); | |||
} | |||
$response = new FileDisplayResponse($iconFile, Http::STATUS_OK, ['Content-Type' => 'image/svg+xml']); | |||
$response->cacheFor(86400); | |||
$response->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime())); | |||
$response->addHeader('Pragma', 'cache'); | |||
@@ -94,12 +108,16 @@ class IconController extends Controller { | |||
* @NoCSRFRequired | |||
* | |||
* @param $app string app name | |||
* @return DataDisplayResponse | |||
* @return FileDisplayResponse|DataDisplayResponse | |||
*/ | |||
public function getFavicon($app="core") { | |||
if($this->themingDefaults->shouldReplaceIcons()) { | |||
public function getFavicon($app = "core") { | |||
$iconFile = $this->imageManager->getCachedImage('favIcon-' . $app); | |||
if($iconFile === null && $this->themingDefaults->shouldReplaceIcons()) { | |||
$icon = $this->iconBuilder->getFavicon($app); | |||
$response = new DataDisplayResponse($icon, Http::STATUS_OK, ['Content-Type' => 'image/x-icon']); | |||
$iconFile = $this->imageManager->setCachedImage('favIcon-' . $app, $icon); | |||
} | |||
if ($this->themingDefaults->shouldReplaceIcons()) { | |||
$response = new FileDisplayResponse($iconFile, Http::STATUS_OK, ['Content-Type' => 'image/x-icon']); | |||
} else { | |||
$response = new DataDisplayResponse(null, Http::STATUS_NOT_FOUND); | |||
} | |||
@@ -116,12 +134,16 @@ class IconController extends Controller { | |||
* @NoCSRFRequired | |||
* | |||
* @param $app string app name | |||
* @return DataDisplayResponse | |||
* @return FileDisplayResponse|DataDisplayResponse | |||
*/ | |||
public function getTouchIcon($app="core") { | |||
if($this->themingDefaults->shouldReplaceIcons()) { | |||
public function getTouchIcon($app = "core") { | |||
$iconFile = $this->imageManager->getCachedImage('touchIcon-' . $app); | |||
if ($iconFile === null && $this->themingDefaults->shouldReplaceIcons()) { | |||
$icon = $this->iconBuilder->getTouchIcon($app); | |||
$response = new DataDisplayResponse($icon, Http::STATUS_OK, ['Content-Type' => 'image/png']); | |||
$iconFile = $this->imageManager->setCachedImage('touchIcon-' . $app, $icon); | |||
} | |||
if ($this->themingDefaults->shouldReplaceIcons()) { | |||
$response = new FileDisplayResponse($iconFile, Http::STATUS_OK, ['Content-Type' => 'image/png']); | |||
} else { | |||
$response = new DataDisplayResponse(null, Http::STATUS_NOT_FOUND); | |||
} | |||
@@ -130,5 +152,4 @@ class IconController extends Controller { | |||
$response->addHeader('Pragma', 'cache'); | |||
return $response; | |||
} | |||
} |
@@ -80,19 +80,21 @@ class IconBuilder { | |||
*/ | |||
public function renderAppIcon($app) { | |||
$appIcon = $this->util->getAppIcon($app); | |||
$appIconContent = file_get_contents($appIcon); | |||
$color = $this->themingDefaults->getMailHeaderColor(); | |||
$mime = mime_content_type($appIcon); | |||
// generate background image with rounded corners | |||
$background = '<?xml version="1.0" encoding="UTF-8"?>' . | |||
'<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:cc="http://creativecommons.org/ns#" width="512" height="512" xmlns:xlink="http://www.w3.org/1999/xlink">' . | |||
'<rect x="0" y="0" rx="75" ry="75" width="512" height="512" style="fill:' . $color . ';" />' . | |||
'</svg>'; | |||
// resize svg magic as this seems broken in Imagemagick | |||
if($mime === "image/svg+xml") { | |||
$svg = file_get_contents($appIcon); | |||
if($mime === "image/svg+xml" || substr($appIconContent, 0, 4) === "<svg") { | |||
if(substr($appIconContent, 0, 5) !== "<?xml") { | |||
$svg = "<?xml version=\"1.0\"?>".$appIconContent; | |||
} | |||
$tmp = new Imagick(); | |||
$tmp->readImageBlob($svg); | |||
$x = $tmp->getImageWidth(); | |||
@@ -137,4 +139,12 @@ class IconBuilder { | |||
return $finalIconFile; | |||
} | |||
public function colorSvg($app, $image) { | |||
$imageFile = $this->util->getAppImage($app, $image); | |||
$svg = file_get_contents($imageFile); | |||
$color = $this->util->elementColor($this->themingDefaults->getMailHeaderColor()); | |||
$svg = $this->util->colorizeSvg($svg, $color); | |||
return $svg; | |||
} | |||
} |
@@ -0,0 +1,118 @@ | |||
<?php | |||
/** | |||
* @copyright Copyright (c) 2016 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/>. | |||
* | |||
*/ | |||
namespace OCA\Theming; | |||
use OCP\IConfig; | |||
use OCP\Files\IAppData; | |||
use OCP\Files\NotFoundException; | |||
use OCP\Files\NotPermittedException; | |||
class ImageManager { | |||
/** @var IConfig */ | |||
private $config; | |||
/** @var IAppData */ | |||
private $appData; | |||
/** | |||
* ImageManager constructor. | |||
* | |||
* @param IConfig $config | |||
* @param IAppData $appData | |||
*/ | |||
public function __construct(IConfig $config, | |||
IAppData $appData | |||
) { | |||
$this->config = $config; | |||
$this->appData = $appData; | |||
} | |||
/** | |||
* Get folder for current theming files | |||
* | |||
* @return \OCP\Files\SimpleFS\ISimpleFolder | |||
* @throws NotPermittedException | |||
* @throws \RuntimeException | |||
*/ | |||
public function getCacheFolder() { | |||
$cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0'); | |||
try { | |||
$folder = $this->appData->getFolder($cacheBusterValue); | |||
} catch (NotFoundException $e) { | |||
$folder = $this->appData->newFolder($cacheBusterValue); | |||
$this->cleanup(); | |||
} | |||
return $folder; | |||
} | |||
/** | |||
* Get a file from AppData | |||
* | |||
* @param string $filename | |||
* @return null|\OCP\Files\SimpleFS\ISimpleFile | |||
*/ | |||
public function getCachedImage($filename) { | |||
$currentFolder = $this->getCacheFolder(); | |||
if($currentFolder->fileExists($filename)) { | |||
return $currentFolder->getFile($filename); | |||
} else { | |||
return null; | |||
} | |||
} | |||
/** | |||
* Store a file for theming in AppData | |||
* | |||
* @param string $filename | |||
* @param string $data | |||
* @return \OCP\Files\SimpleFS\ISimpleFile | |||
*/ | |||
public function setCachedImage($filename, $data) { | |||
$currentFolder = $this->getCacheFolder(); | |||
if ($currentFolder->fileExists($filename)) { | |||
$file = $currentFolder->getFile($filename); | |||
} else { | |||
$file = $currentFolder->newFile($filename); | |||
} | |||
$file->putContent($data); | |||
return $file; | |||
} | |||
/** | |||
* remove cached files that are not required any longer | |||
*/ | |||
public function cleanup() { | |||
$currentFolder = $this->getCacheFolder(); | |||
$folders = $this->appData->getDirectoryListing(); | |||
foreach ($folders as $folder) { | |||
if ($folder->getName() !== $currentFolder->getName()) { | |||
$folder->delete(); | |||
} | |||
} | |||
} | |||
} |
@@ -23,12 +23,18 @@ | |||
namespace OCA\Theming\Tests\Controller; | |||
use OC\Files\SimpleFS\SimpleFile; | |||
use OCA\Theming\ImageManager; | |||
use OCP\AppFramework\Http; | |||
use OCP\AppFramework\Http\DataDisplayResponse; | |||
use OCP\Files\IRootFolder; | |||
use OCP\IConfig; | |||
use OCP\IL10N; | |||
use OCP\IRequest; | |||
use Test\TestCase; | |||
use OCA\Theming\Util; | |||
use OCA\Theming\Controller\IconController; | |||
use OCP\AppFramework\Http\FileDisplayResponse; | |||
class IconControllerTest extends TestCase { | |||
@@ -42,8 +48,12 @@ class IconControllerTest extends TestCase { | |||
private $timeFactory; | |||
/** @var IL10N|\PHPUnit_Framework_MockObject_MockObject */ | |||
private $iconController; | |||
/** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ | |||
private $config; | |||
/** @var IRootFolder|\PHPUnit_Framework_MockObject_MockObject */ | |||
private $iconBuilder; | |||
/** @var ImageManager */ | |||
private $imageManager; | |||
public function setUp() { | |||
$this->request = $this->getMockBuilder('OCP\IRequest')->getMock(); | |||
@@ -54,9 +64,10 @@ class IconControllerTest extends TestCase { | |||
$this->timeFactory = $this->getMockBuilder('OCP\AppFramework\Utility\ITimeFactory') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$this->config = $this->getMockBuilder('OCP\IConfig')->getMock(); | |||
$this->iconBuilder = $this->getMockBuilder('OCA\Theming\IconBuilder') | |||
->disableOriginalConstructor()->getMock(); | |||
$this->imageManager = $this->getMockBuilder('OCA\Theming\ImageManager')->disableOriginalConstructor()->getMock(); | |||
$this->timeFactory->expects($this->any()) | |||
->method('getTime') | |||
->willReturn(123); | |||
@@ -67,124 +78,114 @@ class IconControllerTest extends TestCase { | |||
$this->themingDefaults, | |||
$this->util, | |||
$this->timeFactory, | |||
$this->iconBuilder | |||
$this->config, | |||
$this->iconBuilder, | |||
$this->imageManager | |||
); | |||
parent::setUp(); | |||
} | |||
private function iconFileMock($filename, $data) { | |||
$icon = $this->getMockBuilder('OCP\Files\File')->getMock(); | |||
$icon->expects($this->any())->method('getContent')->willReturn($data); | |||
$icon->expects($this->any())->method('getMimeType')->willReturn('image type'); | |||
$icon->expects($this->any())->method('getEtag')->willReturn('my etag'); | |||
$icon->method('getName')->willReturn($filename); | |||
return new SimpleFile($icon); | |||
} | |||
public function testGetThemedIcon() { | |||
$this->util->expects($this->once()) | |||
->method('getAppImage') | |||
->with('core','filetypes/folder.svg') | |||
->willReturn(\OC::$SERVERROOT . "/core/img/filetypes/folder.svg"); | |||
$this->themingDefaults | |||
->expects($this->once()) | |||
->method('getMailHeaderColor') | |||
->willReturn('#000000'); | |||
$this->util | |||
->expects($this->once()) | |||
->method('elementColor') | |||
->willReturn('#000000'); | |||
$svg = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?> | |||
<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"16\" width=\"16\" version=\"1.0\"> | |||
<g fill-rule=\"evenodd\" transform=\"matrix(.86667 0 0 .86667 -172.05 -864.43)\" fill=\"#000000\"> | |||
<path d=\"m200.2 999.72c-0.28913 0-0.53125 0.2421-0.53125 0.53117v12.784c0 0.2985 0.23264 0.5312 0.53125 0.5312h15.091c0.2986 0 0.53124-0.2327 0.53124-0.5312l0.0004-10.474c0-0.2889-0.24211-0.5338-0.53124-0.5338l-7.5457 0.0005-2.3076-2.3078z\" fill-rule=\"evenodd\" fill=\"#000000\"/> | |||
</g> | |||
</svg> | |||
"; | |||
$expected = new DataDisplayResponse($svg, Http::STATUS_OK, ['Content-Type' => 'image/svg+xml']); | |||
$file = $this->iconFileMock('icon-core-filetypes_folder.svg', 'filecontent'); | |||
$this->imageManager->expects($this->once()) | |||
->method('getCachedImage') | |||
->with('icon-core-filetypes_folder.svg') | |||
->willReturn($file); | |||
$expected = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'image/svg+xml']); | |||
$expected->cacheFor(86400); | |||
$expected->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime())); | |||
$expected->addHeader('Pragma', 'cache'); | |||
@$this->assertEquals($expected, $this->iconController->getThemedIcon('core','filetypes/folder.svg')); | |||
@$this->assertEquals($expected, $this->iconController->getThemedIcon('core', 'filetypes/folder.svg')); | |||
} | |||
public function testGetFaviconDefault() { | |||
if(!extension_loaded('imagick')) { | |||
if (!extension_loaded('imagick')) { | |||
$this->markTestSkipped('Imagemagick is required for dynamic icon generation.'); | |||
} | |||
$checkImagick = new \Imagick(); | |||
if (count($checkImagick->queryFormats('SVG')) < 1) { | |||
$this->markTestSkipped('No SVG provider present.'); | |||
} | |||
$this->themingDefaults->expects($this->once()) | |||
$this->themingDefaults->expects($this->any()) | |||
->method('shouldReplaceIcons') | |||
->willReturn(true); | |||
$expectedIcon = new \Imagick(realpath(dirname(__FILE__)) . '/../data/favicon-original.ico'); | |||
$this->iconBuilder->expects($this->once()) | |||
->method('getFavicon') | |||
->with('core') | |||
->willReturn($expectedIcon); | |||
$favicon = $this->iconController->getFavicon(); | |||
->willReturn('filecontent'); | |||
$file = $this->iconFileMock('filename', 'filecontent'); | |||
$this->imageManager->expects($this->once()) | |||
->method('setCachedImage') | |||
->willReturn($file); | |||
$expected = new DataDisplayResponse($expectedIcon, Http::STATUS_OK, ['Content-Type' => 'image/x-icon']); | |||
$expected = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'image/x-icon']); | |||
$expected->cacheFor(86400); | |||
$expected->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime())); | |||
$expected->addHeader('Pragma', 'cache'); | |||
$this->assertEquals($expected, $favicon); | |||
$this->assertEquals($expected, $this->iconController->getFavicon()); | |||
} | |||
public function testGetFaviconFail() { | |||
$this->themingDefaults->expects($this->any()) | |||
->method('shouldReplaceIcons') | |||
->willReturn(false); | |||
$expected = new DataDisplayResponse(null, Http::STATUS_NOT_FOUND); | |||
$expected->cacheFor(86400); | |||
$expected->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime())); | |||
$expected->addHeader('Pragma', 'cache'); | |||
$this->assertEquals($expected, $this->iconController->getFavicon()); | |||
} | |||
public function testGetTouchIconDefault() { | |||
if(!extension_loaded('imagick')) { | |||
if (!extension_loaded('imagick')) { | |||
$this->markTestSkipped('Imagemagick is required for dynamic icon generation.'); | |||
} | |||
$checkImagick = new \Imagick(); | |||
if (count($checkImagick->queryFormats('SVG')) < 1) { | |||
$this->markTestSkipped('No SVG provider present.'); | |||
} | |||
$this->themingDefaults->expects($this->once()) | |||
$this->themingDefaults->expects($this->any()) | |||
->method('shouldReplaceIcons') | |||
->willReturn(true); | |||
$expectedIcon = new \Imagick(realpath(dirname(__FILE__)) . '/../data/touch-original.png'); | |||
$this->iconBuilder->expects($this->once()) | |||
->method('getTouchIcon') | |||
->with('core') | |||
->willReturn($expectedIcon); | |||
$favicon = $this->iconController->getTouchIcon(); | |||
->willReturn('filecontent'); | |||
$file = $this->iconFileMock('filename', 'filecontent'); | |||
$this->imageManager->expects($this->once()) | |||
->method('setCachedImage') | |||
->willReturn($file); | |||
$expected = new DataDisplayResponse($expectedIcon, Http::STATUS_OK, ['Content-Type' => 'image/png']); | |||
$expected = new FileDisplayResponse($file, Http::STATUS_OK, ['Content-Type' => 'image/png']); | |||
$expected->cacheFor(86400); | |||
$expected->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime())); | |||
$expected->addHeader('Pragma', 'cache'); | |||
$this->assertEquals($expected, $favicon); | |||
$this->assertEquals($expected, $this->iconController->getTouchIcon()); | |||
} | |||
public function testGetFaviconFail() { | |||
if(!extension_loaded('imagick')) { | |||
$this->markTestSkipped('Imagemagick is required for dynamic icon generation.'); | |||
} | |||
$checkImagick = new \Imagick(); | |||
if (count($checkImagick->queryFormats('SVG')) < 1) { | |||
$this->markTestSkipped('No SVG provider present.'); | |||
} | |||
$this->themingDefaults->expects($this->once()) | |||
->method('shouldReplaceIcons') | |||
->willReturn(false); | |||
$favicon = $this->iconController->getFavicon(); | |||
$expected = new DataDisplayResponse(null, Http::STATUS_NOT_FOUND); | |||
$expected->cacheFor(86400); | |||
$expected->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime())); | |||
$expected->addHeader('Pragma', 'cache'); | |||
$this->assertEquals($expected, $favicon); | |||
} | |||
public function testGetTouchIconFail() { | |||
if(!extension_loaded('imagick')) { | |||
$this->markTestSkipped('Imagemagick is required for dynamic icon generation.'); | |||
} | |||
$checkImagick = new \Imagick(); | |||
if (count($checkImagick->queryFormats('SVG')) < 1) { | |||
$this->markTestSkipped('No SVG provider present.'); | |||
} | |||
$this->themingDefaults->expects($this->once()) | |||
$this->themingDefaults->expects($this->any()) | |||
->method('shouldReplaceIcons') | |||
->willReturn(false); | |||
$favicon = $this->iconController->getTouchIcon(); | |||
$expected = new DataDisplayResponse(null, Http::STATUS_NOT_FOUND); | |||
$expected->cacheFor(86400); | |||
$expected->addHeader('Expires', date(\DateTime::RFC2822, $this->timeFactory->getTime())); | |||
$expected->addHeader('Pragma', 'cache'); | |||
$this->assertEquals($expected, $favicon); | |||
$this->assertEquals($expected, $this->iconController->getTouchIcon()); | |||
} | |||
} |
@@ -45,6 +45,15 @@ class IconBuilderTest extends TestCase { | |||
protected function setUp() { | |||
parent::setUp(); | |||
$this->config = $this->getMockBuilder('\OCP\IConfig')->getMock(); | |||
$this->rootFolder = $this->getMockBuilder('OCP\Files\IRootFolder')->getMock(); | |||
$this->themingDefaults = $this->getMockBuilder('OCA\Theming\ThemingDefaults') | |||
->disableOriginalConstructor()->getMock(); | |||
$this->util = new Util($this->config, $this->rootFolder); | |||
$this->iconBuilder = new IconBuilder($this->themingDefaults, $this->util); | |||
} | |||
private function checkImagick() { | |||
if(!extension_loaded('imagick')) { | |||
$this->markTestSkipped('Imagemagick is required for dynamic icon generation.'); | |||
} | |||
@@ -52,13 +61,6 @@ class IconBuilderTest extends TestCase { | |||
if (count($checkImagick->queryFormats('SVG')) < 1) { | |||
$this->markTestSkipped('No SVG provider present.'); | |||
} | |||
$this->config = $this->getMockBuilder('\OCP\IConfig')->getMock(); | |||
$this->rootFolder = $this->getMockBuilder('OCP\Files\IRootFolder')->getMock(); | |||
$this->themingDefaults = $this->getMockBuilder('OCA\Theming\ThemingDefaults') | |||
->disableOriginalConstructor()->getMock(); | |||
$this->util = new Util($this->config, $this->rootFolder); | |||
$this->iconBuilder = new IconBuilder($this->themingDefaults, $this->util); | |||
} | |||
public function dataRenderAppIcon() { | |||
@@ -78,6 +80,7 @@ class IconBuilderTest extends TestCase { | |||
* @param $file | |||
*/ | |||
public function testRenderAppIcon($app, $color, $file) { | |||
$this->checkImagick(); | |||
$this->themingDefaults->expects($this->once()) | |||
->method('getMailHeaderColor') | |||
->willReturn($color); | |||
@@ -102,6 +105,7 @@ class IconBuilderTest extends TestCase { | |||
* @param $file | |||
*/ | |||
public function testGetTouchIcon($app, $color, $file) { | |||
$this->checkImagick(); | |||
$this->themingDefaults->expects($this->once()) | |||
->method('getMailHeaderColor') | |||
->willReturn($color); | |||
@@ -127,6 +131,7 @@ class IconBuilderTest extends TestCase { | |||
* @param $file | |||
*/ | |||
public function testGetFavicon($app, $color, $file) { | |||
$this->checkImagick(); | |||
$this->themingDefaults->expects($this->once()) | |||
->method('getMailHeaderColor') | |||
->willReturn($color); |
@@ -0,0 +1,185 @@ | |||
<?php | |||
/** | |||
* @copyright Copyright (c) 2016 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/>. | |||
* | |||
*/ | |||
namespace OCA\Theming\Tests; | |||
use OCP\Files\SimpleFS\ISimpleFile; | |||
use OCP\IConfig; | |||
use Test\TestCase; | |||
use OCP\Files\SimpleFS\ISimpleFolder; | |||
use OCP\Files\IAppData; | |||
use OCP\Files\NotFoundException; | |||
class ImageManager extends TestCase { | |||
/** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $config; | |||
/** @var IAppData|\PHPUnit_Framework_MockObject_MockObject */ | |||
protected $appData; | |||
/** @var ImageManager */ | |||
protected $imageManager; | |||
protected function setUp() { | |||
parent::setUp(); | |||
$this->config = $this->getMockBuilder('\OCP\IConfig')->getMock(); | |||
$this->appData = $this->getMockBuilder('OCP\Files\IAppData')->getMock(); | |||
$this->imageManager = new \OCA\Theming\ImageManager( | |||
$this->config, | |||
$this->appData | |||
); | |||
} | |||
public function testGetCacheFolder() { | |||
$folder = $this->createMock(ISimpleFolder::class); | |||
$this->config->expects($this->once()) | |||
->method('getAppValue') | |||
->with('theming', 'cachebuster', '0') | |||
->willReturn('0'); | |||
$this->appData->expects($this->at(0)) | |||
->method('getFolder') | |||
->with('0') | |||
->willReturn($folder); | |||
$this->assertEquals($folder, $this->imageManager->getCacheFolder()); | |||
} | |||
public function testGetCacheFolderCreate() { | |||
$folder = $this->createMock(ISimpleFolder::class); | |||
$this->config->expects($this->exactly(2)) | |||
->method('getAppValue') | |||
->with('theming', 'cachebuster', '0') | |||
->willReturn('0'); | |||
$this->appData->expects($this->at(0)) | |||
->method('getFolder') | |||
->willThrowException(new NotFoundException()); | |||
$this->appData->expects($this->at(1)) | |||
->method('newFolder') | |||
->with('0') | |||
->willReturn($folder); | |||
$this->appData->expects($this->at(2)) | |||
->method('getFolder') | |||
->with('0') | |||
->willReturn($folder); | |||
$this->appData->expects($this->once()) | |||
->method('getDirectoryListing') | |||
->willReturn([]); | |||
$this->assertEquals($folder, $this->imageManager->getCacheFolder()); | |||
} | |||
public function testGetCachedImage() { | |||
$folder = $this->setupCacheFolder(); | |||
$folder->expects($this->once()) | |||
->method('fileExists') | |||
->with('filename') | |||
->willReturn(true); | |||
$folder->expects($this->once()) | |||
->method('getFile') | |||
->with('filename') | |||
->willReturn('filecontent'); | |||
$expected = 'filecontent'; | |||
$this->assertEquals($expected, $this->imageManager->getCachedImage('filename')); | |||
} | |||
public function testGetCachedImageNotFound() { | |||
$folder = $this->setupCacheFolder(); | |||
$folder->expects($this->once()) | |||
->method('fileExists') | |||
->with('filename') | |||
->willReturn(false); | |||
$expected = null; | |||
$this->assertEquals($expected, $this->imageManager->getCachedImage('filename')); | |||
} | |||
public function testSetCachedImage() { | |||
$folder = $this->setupCacheFolder(); | |||
$file = $this->createMock(ISimpleFile::class); | |||
$folder->expects($this->once()) | |||
->method('fileExists') | |||
->with('filename') | |||
->willReturn(true); | |||
$folder->expects($this->once()) | |||
->method('getFile') | |||
->with('filename') | |||
->willReturn($file); | |||
$file->expects($this->once()) | |||
->method('putContent') | |||
->with('filecontent'); | |||
$this->assertEquals($file, $this->imageManager->setCachedImage('filename', 'filecontent')); | |||
} | |||
public function testSetCachedImageCreate() { | |||
$folder = $this->setupCacheFolder(); | |||
$file = $this->createMock(ISimpleFile::class); | |||
$folder->expects($this->once()) | |||
->method('fileExists') | |||
->with('filename') | |||
->willReturn(false); | |||
$folder->expects($this->once()) | |||
->method('newFile') | |||
->with('filename') | |||
->willReturn($file); | |||
$file->expects($this->once()) | |||
->method('putContent') | |||
->with('filecontent'); | |||
$this->assertEquals($file, $this->imageManager->setCachedImage('filename', 'filecontent')); | |||
} | |||
private function setupCacheFolder() { | |||
$folder = $this->createMock(ISimpleFolder::class); | |||
$this->config->expects($this->once()) | |||
->method('getAppValue') | |||
->with('theming', 'cachebuster', '0') | |||
->willReturn('0'); | |||
$this->appData->expects($this->at(0)) | |||
->method('getFolder') | |||
->with('0') | |||
->willReturn($folder); | |||
return $folder; | |||
} | |||
public function testCleanup() { | |||
$folders = [ | |||
$this->createMock(ISimpleFolder::class), | |||
$this->createMock(ISimpleFolder::class), | |||
$this->createMock(ISimpleFolder::class) | |||
]; | |||
foreach ($folders as $index=>$folder) { | |||
$folder->expects($this->any()) | |||
->method('getName') | |||
->willReturn($index); | |||
} | |||
$folders[0]->expects($this->once())->method('delete'); | |||
$folders[1]->expects($this->once())->method('delete'); | |||
$folders[2]->expects($this->never())->method('delete'); | |||
$this->config->expects($this->once()) | |||
->method('getAppValue') | |||
->with('theming','cachebuster','0') | |||
->willReturn('2'); | |||
$this->appData->expects($this->once()) | |||
->method('getDirectoryListing') | |||
->willReturn($folders); | |||
$this->appData->expects($this->once()) | |||
->method('getFolder') | |||
->with('2') | |||
->willReturn($folders[2]); | |||
$this->imageManager->cleanup(); | |||
} | |||
} |