From e40d6b1c6b76e345ec9500cb23cf5475ffbb2773 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Thu, 12 Feb 2026 12:05:11 +0100 Subject: [PATCH] refactor(dav): Modernize Node Signed-off-by: provokateurin --- apps/dav/lib/Connector/Sabre/FilesPlugin.php | 5 - apps/dav/lib/Connector/Sabre/Node.php | 178 +++++++++--------- apps/dav/lib/Files/FilesHome.php | 4 +- .../Sabre/CommentsPropertiesPluginTest.php | 10 +- .../unit/Connector/Sabre/DirectoryTest.php | 23 ++- .../tests/unit/Connector/Sabre/FileTest.php | 16 ++ .../unit/Connector/Sabre/FilesPluginTest.php | 48 +---- .../Connector/Sabre/FilesReportPluginTest.php | 8 +- .../tests/unit/Connector/Sabre/NodeTest.php | 25 +++ .../unit/Connector/Sabre/ObjectTreeTest.php | 12 ++ build/psalm-baseline.xml | 9 - build/rector-strict.php | 1 + psalm-strict.xml | 6 + 13 files changed, 182 insertions(+), 163 deletions(-) diff --git a/apps/dav/lib/Connector/Sabre/FilesPlugin.php b/apps/dav/lib/Connector/Sabre/FilesPlugin.php index 7b2f144dfa1..83ec30e0893 100644 --- a/apps/dav/lib/Connector/Sabre/FilesPlugin.php +++ b/apps/dav/lib/Connector/Sabre/FilesPlugin.php @@ -166,11 +166,6 @@ class FilesPlugin extends ServerPlugin { return; } - // Ensure source exists - $sourceNodeFileInfo = $sourceNode->getFileInfo(); - if ($sourceNodeFileInfo === null) { - throw new NotFound($source . ' does not exist'); - } // Ensure the target name is valid try { [$targetPath, $targetName] = \Sabre\Uri\split($target); diff --git a/apps/dav/lib/Connector/Sabre/Node.php b/apps/dav/lib/Connector/Sabre/Node.php index 14ac7063ace..1feac9839df 100644 --- a/apps/dav/lib/Connector/Sabre/Node.php +++ b/apps/dav/lib/Connector/Sabre/Node.php @@ -1,5 +1,7 @@ path = $this->fileView->getRelativePath($info->getPath()); - $this->info = $info; - if ($shareManager) { - $this->shareManager = $shareManager; - } else { - $this->shareManager = Server::get(\OCP\Share\IManager::class); + $relativePath = $this->fileView->getRelativePath($info->getPath()); + if ($relativePath === null) { + throw new RuntimeException('Failed to get relative path for ' . $info->getPath()); } + + $this->path = $relativePath; + $this->info = $info; + $this->shareManager = $shareManager instanceof IManager ? $shareManager : Server::get(IManager::class); + if ($info instanceof Folder || $info instanceof File) { $this->node = $info; } else { @@ -70,11 +78,16 @@ abstract class Node implements \Sabre\DAV\INode { } } + /** + * @throws Exception + * @throws PreConditionNotMetException + */ protected function refreshInfo(): void { $info = $this->fileView->getFileInfo($this->path); if ($info === false) { - throw new \Sabre\DAV\Exception('Failed to get fileinfo for ' . $this->path); + throw new Exception('Failed to get fileinfo for ' . $this->path); } + $this->info = $info; $root = Server::get(IRootFolder::class); $rootView = Server::get(View::class); @@ -87,19 +100,15 @@ abstract class Node implements \Sabre\DAV\INode { /** * Returns the name of the node - * - * @return string */ - public function getName() { + public function getName(): string { return $this->info->getName(); } /** * Returns the full path - * - * @return string */ - public function getPath() { + public function getPath(): string { return $this->path; } @@ -107,25 +116,30 @@ abstract class Node implements \Sabre\DAV\INode { * Renames the node * * @param string $name The new name - * @throws \Sabre\DAV\Exception\BadRequest - * @throws \Sabre\DAV\Exception\Forbidden + * @throws Exception + * @throws Forbidden + * @throws InvalidPath + * @throws PreConditionNotMetException + * @throws LockedException */ - public function setName($name) { + public function setName($name): void { // rename is only allowed if the delete privilege is granted // (basically rename is a copy with delete of the original node) - if (!($this->info->isDeletable() || ($this->info->getMountPoint() instanceof MoveableMount && $this->info->getInternalPath() === ''))) { - throw new \Sabre\DAV\Exception\Forbidden(); + if (!$this->info->isDeletable() && !($this->info->getMountPoint() instanceof MoveableMount && $this->info->getInternalPath() === '')) { + throw new Forbidden(); } + /** @var string $parentPath */ [$parentPath,] = \Sabre\Uri\split($this->path); + /** @var string $newName */ [, $newName] = \Sabre\Uri\split($name); $newPath = $parentPath . '/' . $newName; // verify path of the target $this->verifyPath($newPath); - if (!$this->fileView->rename($this->path, $newPath)) { - throw new \Sabre\DAV\Exception('Failed to rename ' . $this->path . ' to ' . $newPath); + if ($this->fileView->rename($this->path, $newPath) === false) { + throw new Exception('Failed to rename ' . $this->path . ' to ' . $newPath); } $this->path = $newPath; @@ -138,12 +152,8 @@ abstract class Node implements \Sabre\DAV\INode { * * @return int timestamp as integer */ - public function getLastModified() { - $timestamp = $this->info->getMtime(); - if (!empty($timestamp)) { - return (int)$timestamp; - } - return $timestamp; + public function getLastModified(): int { + return $this->info->getMtime(); } /** @@ -151,7 +161,7 @@ abstract class Node implements \Sabre\DAV\INode { * in the second parameter or to now if the second param is empty. * Even if the modification time is set to a custom value the access time is set to now. */ - public function touch($mtime) { + public function touch(string $mtime): void { $mtime = $this->sanitizeMtime($mtime); $this->fileView->touch($this->path, $mtime); $this->refreshInfo(); @@ -165,37 +175,29 @@ abstract class Node implements \Sabre\DAV\INode { * arbitrary string, but MUST be surrounded by double-quotes. * * Return null if the ETag can not effectively be determined - * - * @return string */ - public function getETag() { + public function getETag(): string { return '"' . $this->info->getEtag() . '"'; } /** * Sets the ETag * - * @param string $etag - * * @return int file id of updated file or -1 on failure */ - public function setETag($etag) { + public function setETag(string $etag): int { return $this->fileView->putFileInfo($this->path, ['etag' => $etag]); } - public function setCreationTime(int $time) { + public function setCreationTime(int $time): int { return $this->fileView->putFileInfo($this->path, ['creation_time' => $time]); } - public function setUploadTime(int $time) { - return $this->fileView->putFileInfo($this->path, ['upload_time' => $time]); - } - /** * Returns the size of the node, in bytes * + * @psalm-suppress UnusedPsalmSuppress psalm:strict actually thinks there is no mismatch, idk lol * @psalm-suppress ImplementedReturnTypeMismatch \Sabre\DAV\IFile::getSize signature does not support 32bit - * @return int|float */ public function getSize(): int|float { return $this->info->getSize(); @@ -203,28 +205,21 @@ abstract class Node implements \Sabre\DAV\INode { /** * Returns the cache's file id - * - * @return int */ - public function getId() { + public function getId(): ?int { return $this->info->getId(); } - /** - * @return string|null - */ - public function getFileId() { - if ($id = $this->info->getId()) { + public function getFileId(): ?string { + $id = $this->info->getId(); + if ($id !== null) { return DavUtil::getDavFileId($id); } return null; } - /** - * @return integer - */ - public function getInternalFileId() { + public function getInternalFileId(): ?int { return $this->info->getId(); } @@ -232,30 +227,24 @@ abstract class Node implements \Sabre\DAV\INode { return $this->info->getInternalPath(); } - /** - * @param string $user - * @return int - */ - public function getSharePermissions($user) { + public function getSharePermissions(?string $user): int { // check of we access a federated share if ($user !== null) { try { - $share = $this->shareManager->getShareByToken($user); - return $share->getPermissions(); - } catch (ShareNotFound $e) { + return $this->shareManager->getShareByToken($user)->getPermissions(); + } catch (ShareNotFound) { // ignore } } try { $storage = $this->info->getStorage(); - } catch (StorageNotAvailableException $e) { + } catch (StorageNotAvailableException) { $storage = null; } if ($storage && $storage->instanceOfStorage(ISharedStorage::class)) { - /** @var ISharedStorage $storage */ - $permissions = (int)$storage->getShare()->getPermissions(); + $permissions = $storage->getShare()->getPermissions(); } else { $permissions = $this->info->getPermissions(); } @@ -266,6 +255,10 @@ abstract class Node implements \Sabre\DAV\INode { */ $mountpoint = $this->info->getMountPoint(); if (!($mountpoint instanceof MoveableMount)) { + /** + * @psalm-suppress UnnecessaryVarAnnotation Rector doesn't trust the return type annotation + * @var string $mountpointpath + */ $mountpointpath = $mountpoint->getMountPoint(); if (str_ends_with($mountpointpath, '/')) { $mountpointpath = substr($mountpointpath, 0, -1); @@ -286,25 +279,21 @@ abstract class Node implements \Sabre\DAV\INode { return $permissions; } - /** - * @return array - */ public function getShareAttributes(): array { try { $storage = $this->node->getStorage(); - } catch (NotFoundException $e) { + } catch (NotFoundException) { return []; } $attributes = []; if ($storage->instanceOfStorage(ISharedStorage::class)) { - /** @var ISharedStorage $storage */ $attributes = $storage->getShare()->getAttributes(); if ($attributes === null) { return []; - } else { - return $attributes->toArray(); } + + return $attributes->toArray(); } return $attributes; @@ -318,63 +307,66 @@ abstract class Node implements \Sabre\DAV\INode { } if ($storage->instanceOfStorage(ISharedStorage::class)) { - /** @var ISharedStorage $storage */ $share = $storage->getShare(); if ($user === $share->getShareOwner()) { // Note is only for recipient not the owner return null; } + return $share->getNote(); } return null; } - /** - * @return string - */ - public function getDavPermissions() { + public function getDavPermissions(): string { return DavUtil::getDavPermissions($this->info); } - public function getOwner() { + public function getOwner(): ?IUser { return $this->info->getOwner(); } + /** + * @throws InvalidPath + */ protected function verifyPath(?string $path = null): void { try { - $path = $path ?? $this->info->getPath(); + $path ??= $this->info->getPath(); $this->fileView->verifyPath( dirname($path), basename($path), ); - } catch (InvalidPathException $ex) { - throw new InvalidPath($ex->getMessage()); + } catch (InvalidPathException $invalidPathException) { + throw new InvalidPath($invalidPathException->getMessage(), false, $invalidPathException); } } /** - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @param ILockingProvider::LOCK_* $type + * @throws LockedException */ - public function acquireLock($type) { + public function acquireLock($type): void { $this->fileView->lockFile($this->path, $type); } /** - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @param ILockingProvider::LOCK_* $type + * @throws LockedException */ - public function releaseLock($type) { + public function releaseLock($type): void { $this->fileView->unlockFile($this->path, $type); } /** - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @param ILockingProvider::LOCK_* $type + * @throws LockedException */ - public function changeLock($type) { + public function changeLock($type): void { $this->fileView->changeLock($this->path, $type); } - public function getFileInfo() { + public function getFileInfo(): FileInfo { return $this->info; } diff --git a/apps/dav/lib/Files/FilesHome.php b/apps/dav/lib/Files/FilesHome.php index f8aa82cdcc9..ab3a9b68c13 100644 --- a/apps/dav/lib/Files/FilesHome.php +++ b/apps/dav/lib/Files/FilesHome.php @@ -32,12 +32,12 @@ class FilesHome extends Directory { throw new Forbidden('Permission denied to delete home folder'); } - public function getName() { + public function getName(): string { [,$name] = \Sabre\Uri\split($this->principalInfo['uri']); return $name; } - public function setName($name) { + public function setName($name): void { throw new Forbidden('Permission denied to rename this folder'); } } diff --git a/apps/dav/tests/unit/Connector/Sabre/CommentsPropertiesPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/CommentsPropertiesPluginTest.php index f89e8e06542..e3f296353e3 100644 --- a/apps/dav/tests/unit/Connector/Sabre/CommentsPropertiesPluginTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/CommentsPropertiesPluginTest.php @@ -61,14 +61,14 @@ class CommentsPropertiesPluginTest extends \Test\TestCase { public static function baseUriProvider(): array { return [ - ['owncloud/remote.php/webdav/', '4567', 'owncloud/remote.php/dav/comments/files/4567'], - ['owncloud/remote.php/files/', '4567', 'owncloud/remote.php/dav/comments/files/4567'], - ['owncloud/wicked.php/files/', '4567', null] + ['owncloud/remote.php/webdav/', 4567, 'owncloud/remote.php/dav/comments/files/4567'], + ['owncloud/remote.php/files/', 4567, 'owncloud/remote.php/dav/comments/files/4567'], + ['owncloud/wicked.php/files/', 4567, null] ]; } #[\PHPUnit\Framework\Attributes\DataProvider(methodName: 'baseUriProvider')] - public function testGetCommentsLink(string $baseUri, string $fid, ?string $expectedHref): void { + public function testGetCommentsLink(string $baseUri, int $fid, ?string $expectedHref): void { $node = $this->createMock(File::class); $node->expects($this->any()) ->method('getId') @@ -94,7 +94,7 @@ class CommentsPropertiesPluginTest extends \Test\TestCase { $node = $this->createMock(File::class); $node->expects($this->any()) ->method('getId') - ->willReturn('4567'); + ->willReturn(4567); if ($user !== null) { $user = $this->createMock($user); diff --git a/apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php b/apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php index 4144c79821e..4fe6dd88ad9 100644 --- a/apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php @@ -230,6 +230,10 @@ class DirectoryTest extends \Test\TestCase { $info->expects($this->any()) ->method('isReadable') ->willReturn(false); + $this->view + ->method('getRelativePath') + ->with(null) + ->willReturn(''); $dir = new Directory($this->view, $info); $dir->getChildren(); @@ -242,6 +246,10 @@ class DirectoryTest extends \Test\TestCase { $this->info->expects($this->any()) ->method('isReadable') ->willReturn(false); + $this->view + ->method('getRelativePath') + ->with('/admin/files/folder') + ->willReturn(''); $dir = new Directory($this->view, $this->info); $dir->getChild('test'); @@ -254,6 +262,10 @@ class DirectoryTest extends \Test\TestCase { $this->view->expects($this->once()) ->method('getFileInfo') ->willThrowException(new StorageNotAvailableException()); + $this->view + ->method('getRelativePath') + ->with('/admin/files/folder') + ->willReturn(''); $dir = new Directory($this->view, $this->info); $dir->getChild('.'); @@ -268,6 +280,10 @@ class DirectoryTest extends \Test\TestCase { ->willThrowException(new InvalidPathException()); $this->view->expects($this->never()) ->method('getFileInfo'); + $this->view + ->method('getRelativePath') + ->with('/admin/files/folder') + ->willReturn(''); $dir = new Directory($this->view, $this->info); $dir->getChild('.'); @@ -376,6 +392,11 @@ class DirectoryTest extends \Test\TestCase { } public function testGetNodeForPathFailsWithNoReadPermissionsForPath(): void { + $this->view + ->method('getRelativePath') + ->with('/admin/files/') + ->willReturn(''); + $directoryNode = $this->createMock(Folder::class); $pathNode = $this->createMock(Folder::class); $storage = $this->createMock(IStorage::class); @@ -396,7 +417,7 @@ class DirectoryTest extends \Test\TestCase { 2 => false, }; }); - $directoryNode->expects($this->once()) + $directoryNode ->method('getPath') ->willReturn('/admin/files/'); $directoryNode->expects($this->once()) diff --git a/apps/dav/tests/unit/Connector/Sabre/FileTest.php b/apps/dav/tests/unit/Connector/Sabre/FileTest.php index 8c5b04486dd..a5ea180e873 100644 --- a/apps/dav/tests/unit/Connector/Sabre/FileTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/FileTest.php @@ -673,6 +673,10 @@ class FileTest extends TestCase { /** @var View&MockObject */ $view = $this->getMockBuilder(View::class) ->getMock(); + $view + ->method('getRelativePath') + ->with('/test.txt') + ->willReturn(''); $view->expects($this->once()) ->method('unlink') @@ -697,6 +701,10 @@ class FileTest extends TestCase { /** @var View&MockObject */ $view = $this->getMockBuilder(View::class) ->getMock(); + $view + ->method('getRelativePath') + ->with('/test.txt') + ->willReturn(''); $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [ 'permissions' => 0, @@ -717,6 +725,10 @@ class FileTest extends TestCase { /** @var View&MockObject */ $view = $this->getMockBuilder(View::class) ->getMock(); + $view + ->method('getRelativePath') + ->with('/test.txt') + ->willReturn(''); // but fails $view->expects($this->once()) @@ -742,6 +754,10 @@ class FileTest extends TestCase { /** @var View&MockObject */ $view = $this->getMockBuilder(View::class) ->getMock(); + $view + ->method('getRelativePath') + ->with('/test.txt') + ->willReturn(''); // but fails $view->expects($this->once()) diff --git a/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php index 6e2d5557626..a5a8358d61f 100644 --- a/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php @@ -101,7 +101,7 @@ class FilesPluginTest extends TestCase { ->willReturn('00000123instanceid'); $node->expects($this->any()) ->method('getInternalFileId') - ->willReturn('123'); + ->willReturn(123); $node->expects($this->any()) ->method('getEtag') ->willReturn('"abc"'); @@ -455,7 +455,7 @@ class FilesPluginTest extends TestCase { $node->expects($this->once()) ->method('setEtag') ->with('newetag') - ->willReturn(true); + ->willReturn(123); $node->expects($this->once()) ->method('setCreationTime') @@ -562,35 +562,11 @@ class FilesPluginTest extends TestCase { $this->plugin->checkMove('FolderA/test.txt', 'test.txt'); } - public function testMoveSrcNotExist(): void { - $this->expectException(\Sabre\DAV\Exception\NotFound::class); - $this->expectExceptionMessage('FolderA/test.txt does not exist'); - - $node = $this->createMock(Node::class); - $node->expects($this->atLeastOnce()) - ->method('getFileInfo') - ->willReturn(null); - - $this->tree->expects($this->atLeastOnce()) - ->method('getNodeForPath') - ->willReturn($node); - - $this->plugin->checkMove('FolderA/test.txt', 'test.txt'); - } - public function testMoveDestinationInvalid(): void { $this->expectException(InvalidPath::class); $this->expectExceptionMessage('Mocked exception'); - $fileInfoFolderATestTXT = $this->createMock(FileInfo::class); - $fileInfoFolderATestTXT->expects(self::any()) - ->method('isDeletable') - ->willReturn(true); - $node = $this->createMock(Node::class); - $node->expects($this->atLeastOnce()) - ->method('getFileInfo') - ->willReturn($fileInfoFolderATestTXT); $this->tree->expects($this->atLeastOnce()) ->method('getNodeForPath') @@ -604,31 +580,11 @@ class FilesPluginTest extends TestCase { $this->plugin->checkMove('FolderA/test.txt', 'invalid\\path.txt'); } - public function testCopySrcNotExist(): void { - $this->expectException(\Sabre\DAV\Exception\NotFound::class); - $this->expectExceptionMessage('FolderA/test.txt does not exist'); - - $node = $this->createMock(Node::class); - $node->expects($this->atLeastOnce()) - ->method('getFileInfo') - ->willReturn(null); - - $this->tree->expects($this->atLeastOnce()) - ->method('getNodeForPath') - ->willReturn($node); - - $this->plugin->checkCopy('FolderA/test.txt', 'test.txt'); - } - public function testCopyDestinationInvalid(): void { $this->expectException(InvalidPath::class); $this->expectExceptionMessage('Mocked exception'); - $fileInfoFolderATestTXT = $this->createMock(FileInfo::class); $node = $this->createMock(Node::class); - $node->expects($this->atLeastOnce()) - ->method('getFileInfo') - ->willReturn($fileInfoFolderATestTXT); $this->tree->expects($this->atLeastOnce()) ->method('getNodeForPath') diff --git a/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php index 9c408c55e28..717cecda758 100644 --- a/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php @@ -57,6 +57,10 @@ class FilesReportPluginTest extends \Test\TestCase { $this->tree = $this->createMock(Tree::class); $this->view = $this->createMock(View::class); + $this->view + ->method('getRelativePath') + ->with(null) + ->willReturn(''); $this->server = $this->getMockBuilder(Server::class) ->setConstructorArgs([$this->tree]) @@ -315,14 +319,14 @@ class FilesReportPluginTest extends \Test\TestCase { $node1->expects($this->once()) ->method('getInternalFileId') - ->willReturn('111'); + ->willReturn(111); $node1->expects($this->any()) ->method('getPath') ->willReturn('/node1'); $node1->method('getFileInfo')->willReturn($fileInfo); $node2->expects($this->once()) ->method('getInternalFileId') - ->willReturn('222'); + ->willReturn(222); $node2->expects($this->once()) ->method('getSize') ->willReturn(1024); diff --git a/apps/dav/tests/unit/Connector/Sabre/NodeTest.php b/apps/dav/tests/unit/Connector/Sabre/NodeTest.php index 896f36f1253..80e30d29d94 100644 --- a/apps/dav/tests/unit/Connector/Sabre/NodeTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/NodeTest.php @@ -94,6 +94,10 @@ class NodeTest extends \Test\TestCase { $info->method('getStorage') ->willReturn($storage); $view = $this->createMock(View::class); + $view + ->method('getRelativePath') + ->with(null) + ->willReturn(''); $node = new File($view, $info); $this->assertEquals($expected, $node->getDavPermissions()); @@ -169,6 +173,10 @@ class NodeTest extends \Test\TestCase { $info->method('getPermissions')->willReturn($permissions); $view = $this->createMock(View::class); + $view + ->method('getRelativePath') + ->with(null) + ->willReturn(''); $node = new File($view, $info); $this->invokePrivate($node, 'shareManager', [$shareManager]); @@ -204,6 +212,10 @@ class NodeTest extends \Test\TestCase { /** @var View&MockObject $view */ $view = $this->createMock(View::class); + $view + ->method('getRelativePath') + ->with(null) + ->willReturn(''); $node = new File($view, $info); $this->invokePrivate($node, 'shareManager', [$shareManager]); @@ -225,6 +237,10 @@ class NodeTest extends \Test\TestCase { /** @var View&MockObject */ $view = $this->createMock(View::class); + $view + ->method('getRelativePath') + ->with(null) + ->willReturn(''); $node = new File($view, $info); $this->invokePrivate($node, 'shareManager', [$shareManager]); @@ -243,6 +259,10 @@ class NodeTest extends \Test\TestCase { $view = $this->getMockBuilder(View::class) ->disableOriginalConstructor() ->getMock(); + $view + ->method('getRelativePath') + ->with(null) + ->willReturn(''); $info = $this->getMockBuilder(FileInfo::class) ->disableOriginalConstructor() ->getMock(); @@ -263,6 +283,11 @@ class NodeTest extends \Test\TestCase { $this->expectException(\InvalidArgumentException::class); $view = $this->createMock(View::class); + $view + ->method('getRelativePath') + ->with(null) + ->willReturn(''); + $info = $this->createMock(FileInfo::class); $node = new File($view, $info); diff --git a/apps/dav/tests/unit/Connector/Sabre/ObjectTreeTest.php b/apps/dav/tests/unit/Connector/Sabre/ObjectTreeTest.php index fbbda7deffb..d46232e34ad 100644 --- a/apps/dav/tests/unit/Connector/Sabre/ObjectTreeTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/ObjectTreeTest.php @@ -63,6 +63,10 @@ class ObjectTreeTest extends \Test\TestCase { ->method('getFileInfo') ->with($targetParent === '' ? '.' : $targetParent) ->willReturn($info); + $view + ->method('getRelativePath') + ->with(null) + ->willReturn(''); $rootDir = new Directory($view, $info); $objectTree = $this->getMockBuilder(ObjectTree::class) @@ -104,6 +108,10 @@ class ObjectTreeTest extends \Test\TestCase { ->method('getFileInfo') ->with($targetParent === '' ? '.' : $targetParent) ->willReturn($info); + $view + ->method('getRelativePath') + ->with(null) + ->willReturn(''); $rootDir = new Directory($view, $info); $objectTree = $this->getMockBuilder(ObjectTree::class) @@ -141,6 +149,10 @@ class ObjectTreeTest extends \Test\TestCase { $view->method('getFileInfo') ->with($fileInfoQueryPath) ->willReturn($fileInfo); + $view + ->method('getRelativePath') + ->with(null) + ->willReturn(''); $tree = new ObjectTree(); $tree->init($rootNode, $view, $mountManager); diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml index 1163db1d930..4faa60b4a1b 100644 --- a/build/psalm-baseline.xml +++ b/build/psalm-baseline.xml @@ -616,20 +616,11 @@ - - - - - - - info->getId()]]> - info->getId()]]> - diff --git a/build/rector-strict.php b/build/rector-strict.php index 529eace3b67..10d3f34a5aa 100644 --- a/build/rector-strict.php +++ b/build/rector-strict.php @@ -12,6 +12,7 @@ return (require __DIR__ . '/rector-shared.php') $nextcloudDir . '/build/rector-strict.php', $nextcloudDir . '/core/BackgroundJobs/ExpirePreviewsJob.php', $nextcloudDir . '/lib/public/IContainer.php', + $nextcloudDir . '/apps/dav/lib/Connector/Sabre/Node.php', ]) ->withPreparedSets( deadCode: true, diff --git a/psalm-strict.xml b/psalm-strict.xml index 01e6e3a579e..5e57d683b09 100644 --- a/psalm-strict.xml +++ b/psalm-strict.xml @@ -18,6 +18,7 @@ + @@ -27,8 +28,13 @@ + + + + +