339 lines
11 KiB
PHP
339 lines
11 KiB
PHP
<?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/>.
|
|
*
|
|
*/
|
|
|
|
namespace OCA\Deck\Service;
|
|
|
|
|
|
use OCA\Deck\AppInfo\Application;
|
|
use OCA\Deck\Db\AssignedUsers;
|
|
use OCA\Deck\Db\AssignedUsersMapper;
|
|
use OCA\Deck\Db\Attachment;
|
|
use OCA\Deck\Db\AttachmentMapper;
|
|
use OCA\Deck\Db\Card;
|
|
use OCA\Deck\Db\CardMapper;
|
|
use OCA\Deck\Db\StackMapper;
|
|
use OCA\Deck\InvalidAttachmentType;
|
|
use OCA\Deck\NotFoundException;
|
|
use OCA\Deck\StatusException;
|
|
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
|
use OCP\AppFramework\Http\FileDisplayResponse;
|
|
use OCP\AppFramework\Http\Response;
|
|
use OCP\AppFramework\Http\StreamResponse;
|
|
use OCP\AppFramework\IAppContainer;
|
|
use OCP\Files\Folder;
|
|
use OCP\Files\IAppData;
|
|
use OCP\Files\IRootFolder;
|
|
use OCP\Files\SimpleFS\ISimpleFile;
|
|
use OCP\Files\SimpleFS\ISimpleFolder;
|
|
use OCP\ICacheFactory;
|
|
use OCP\IConfig;
|
|
use OCP\IL10N;
|
|
use OCP\ILogger;
|
|
use OCP\IRequest;
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
|
use Test\TestCase;
|
|
|
|
class FileServiceTest extends TestCase {
|
|
|
|
/** @var IL10N|MockObject */
|
|
private $l10n;
|
|
/** @var IAppData|MockObject */
|
|
private $appData;
|
|
/** @var IRequest|MockObject */
|
|
private $request;
|
|
/** @var ILogger|MockObject */
|
|
private $logger;
|
|
/** @var FileService */
|
|
private $fileService;
|
|
/** @var IRootFolder */
|
|
private $rootFolder;
|
|
/** @var IConfig */
|
|
private $config;
|
|
|
|
public function setUp() {
|
|
parent::setUp();
|
|
$this->request = $this->createMock(IRequest::class);
|
|
$this->appData = $this->createMock(IAppData::class);
|
|
$this->l10n = $this->createMock(IL10N::class);
|
|
$this->logger = $this->createMock(ILogger::class);
|
|
$this->rootFolder = $this->createMock(IRootFolder::class);
|
|
$this->config = $this->createMock(IConfig::class);
|
|
$this->fileService = new FileService($this->l10n, $this->appData, $this->request, $this->logger, $this->rootFolder, $this->config);
|
|
}
|
|
|
|
public function mockGetFolder($cardId) {
|
|
$folder = $this->createMock(ISimpleFolder::class);
|
|
$this->appData->expects($this->once())
|
|
->method('getFolder')
|
|
->with('file-card-' . $cardId)
|
|
->willReturn($folder);
|
|
return $folder;
|
|
}
|
|
public function mockGetFolderFailure($cardId) {
|
|
$folder = $this->createMock(ISimpleFolder::class);
|
|
$this->appData->expects($this->once())
|
|
->method('getFolder')
|
|
->with('file-card-' . $cardId)
|
|
->will($this->throwException(new \OCP\Files\NotFoundException()));
|
|
$this->appData->expects($this->once())
|
|
->method('newFolder')
|
|
->with('file-card-' . $cardId)
|
|
->willReturn($folder);
|
|
return $folder;
|
|
}
|
|
|
|
private function getAttachment() {
|
|
$attachment = new Attachment();
|
|
$attachment->setId(1);
|
|
$attachment->setCardId(123);
|
|
return $attachment;
|
|
}
|
|
|
|
private function mockGetUploadedFileEmpty() {
|
|
$this->request->expects($this->once())
|
|
->method('getUploadedFile')
|
|
->willReturn([]);
|
|
}
|
|
private function mockGetUploadedFileError($error) {
|
|
$this->request->expects($this->once())
|
|
->method('getUploadedFile')
|
|
->willReturn(['error' => $error]);
|
|
}
|
|
private function mockGetUploadedFile() {
|
|
$this->request->expects($this->once())
|
|
->method('getUploadedFile')
|
|
->willReturn([
|
|
'name' => 'file.jpg',
|
|
'tmp_name' => __FILE__,
|
|
]);
|
|
}
|
|
|
|
public function testExtendDataNotFound() {
|
|
$attachment = $this->getAttachment();
|
|
$folder = $this->mockGetFolder(123);
|
|
$folder->expects($this->once())->method('getFile')->will($this->throwException(new \OCP\Files\NotFoundException()));
|
|
$this->assertEquals($attachment, $this->fileService->extendData($attachment));
|
|
}
|
|
|
|
public function testExtendDataNotPermitted() {
|
|
$attachment = $this->getAttachment();
|
|
$folder = $this->mockGetFolder(123);
|
|
$folder->expects($this->once())->method('getFile')->will($this->throwException(new \OCP\Files\NotPermittedException()));
|
|
$this->assertEquals($attachment, $this->fileService->extendData($attachment));
|
|
}
|
|
|
|
public function testExtendData() {
|
|
$attachment = $this->getAttachment();
|
|
$expected = $this->getAttachment();
|
|
$expected->setExtendedData([
|
|
'filesize' => 100,
|
|
'mimetype' => 'image/jpeg',
|
|
'info' => pathinfo(__FILE__)
|
|
]);
|
|
|
|
$file = $this->createMock(ISimpleFile::class);
|
|
$file->expects($this->once())->method('getSize')->willReturn(100);
|
|
$file->expects($this->once())->method('getMimeType')->willReturn('image/jpeg');
|
|
$file->expects($this->once())->method('getName')->willReturn(__FILE__);
|
|
|
|
$folder = $this->mockGetFolder(123);
|
|
$folder->expects($this->once())->method('getFile')->willReturn($file);
|
|
$this->assertEquals($expected, $this->fileService->extendData($attachment));
|
|
}
|
|
|
|
/**
|
|
* @expectedException \Exception
|
|
*/
|
|
public function testCreateEmpty() {
|
|
$attachment = $this->getAttachment();
|
|
$this->l10n->expects($this->any())
|
|
->method('t')
|
|
->willReturn('Error');
|
|
$this->mockGetUploadedFileEmpty();
|
|
$this->fileService->create($attachment);
|
|
}
|
|
|
|
/**
|
|
* @expectedException \Exception
|
|
*/
|
|
public function testCreateError() {
|
|
$attachment = $this->getAttachment();
|
|
$this->mockGetUploadedFileError(UPLOAD_ERR_INI_SIZE);
|
|
$this->l10n->expects($this->any())
|
|
->method('t')
|
|
->willReturn('Error');
|
|
$this->fileService->create($attachment);
|
|
}
|
|
|
|
public function testCreate() {
|
|
$attachment = $this->getAttachment();
|
|
$this->mockGetUploadedFile();
|
|
$folder = $this->mockGetFolder(123);
|
|
$folder->expects($this->once())
|
|
->method('fileExists')
|
|
->willReturn(false);
|
|
$file = $this->createMock(ISimpleFile::class);
|
|
$file->expects($this->once())
|
|
->method('putContent');
|
|
// FIXME: test fopen call properly
|
|
$folder->expects($this->once())
|
|
->method('newFile')
|
|
->willReturn($file);
|
|
|
|
$this->fileService->create($attachment);
|
|
}
|
|
|
|
public function testCreateNoFolder() {
|
|
$attachment = $this->getAttachment();
|
|
$this->mockGetUploadedFile();
|
|
$folder = $this->mockGetFolderFailure(123);
|
|
$folder->expects($this->once())
|
|
->method('fileExists')
|
|
->willReturn(false);
|
|
$file = $this->createMock(ISimpleFile::class);
|
|
$file->expects($this->once())
|
|
->method('putContent');
|
|
// FIXME: test fopen call properly
|
|
$folder->expects($this->once())
|
|
->method('newFile')
|
|
->willReturn($file);
|
|
|
|
$this->fileService->create($attachment);
|
|
}
|
|
|
|
/**
|
|
* @expectedException \Exception
|
|
* @expectedExceptionMessage File already exists.
|
|
*/
|
|
public function testCreateExists() {
|
|
$attachment = $this->getAttachment();
|
|
$this->mockGetUploadedFile();
|
|
$folder = $this->mockGetFolder(123);
|
|
$folder->expects($this->once())
|
|
->method('fileExists')
|
|
->willReturn(true);
|
|
$this->fileService->create($attachment);
|
|
}
|
|
|
|
public function testUpdate() {
|
|
$attachment = $this->getAttachment();
|
|
$this->mockGetUploadedFile();
|
|
$folder = $this->mockGetFolder(123);
|
|
$file = $this->createMock(ISimpleFile::class);
|
|
$file->expects($this->once())
|
|
->method('putContent');
|
|
// FIXME: test fopen call properly
|
|
$folder->expects($this->once())
|
|
->method('getFile')
|
|
->willReturn($file);
|
|
|
|
$this->fileService->update($attachment);
|
|
}
|
|
|
|
public function testDelete() {
|
|
$attachment = $this->getAttachment();
|
|
$file = $this->createMock(ISimpleFile::class);
|
|
$folder = $this->mockGetFolder('123');
|
|
$folder->expects($this->once())
|
|
->method('getFile')
|
|
->willReturn($file);
|
|
$file->expects($this->once())
|
|
->method('delete');
|
|
$this->fileService->delete($attachment);
|
|
}
|
|
|
|
public function testDisplay() {
|
|
$this->config->expects($this->once())
|
|
->method('getSystemValue')
|
|
->willReturn('123');
|
|
$appDataFolder = $this->createMock(Folder::class);
|
|
$deckAppDataFolder = $this->createMock(Folder::class);
|
|
$cardFolder = $this->createMock(Folder::class);
|
|
$this->rootFolder->expects($this->once())->method('get')->willReturn($appDataFolder);
|
|
$appDataFolder->expects($this->once())->method('get')->willReturn($deckAppDataFolder);
|
|
$deckAppDataFolder->expects($this->once())->method('get')->willReturn($cardFolder);
|
|
$attachment = $this->getAttachment();
|
|
$file = $this->createMock(\OCP\Files\File::class);
|
|
$cardFolder->expects($this->once())->method('get')->willReturn($file);
|
|
$file->expects($this->any())
|
|
->method('getMimeType')
|
|
->willReturn('image/jpeg');
|
|
$file->expects($this->any())
|
|
->method('getName')
|
|
->willReturn('file1');
|
|
$file->expects($this->any())
|
|
->method('fopen')
|
|
->willReturn('fileresource');
|
|
$actual = $this->fileService->display($attachment);
|
|
$expected = new StreamResponse('fileresource');
|
|
$expected->addHeader('Content-Type', 'image/jpeg');
|
|
$expected->addHeader('Content-Disposition', 'inline; filename="' . rawurldecode($file->getName()) . '"');
|
|
|
|
$this->assertEquals($expected, $actual);
|
|
}
|
|
|
|
public function testDisplayPdf() {
|
|
$this->config->expects($this->once())
|
|
->method('getSystemValue')
|
|
->willReturn('123');
|
|
$appDataFolder = $this->createMock(Folder::class);
|
|
$deckAppDataFolder = $this->createMock(Folder::class);
|
|
$cardFolder = $this->createMock(Folder::class);
|
|
$this->rootFolder->expects($this->once())->method('get')->willReturn($appDataFolder);
|
|
$appDataFolder->expects($this->once())->method('get')->willReturn($deckAppDataFolder);
|
|
$deckAppDataFolder->expects($this->once())->method('get')->willReturn($cardFolder);
|
|
$attachment = $this->getAttachment();
|
|
$file = $this->createMock(\OCP\Files\File::class);
|
|
$cardFolder->expects($this->once())->method('get')->willReturn($file);
|
|
$file->expects($this->any())
|
|
->method('getMimeType')
|
|
->willReturn('application/pdf');
|
|
$file->expects($this->any())
|
|
->method('getName')
|
|
->willReturn('file1');
|
|
$file->expects($this->any())
|
|
->method('fopen')
|
|
->willReturn('fileresource');
|
|
$actual = $this->fileService->display($attachment);
|
|
$expected = new StreamResponse('fileresource');
|
|
$expected->addHeader('Content-Disposition', 'inline; filename="' . rawurldecode($file->getName()) . '"');
|
|
$expected->addHeader('Content-Type', 'application/pdf');
|
|
$policy = new ContentSecurityPolicy();
|
|
$policy->addAllowedObjectDomain('\'self\'');
|
|
$policy->addAllowedObjectDomain('blob:');
|
|
$expected->setContentSecurityPolicy($policy);
|
|
$this->assertEquals($expected, $actual);
|
|
}
|
|
|
|
public function testAllowUndo() {
|
|
$this->assertTrue($this->fileService->allowUndo());
|
|
}
|
|
|
|
public function testMarkAsDeleted() {
|
|
// TODO: use proper ITimeFactory in the service so we can mock the call to time
|
|
$attachment = $this->getAttachment();
|
|
$this->assertEquals(0, $attachment->getDeletedAt());
|
|
$this->fileService->markAsDeleted($attachment);
|
|
$this->assertGreaterThan(0, $attachment->getDeletedAt());
|
|
}
|
|
} |