logger = $this->createMock(LoggerInterface::class); $this->shareManager = $this->createMock(IManager::class); $this->config = $this->createMock(IAppConfig::class); $this->appConfig = $this->createMock(AppConfig::class); $this->connection = $this->createMock(IDBConnection::class); $this->extraPermissions = new ExtraPermissions( $this->logger, $this->shareManager, $this->config, $this->appConfig, $this->connection, null, ); } private function stubDbEmpty(): void { $result = $this->createStub(IResult::class); $result->method("fetch")->willReturn(false); $statement = $this->createStub(IPreparedStatement::class); $statement->method("execute")->willReturn($result); $this->connection->method("prepare")->willReturn($statement); } private function makeShare( string $id, int $shareType, int $permissions, string $nodeName = "file.docx" ): IShare&MockObject { $node = $this->createStub(Node::class); $node->method("getName")->willReturn($nodeName); $share = $this->createMock(IShare::class); $share->method("getId")->willReturn($id); $share->method("getShareType")->willReturn($shareType); $share->method("getPermissions")->willReturn($permissions); $share->method("getNode")->willReturn($node); $share->method("getSharedWith")->willReturn("user1"); $share->method("getSharedWithDisplayName")->willReturn("User One"); return $share; } /** * Returns an empty array immediately when no shares are provided, without making any database calls. */ public function testGetExtrasReturnsEmptyArrayWhenNoSharesGiven(): void { $result = $this->extraPermissions->getExtras([]); $this->assertSame([], $result); } /** * Returns null when the share cannot be resolved by any provider, indicating the share does not exist. */ public function testGetExtraReturnsNullWhenShareNotFound(): void { $this->shareManager->method("getShareById")->willThrowException(new ShareNotFound()); $result = $this->extraPermissions->getExtra("nonexistent"); $this->assertNull($result); } /** * Returns null for non-link shares that carry PERMISSION_SHARE when resharing is enabled. */ public function testGetExtraReturnsNullWhenShareHasPermissionShareAndIsNotLink(): void { $share = $this->makeShare("1", IShare::TYPE_USER, Constants::PERMISSION_SHARE); $this->shareManager->method("getShareById")->willReturn($share); $this->config->method("getValueString")->willReturn('yes'); $this->stubDbEmpty(); $result = $this->extraPermissions->getExtra("1"); $this->assertNull($result); } /** * Returns extra permissions for a non-link share with PERMISSION_SHARE when the admin has * disabled resharing. */ public function testGetExtraReturnsExtraPermissionsWhenShareHasPermissionShareButResharingDisabled(): void { $share = $this->makeShare("9", IShare::TYPE_USER, Constants::PERMISSION_SHARE | Constants::PERMISSION_UPDATE, "file.docx"); $this->shareManager->method("getShareById")->willReturn($share); $this->config->method("getValueString")->willReturn('no'); $this->appConfig->method("formatsSetting")->willReturn([ "docx" => ["review" => true] ]); $this->stubDbEmpty(); $result = $this->extraPermissions->getExtra("9"); $this->assertNotNull($result); $this->assertSame(ExtraPermissions::REVIEW, $result["available"] & ExtraPermissions::REVIEW); } /** * Returns null when the shared file's extension is not registered in the format settings. */ public function testGetExtraReturnsNullWhenFileFormatIsUnknown(): void { $share = $this->makeShare("2", IShare::TYPE_LINK, Constants::PERMISSION_UPDATE, "file.xyz"); $this->shareManager->method("getShareById")->willReturn($share); $this->appConfig->method("formatsSetting")->willReturn([]); $this->stubDbEmpty(); $result = $this->extraPermissions->getExtra("2"); $this->assertNull($result); } /** * Sets the REVIEW bit in the available permissions bitmask when the file format declares review support. */ public function testGetExtraReturnsAvailableReviewForReviewCapableFormat(): void { $share = $this->makeShare("3", IShare::TYPE_LINK, Constants::PERMISSION_UPDATE, "file.docx"); $this->shareManager->method("getShareById")->willReturn($share); $this->appConfig->method("formatsSetting")->willReturn([ "docx" => ["review" => true] ]); $this->stubDbEmpty(); $result = $this->extraPermissions->getExtra("3"); $this->assertNotNull($result); $this->assertSame(ExtraPermissions::REVIEW, $result["available"] & ExtraPermissions::REVIEW); } /** * Makes the COMMENT bit available when the format supports comments and REVIEW is not set on the share. */ public function testGetExtraReturnsAvailableCommentWhenReviewNotChecked(): void { $share = $this->makeShare("4", IShare::TYPE_LINK, Constants::PERMISSION_UPDATE, "file.docx"); $this->shareManager->method("getShareById")->willReturn($share); $this->appConfig->method("formatsSetting")->willReturn([ "docx" => ["comment" => true] ]); $this->stubDbEmpty(); $result = $this->extraPermissions->getExtra("4"); $this->assertNotNull($result); $this->assertSame(ExtraPermissions::COMMENT, $result["available"] & ExtraPermissions::COMMENT); } /** * Makes the FILLFORMS bit available when the format supports form filling and REVIEW is not set on the share. */ public function testGetExtraReturnsAvailableFillFormsWhenReviewNotChecked(): void { $share = $this->makeShare("5", IShare::TYPE_LINK, Constants::PERMISSION_UPDATE, "file.pdf"); $this->shareManager->method("getShareById")->willReturn($share); $this->appConfig->method("formatsSetting")->willReturn([ "pdf" => ["fillForms" => true] ]); $this->stubDbEmpty(); $result = $this->extraPermissions->getExtra("5"); $this->assertNotNull($result); $this->assertSame(ExtraPermissions::FILLFORMS, $result["available"] & ExtraPermissions::FILLFORMS); } /** * Makes the MODIFYFILTER bit available when the format supports it and COMMENT is not set on the share. */ public function testGetExtraReturnsAvailableModifyFilterWhenCommentNotSet(): void { $share = $this->makeShare("6", IShare::TYPE_LINK, Constants::PERMISSION_UPDATE, "file.xlsx"); $this->shareManager->method("getShareById")->willReturn($share); $this->appConfig->method("formatsSetting")->willReturn([ "xlsx" => ["modifyFilter" => true] ]); $this->stubDbEmpty(); $result = $this->extraPermissions->getExtra("6"); $this->assertNotNull($result); $this->assertSame(ExtraPermissions::MODIFYFILTER, $result["available"] & ExtraPermissions::MODIFYFILTER); } /** * Seeds the result with id=-1 and the share id when no extra permissions row exists in the database. */ public function testGetExtraInitialisesDefaultsWhenNoExtraStored(): void { $share = $this->makeShare("7", IShare::TYPE_LINK, Constants::PERMISSION_UPDATE, "file.docx"); $this->shareManager->method("getShareById")->willReturn($share); $this->appConfig->method("formatsSetting")->willReturn([ "docx" => ["review" => true] ]); $this->stubDbEmpty(); $result = $this->extraPermissions->getExtra("7"); $this->assertNotNull($result); $this->assertSame(-1, $result["id"]); $this->assertSame("7", $result["share_id"]); } /** * Enriches the result with share metadata (type, shareWith, shareWithName) to avoid re-fetching the share. */ public function testGetExtraIncludesShareMetadataInResult(): void { $share = $this->makeShare("8", IShare::TYPE_LINK, Constants::PERMISSION_UPDATE, "file.docx"); $this->shareManager->method("getShareById")->willReturn($share); $this->appConfig->method("formatsSetting")->willReturn([ "docx" => ["review" => true] ]); $this->stubDbEmpty(); $result = $this->extraPermissions->getExtra("8"); $this->assertSame(IShare::TYPE_LINK, $result["type"]); $this->assertSame("user1", $result["shareWith"]); $this->assertSame("User One", $result["shareWithName"]); } }