diff options
Diffstat (limited to 'apps/dav/tests/unit/Files')
-rw-r--r-- | apps/dav/tests/unit/Files/FileSearchBackendTest.php | 115 | ||||
-rw-r--r-- | apps/dav/tests/unit/Files/MultipartRequestParserTest.php | 167 | ||||
-rw-r--r-- | apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php | 250 |
3 files changed, 309 insertions, 223 deletions
diff --git a/apps/dav/tests/unit/Files/FileSearchBackendTest.php b/apps/dav/tests/unit/Files/FileSearchBackendTest.php index 0240fac3621..c6d6f85347b 100644 --- a/apps/dav/tests/unit/Files/FileSearchBackendTest.php +++ b/apps/dav/tests/unit/Files/FileSearchBackendTest.php @@ -1,31 +1,12 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.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 OCA\DAV\Tests\Files; +namespace OCA\DAV\Tests\unit\Files; use OC\Files\Search\SearchComparison; use OC\Files\Search\SearchQuery; @@ -34,6 +15,7 @@ use OCA\DAV\Connector\Sabre\Directory; use OCA\DAV\Connector\Sabre\File; use OCA\DAV\Connector\Sabre\FilesPlugin; use OCA\DAV\Connector\Sabre\ObjectTree; +use OCA\DAV\Connector\Sabre\Server; use OCA\DAV\Files\FileSearchBackend; use OCP\Files\FileInfo; use OCP\Files\Folder; @@ -44,36 +26,25 @@ use OCP\Files\Search\ISearchQuery; use OCP\FilesMetadata\IFilesMetadataManager; use OCP\IUser; use OCP\Share\IManager; +use PHPUnit\Framework\MockObject\MockObject; use SearchDAV\Backend\SearchPropertyDefinition; use SearchDAV\Query\Limit; +use SearchDAV\Query\Literal; use SearchDAV\Query\Operator; use SearchDAV\Query\Query; +use SearchDAV\Query\Scope; use Test\TestCase; class FileSearchBackendTest extends TestCase { - /** @var ObjectTree|\PHPUnit\Framework\MockObject\MockObject */ - private $tree; - - /** @var IUser */ - private $user; - - /** @var IRootFolder|\PHPUnit\Framework\MockObject\MockObject */ - private $rootFolder; - - /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */ - private $shareManager; - - /** @var View|\PHPUnit\Framework\MockObject\MockObject */ - private $view; - - /** @var Folder|\PHPUnit\Framework\MockObject\MockObject */ - private $searchFolder; - - /** @var FileSearchBackend */ - private $search; - - /** @var Directory|\PHPUnit\Framework\MockObject\MockObject */ - private $davFolder; + private ObjectTree&MockObject $tree; + private Server&MockObject $server; + private IUser&MockObject $user; + private IRootFolder&MockObject $rootFolder; + private IManager&MockObject $shareManager; + private View&MockObject $view; + private Folder&MockObject $searchFolder; + private Directory&MockObject $davFolder; + private FileSearchBackend $search; protected function setUp(): void { parent::setUp(); @@ -83,11 +54,14 @@ class FileSearchBackendTest extends TestCase { ->method('getUID') ->willReturn('test'); - $this->tree = $this->getMockBuilder(ObjectTree::class) - ->disableOriginalConstructor() - ->getMock(); - + $this->tree = $this->createMock(ObjectTree::class); + $this->server = $this->createMock(Server::class); $this->view = $this->createMock(View::class); + $this->rootFolder = $this->createMock(IRootFolder::class); + $this->shareManager = $this->createMock(IManager::class); + $this->searchFolder = $this->createMock(Folder::class); + $fileInfo = $this->createMock(FileInfo::class); + $this->davFolder = $this->createMock(Directory::class); $this->view->expects($this->any()) ->method('getRoot') @@ -97,16 +71,6 @@ class FileSearchBackendTest extends TestCase { ->method('getRelativePath') ->willReturnArgument(0); - $this->rootFolder = $this->createMock(IRootFolder::class); - - $this->shareManager = $this->createMock(IManager::class); - - $this->searchFolder = $this->createMock(Folder::class); - - $fileInfo = $this->createMock(FileInfo::class); - - $this->davFolder = $this->createMock(Directory::class); - $this->davFolder->expects($this->any()) ->method('getFileInfo') ->willReturn($fileInfo); @@ -117,7 +81,7 @@ class FileSearchBackendTest extends TestCase { $filesMetadataManager = $this->createMock(IFilesMetadataManager::class); - $this->search = new FileSearchBackend($this->tree, $this->user, $this->rootFolder, $this->shareManager, $this->view, $filesMetadataManager); + $this->search = new FileSearchBackend($this->server, $this->tree, $this->user, $this->rootFolder, $this->shareManager, $this->view, $filesMetadataManager); } public function testSearchFilename(): void { @@ -280,8 +244,8 @@ class FileSearchBackendTest extends TestCase { $this->search->search($query); } - private function getBasicQuery($type, $property, $value = null) { - $scope = new \SearchDAV\Query\Scope('/', 'infinite'); + private function getBasicQuery(string $type, string $property, int|string|null $value = null) { + $scope = new Scope('/', 'infinite'); $scope->path = '/'; $from = [$scope]; $orderBy = []; @@ -289,12 +253,12 @@ class FileSearchBackendTest extends TestCase { if (is_null($value)) { $where = new Operator( $type, - [new \SearchDAV\Query\Literal($property)] + [new Literal($property)] ); } else { $where = new Operator( $type, - [new SearchPropertyDefinition($property, true, true, true), new \SearchDAV\Query\Literal($value)] + [new SearchPropertyDefinition($property, true, true, true), new Literal($value)] ); } $limit = new Limit(); @@ -367,11 +331,11 @@ class FileSearchBackendTest extends TestCase { [ new Operator( Operator::OPERATION_EQUAL, - [new SearchPropertyDefinition('{DAV:}getcontenttype', true, true, true), new \SearchDAV\Query\Literal('image/png')] + [new SearchPropertyDefinition('{DAV:}getcontenttype', true, true, true), new Literal('image/png')] ), new Operator( Operator::OPERATION_EQUAL, - [new SearchPropertyDefinition(FilesPlugin::OWNER_ID_PROPERTYNAME, true, true, true), new \SearchDAV\Query\Literal($this->user->getUID())] + [new SearchPropertyDefinition(FilesPlugin::OWNER_ID_PROPERTYNAME, true, true, true), new Literal($this->user->getUID())] ), ] ); @@ -400,7 +364,7 @@ class FileSearchBackendTest extends TestCase { $innerOperator = new Operator( Operator::OPERATION_EQUAL, - [new SearchPropertyDefinition('{DAV:}getcontenttype', true, true, true), new \SearchDAV\Query\Literal('image/png')] + [new SearchPropertyDefinition('{DAV:}getcontenttype', true, true, true), new Literal('image/png')] ); // 5 child operators $level1Operator = new Operator( @@ -441,4 +405,17 @@ class FileSearchBackendTest extends TestCase { $this->expectException(\InvalidArgumentException::class); $this->search->search($query); } + + public function testPreloadPropertyFor(): void { + $node1 = $this->createMock(File::class); + $node2 = $this->createMock(Directory::class); + $nodes = [$node1, $node2]; + $requestProperties = ['{DAV:}getcontenttype', '{DAV:}getlastmodified']; + + $this->server->expects($this->once()) + ->method('emit') + ->with('preloadProperties', [$nodes, $requestProperties]); + + $this->search->preloadPropertyFor($nodes, $requestProperties); + } } diff --git a/apps/dav/tests/unit/Files/MultipartRequestParserTest.php b/apps/dav/tests/unit/Files/MultipartRequestParserTest.php index 0edf68e6c09..dc0e884f07c 100644 --- a/apps/dav/tests/unit/Files/MultipartRequestParserTest.php +++ b/apps/dav/tests/unit/Files/MultipartRequestParserTest.php @@ -1,77 +1,68 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2021, Louis Chemineau <louis@chmn.me> - * - * @author Louis Chemineau <louis@chmn.me> - * - * @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: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-only */ -namespace OCA\DAV\Tests\unit\DAV; +namespace OCA\DAV\Tests\unit\Files; use OCA\DAV\BulkUpload\MultipartRequestParser; +use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; +use Sabre\HTTP\RequestInterface; use Test\TestCase; class MultipartRequestParserTest extends TestCase { - protected LoggerInterface $logger; + protected LoggerInterface&MockObject $logger; protected function setUp(): void { + parent::setUp(); $this->logger = $this->createMock(LoggerInterface::class); } - private function getValidBodyObject() { + private static function getValidBodyObject(): array { return [ [ - "headers" => [ - "Content-Length" => 7, - "X-File-MD5" => "4f2377b4d911f7ec46325fe603c3af03", - "X-File-Path" => "/coucou.txt" + 'headers' => [ + 'Content-Length' => 7, + 'X-File-MD5' => '4f2377b4d911f7ec46325fe603c3af03', + 'OC-Checksum' => 'md5:4f2377b4d911f7ec46325fe603c3af03', + 'X-File-Path' => '/coucou.txt' ], - "content" => "Coucou\n" + 'content' => "Coucou\n" ] ]; } - private function getMultipartParser(array $parts, array $headers = [], string $boundary = "boundary_azertyuiop"): MultipartRequestParser { - $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface') + private function getMultipartParser(array $parts, array $headers = [], string $boundary = 'boundary_azertyuiop'): MultipartRequestParser { + /** @var RequestInterface&MockObject $request */ + $request = $this->getMockBuilder(RequestInterface::class) ->disableOriginalConstructor() ->getMock(); - $headers = array_merge(['Content-Type' => 'multipart/related; boundary='.$boundary], $headers); + $headers = array_merge(['Content-Type' => 'multipart/related; boundary=' . $boundary], $headers); $request->expects($this->any()) ->method('getHeader') ->willReturnCallback(function (string $key) use (&$headers) { return $headers[$key]; }); - $body = ""; + $body = ''; foreach ($parts as $part) { - $body .= '--'.$boundary."\r\n"; + $body .= '--' . $boundary . "\r\n"; foreach ($part['headers'] as $headerKey => $headerPart) { - $body .= $headerKey.": ".$headerPart."\r\n"; + $body .= $headerKey . ': ' . $headerPart . "\r\n"; } $body .= "\r\n"; - $body .= $part['content']."\r\n"; + $body .= $part['content'] . "\r\n"; } - $body .= '--'.$boundary."--"; + $body .= '--' . $boundary . '--'; $stream = fopen('php://temp', 'r+'); fwrite($stream, $body); @@ -89,8 +80,9 @@ class MultipartRequestParserTest extends TestCase { * Test validation of the request's body type */ public function testBodyTypeValidation(): void { - $bodyStream = "I am not a stream, but pretend to be"; - $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface') + $bodyStream = 'I am not a stream, but pretend to be'; + /** @var RequestInterface&MockObject $request */ + $request = $this->getMockBuilder(RequestInterface::class) ->disableOriginalConstructor() ->getMock(); $request->expects($this->any()) @@ -104,50 +96,91 @@ class MultipartRequestParserTest extends TestCase { /** * Test with valid request. * - valid boundary - * - valid md5 hash + * - valid hash * - valid content-length * - valid file content * - valid file path */ public function testValidRequest(): void { - $multipartParser = $this->getMultipartParser( - $this->getValidBodyObject() - ); + $bodyObject = self::getValidBodyObject(); + unset($bodyObject['0']['headers']['X-File-MD5']); + + $multipartParser = $this->getMultipartParser($bodyObject); [$headers, $content] = $multipartParser->parseNextPart(); - $this->assertSame((int)$headers["content-length"], 7, "Content-Length header should be the same as provided."); - $this->assertSame($headers["x-file-md5"], "4f2377b4d911f7ec46325fe603c3af03", "X-File-MD5 header should be the same as provided."); - $this->assertSame($headers["x-file-path"], "/coucou.txt", "X-File-Path header should be the same as provided."); + $this->assertSame((int)$headers['content-length'], 7, 'Content-Length header should be the same as provided.'); + $this->assertSame($headers['oc-checksum'], 'md5:4f2377b4d911f7ec46325fe603c3af03', 'OC-Checksum header should be the same as provided.'); + $this->assertSame($headers['x-file-path'], '/coucou.txt', 'X-File-Path header should be the same as provided.'); + + $this->assertSame($content, "Coucou\n", 'Content should be the same'); + } - $this->assertSame($content, "Coucou\n", "Content should be the same"); + /** + * Test with valid request. + * - valid boundary + * - valid md5 hash + * - valid content-length + * - valid file content + * - valid file path + */ + public function testValidRequestWithMd5(): void { + $bodyObject = self::getValidBodyObject(); + unset($bodyObject['0']['headers']['OC-Checksum']); + + $multipartParser = $this->getMultipartParser($bodyObject); + + [$headers, $content] = $multipartParser->parseNextPart(); + + $this->assertSame((int)$headers['content-length'], 7, 'Content-Length header should be the same as provided.'); + $this->assertSame($headers['x-file-md5'], '4f2377b4d911f7ec46325fe603c3af03', 'X-File-MD5 header should be the same as provided.'); + $this->assertSame($headers['x-file-path'], '/coucou.txt', 'X-File-Path header should be the same as provided.'); + + $this->assertSame($content, "Coucou\n", 'Content should be the same'); + } + + /** + * Test with invalid hash. + */ + public function testInvalidHash(): void { + $bodyObject = self::getValidBodyObject(); + $bodyObject['0']['headers']['OC-Checksum'] = 'md5:f2377b4d911f7ec46325fe603c3af03'; + unset($bodyObject['0']['headers']['X-File-MD5']); + $multipartParser = $this->getMultipartParser( + $bodyObject + ); + + $this->expectExceptionMessage('Computed md5 hash is incorrect (4f2377b4d911f7ec46325fe603c3af03).'); + $multipartParser->parseNextPart(); } /** * Test with invalid md5 hash. */ public function testInvalidMd5Hash(): void { - $bodyObject = $this->getValidBodyObject(); - $bodyObject["0"]["headers"]["X-File-MD5"] = "f2377b4d911f7ec46325fe603c3af03"; + $bodyObject = self::getValidBodyObject(); + unset($bodyObject['0']['headers']['OC-Checksum']); + $bodyObject['0']['headers']['X-File-MD5'] = 'f2377b4d911f7ec46325fe603c3af03'; $multipartParser = $this->getMultipartParser( $bodyObject ); - $this->expectExceptionMessage('Computed md5 hash is incorrect.'); + $this->expectExceptionMessage('Computed md5 hash is incorrect (4f2377b4d911f7ec46325fe603c3af03).'); $multipartParser->parseNextPart(); } /** - * Test with a null md5 hash. + * Test with a null hash headers. */ - public function testNullMd5Hash(): void { - $bodyObject = $this->getValidBodyObject(); - unset($bodyObject["0"]["headers"]["X-File-MD5"]); + public function testNullHash(): void { + $bodyObject = self::getValidBodyObject(); + unset($bodyObject['0']['headers']['OC-Checksum']); + unset($bodyObject['0']['headers']['X-File-MD5']); $multipartParser = $this->getMultipartParser( $bodyObject ); - $this->expectExceptionMessage('The X-File-MD5 header must not be null.'); + $this->expectExceptionMessage('The hash headers must not be null.'); $multipartParser->parseNextPart(); } @@ -155,8 +188,8 @@ class MultipartRequestParserTest extends TestCase { * Test with a null Content-Length. */ public function testNullContentLength(): void { - $bodyObject = $this->getValidBodyObject(); - unset($bodyObject["0"]["headers"]["Content-Length"]); + $bodyObject = self::getValidBodyObject(); + unset($bodyObject['0']['headers']['Content-Length']); $multipartParser = $this->getMultipartParser( $bodyObject ); @@ -169,13 +202,13 @@ class MultipartRequestParserTest extends TestCase { * Test with a lower Content-Length. */ public function testLowerContentLength(): void { - $bodyObject = $this->getValidBodyObject(); - $bodyObject["0"]["headers"]["Content-Length"] = 6; + $bodyObject = self::getValidBodyObject(); + $bodyObject['0']['headers']['Content-Length'] = 6; $multipartParser = $this->getMultipartParser( $bodyObject ); - $this->expectExceptionMessage('Computed md5 hash is incorrect.'); + $this->expectExceptionMessage('Computed md5 hash is incorrect (41060d3ddfdf63e68fc2bf196f652ee9).'); $multipartParser->parseNextPart(); } @@ -183,13 +216,13 @@ class MultipartRequestParserTest extends TestCase { * Test with a higher Content-Length. */ public function testHigherContentLength(): void { - $bodyObject = $this->getValidBodyObject(); - $bodyObject["0"]["headers"]["Content-Length"] = 8; + $bodyObject = self::getValidBodyObject(); + $bodyObject['0']['headers']['Content-Length'] = 8; $multipartParser = $this->getMultipartParser( $bodyObject ); - $this->expectExceptionMessage('Computed md5 hash is incorrect.'); + $this->expectExceptionMessage('Computed md5 hash is incorrect (0161002bbee6a744f18741b8a914e413).'); $multipartParser->parseNextPart(); } @@ -197,7 +230,7 @@ class MultipartRequestParserTest extends TestCase { * Test with wrong boundary in body. */ public function testWrongBoundary(): void { - $bodyObject = $this->getValidBodyObject(); + $bodyObject = self::getValidBodyObject(); $multipartParser = $this->getMultipartParser( $bodyObject, ['Content-Type' => 'multipart/related; boundary=boundary_poiuytreza'] @@ -211,7 +244,7 @@ class MultipartRequestParserTest extends TestCase { * Test with no boundary in request headers. */ public function testNoBoundaryInHeader(): void { - $bodyObject = $this->getValidBodyObject(); + $bodyObject = self::getValidBodyObject(); $this->expectExceptionMessage('Error while parsing boundary in Content-Type header.'); $this->getMultipartParser( $bodyObject, @@ -223,7 +256,7 @@ class MultipartRequestParserTest extends TestCase { * Test with no boundary in the request's headers. */ public function testNoBoundaryInBody(): void { - $bodyObject = $this->getValidBodyObject(); + $bodyObject = self::getValidBodyObject(); $multipartParser = $this->getMultipartParser( $bodyObject, ['Content-Type' => 'multipart/related; boundary=boundary_azertyuiop'], @@ -238,7 +271,7 @@ class MultipartRequestParserTest extends TestCase { * Test with a boundary with quotes in the request's headers. */ public function testBoundaryWithQuotes(): void { - $bodyObject = $this->getValidBodyObject(); + $bodyObject = self::getValidBodyObject(); $multipartParser = $this->getMultipartParser( $bodyObject, ['Content-Type' => 'multipart/related; boundary="boundary_azertyuiop"'], @@ -254,7 +287,7 @@ class MultipartRequestParserTest extends TestCase { * Test with a wrong Content-Type in the request's headers. */ public function testWrongContentType(): void { - $bodyObject = $this->getValidBodyObject(); + $bodyObject = self::getValidBodyObject(); $this->expectExceptionMessage('Content-Type must be multipart/related'); $this->getMultipartParser( $bodyObject, @@ -266,7 +299,7 @@ class MultipartRequestParserTest extends TestCase { * Test with a wrong key after the content type in the request's headers. */ public function testWrongKeyInContentType(): void { - $bodyObject = $this->getValidBodyObject(); + $bodyObject = self::getValidBodyObject(); $this->expectExceptionMessage('Boundary is invalid'); $this->getMultipartParser( $bodyObject, @@ -278,7 +311,7 @@ class MultipartRequestParserTest extends TestCase { * Test with a null Content-Type in the request's headers. */ public function testNullContentType(): void { - $bodyObject = $this->getValidBodyObject(); + $bodyObject = self::getValidBodyObject(); $this->expectExceptionMessage('Content-Type can not be null'); $this->getMultipartParser( $bodyObject, diff --git a/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php b/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php index 764cdd5c339..1a7ab7179e1 100644 --- a/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php +++ b/apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php @@ -1,33 +1,19 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Morris Jobke <hey@morrisjobke.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\DAV\Tests\Files\Sharing; +namespace OCA\DAV\Tests\unit\Files\Sharing; -use OC\Files\View; use OCA\DAV\Files\Sharing\FilesDropPlugin; -use Sabre\DAV\Exception\MethodNotAllowed; +use OCP\Files\Folder; +use OCP\Files\NotFoundException; +use OCP\Share\IAttributes; +use OCP\Share\IShare; +use PHPUnit\Framework\MockObject\MockObject; +use Sabre\DAV\Exception\BadRequest; use Sabre\DAV\Server; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; @@ -35,51 +21,42 @@ use Test\TestCase; class FilesDropPluginTest extends TestCase { - /** @var View|\PHPUnit\Framework\MockObject\MockObject */ - private $view; - - /** @var Server|\PHPUnit\Framework\MockObject\MockObject */ - private $server; - - /** @var FilesDropPlugin */ - private $plugin; + private FilesDropPlugin $plugin; - /** @var RequestInterface|\PHPUnit\Framework\MockObject\MockObject */ - private $request; - - /** @var ResponseInterface|\PHPUnit\Framework\MockObject\MockObject */ - private $response; + private Folder&MockObject $node; + private IShare&MockObject $share; + private Server&MockObject $server; + private RequestInterface&MockObject $request; + private ResponseInterface&MockObject $response; protected function setUp(): void { parent::setUp(); - $this->view = $this->createMock(View::class); + $this->node = $this->createMock(Folder::class); + $this->node->method('getPath') + ->willReturn('/files/token'); + + $this->share = $this->createMock(IShare::class); + $this->share->expects(self::any()) + ->method('getNode') + ->willReturn($this->node); $this->server = $this->createMock(Server::class); $this->plugin = new FilesDropPlugin(); $this->request = $this->createMock(RequestInterface::class); $this->response = $this->createMock(ResponseInterface::class); - $this->response->expects($this->never()) - ->method($this->anything()); - } - - public function testInitialize(): void { - $this->server->expects($this->once()) - ->method('on') - ->with( - $this->equalTo('beforeMethod:*'), - $this->equalTo([$this->plugin, 'beforeMethod']), - $this->equalTo(999) - ); + $attributes = $this->createMock(IAttributes::class); + $this->share->expects($this->any()) + ->method('getAttributes') + ->willReturn($attributes); - $this->plugin->initialize($this->server); + $this->share + ->method('getToken') + ->willReturn('token'); } public function testNotEnabled(): void { - $this->view->expects($this->never()) - ->method($this->anything()); - $this->request->expects($this->never()) ->method($this->anything()); @@ -88,95 +65,194 @@ class FilesDropPluginTest extends TestCase { public function testValid(): void { $this->plugin->enable(); - $this->plugin->setView($this->view); + $this->plugin->setShare($this->share); $this->request->method('getMethod') ->willReturn('PUT'); $this->request->method('getPath') - ->willReturn('file.txt'); + ->willReturn('/files/token/file.txt'); $this->request->method('getBaseUrl') ->willReturn('https://example.com'); - $this->view->method('file_exists') - ->with('/file.txt') - ->willReturn(false); + $this->node->expects(self::once()) + ->method('getNonExistingName') + ->with('file.txt') + ->willReturn('file.txt'); $this->request->expects($this->once()) ->method('setUrl') - ->with('https://example.com/file.txt'); + ->with('https://example.com/files/token/file.txt'); $this->plugin->beforeMethod($this->request, $this->response); } public function testFileAlreadyExistsValid(): void { $this->plugin->enable(); - $this->plugin->setView($this->view); + $this->plugin->setShare($this->share); $this->request->method('getMethod') ->willReturn('PUT'); $this->request->method('getPath') - ->willReturn('file.txt'); + ->willReturn('/files/token/file.txt'); $this->request->method('getBaseUrl') ->willReturn('https://example.com'); - $this->view->method('file_exists') - ->willReturnCallback(function ($path) { - if ($path === 'file.txt' || $path === '/file.txt') { - return true; - } else { - return false; - } - }); + $this->node->method('getNonExistingName') + ->with('file.txt') + ->willReturn('file (2).txt'); $this->request->expects($this->once()) ->method('setUrl') - ->with($this->equalTo('https://example.com/file (2).txt')); + ->with($this->equalTo('https://example.com/files/token/file (2).txt')); $this->plugin->beforeMethod($this->request, $this->response); } - public function testNoMKCOL(): void { + public function testNoMKCOLWithoutNickname(): void { $this->plugin->enable(); - $this->plugin->setView($this->view); + $this->plugin->setShare($this->share); $this->request->method('getMethod') ->willReturn('MKCOL'); - $this->expectException(MethodNotAllowed::class); + $this->expectException(BadRequest::class); + + $this->plugin->beforeMethod($this->request, $this->response); + } + + public function testMKCOLWithNickname(): void { + $this->plugin->enable(); + $this->plugin->setShare($this->share); + + $this->request->method('getMethod') + ->willReturn('MKCOL'); + + $this->request->method('hasHeader') + ->with('X-NC-Nickname') + ->willReturn(true); + $this->request->method('getHeader') + ->with('X-NC-Nickname') + ->willReturn('nickname'); + + $this->expectNotToPerformAssertions(); $this->plugin->beforeMethod($this->request, $this->response); } - public function testNoSubdirPut(): void { + public function testSubdirPut(): void { $this->plugin->enable(); - $this->plugin->setView($this->view); + $this->plugin->setShare($this->share); $this->request->method('getMethod') ->willReturn('PUT'); + $this->request->method('hasHeader') + ->with('X-NC-Nickname') + ->willReturn(true); + $this->request->method('getHeader') + ->with('X-NC-Nickname') + ->willReturn('nickname'); + $this->request->method('getPath') - ->willReturn('folder/file.txt'); + ->willReturn('/files/token/folder/file.txt'); $this->request->method('getBaseUrl') ->willReturn('https://example.com'); - $this->view->method('file_exists') - ->willReturnCallback(function ($path) { - if ($path === 'file.txt' || $path === '/file.txt') { - return true; - } else { - return false; - } - }); + $nodeName = $this->createMock(Folder::class); + $nodeFolder = $this->createMock(Folder::class); + $nodeFolder->expects(self::once()) + ->method('getPath') + ->willReturn('/files/token/nickname/folder'); + $nodeFolder->method('getNonExistingName') + ->with('file.txt') + ->willReturn('file.txt'); + $nodeName->expects(self::once()) + ->method('get') + ->with('folder') + ->willThrowException(new NotFoundException()); + $nodeName->expects(self::once()) + ->method('newFolder') + ->with('folder') + ->willReturn($nodeFolder); + + $this->node->expects(self::once()) + ->method('get') + ->willThrowException(new NotFoundException()); + $this->node->expects(self::once()) + ->method('newFolder') + ->with('nickname') + ->willReturn($nodeName); $this->request->expects($this->once()) ->method('setUrl') - ->with($this->equalTo('https://example.com/file (2).txt')); + ->with($this->equalTo('https://example.com/files/token/nickname/folder/file.txt')); $this->plugin->beforeMethod($this->request, $this->response); } + + public function testRecursiveFolderCreation(): void { + $this->plugin->enable(); + $this->plugin->setShare($this->share); + + $this->request->method('getMethod') + ->willReturn('PUT'); + $this->request->method('hasHeader') + ->with('X-NC-Nickname') + ->willReturn(true); + $this->request->method('getHeader') + ->with('X-NC-Nickname') + ->willReturn('nickname'); + + $this->request->method('getPath') + ->willReturn('/files/token/folder/subfolder/file.txt'); + $this->request->method('getBaseUrl') + ->willReturn('https://example.com'); + + $this->request->expects($this->once()) + ->method('setUrl') + ->with($this->equalTo('https://example.com/files/token/nickname/folder/subfolder/file.txt')); + + $subfolder = $this->createMock(Folder::class); + $subfolder->expects(self::once()) + ->method('getNonExistingName') + ->with('file.txt') + ->willReturn('file.txt'); + $subfolder->expects(self::once()) + ->method('getPath') + ->willReturn('/files/token/nickname/folder/subfolder'); + + $folder = $this->createMock(Folder::class); + $folder->expects(self::once()) + ->method('get') + ->with('subfolder') + ->willReturn($subfolder); + + $nickname = $this->createMock(Folder::class); + $nickname->expects(self::once()) + ->method('get') + ->with('folder') + ->willReturn($folder); + + $this->node->method('get') + ->with('nickname') + ->willReturn($nickname); + $this->plugin->beforeMethod($this->request, $this->response); + } + + public function testOnMkcol(): void { + $this->plugin->enable(); + $this->plugin->setShare($this->share); + + $this->response->expects($this->once()) + ->method('setStatus') + ->with(201); + + $response = $this->plugin->onMkcol($this->request, $this->response); + $this->assertFalse($response); + } } |