createStub(IL10N::class); $trans->method("t")->willReturnCallback(vsprintf(...)); $this->l10nFactory = $this->createStub(IFactory::class); $this->l10nFactory->method("get")->willReturn($trans); $this->urlGenerator = $this->createStub(IURLGenerator::class); $this->urlGenerator->method("getAbsoluteURL")->willReturnArgument(0); $this->urlGenerator->method("imagePath")->willReturnCallback( fn($app, $img) => "/apps/$app/img/$img" ); $this->urlGenerator->method("linkToRouteAbsolute")->willReturn("https://example.com/editor"); $this->userManager = $this->createStub(IUserManager::class); $this->notifier = new Notifier( $this->appName, $this->l10nFactory, $this->urlGenerator, $this->createStub(LoggerInterface::class), $this->userManager, ); } private function makeNotification(string $objectType, string $objectId = "subject", array $parameters = []): INotification&MockObject { $action = $this->createMock(IAction::class); $action->method("setLabel")->willReturnSelf(); $action->method("setParsedLabel")->willReturnSelf(); $action->method("setLink")->willReturnSelf(); $action->method("setPrimary")->willReturnSelf(); $notification = $this->createMock(INotification::class); $notification->method("getApp")->willReturn($this->appName); $notification->method("getObjectType")->willReturn($objectType); $notification->method("getObjectId")->willReturn($objectId); $notification->method("getSubjectParameters")->willReturn($parameters); $notification->method("createAction")->willReturn($action); $notification->method("setParsedSubject")->willReturnSelf(); $notification->method("setParsedMessage")->willReturnSelf(); $notification->method("setIcon")->willReturnSelf(); $notification->method("setRichSubject")->willReturnSelf(); $notification->method("addParsedAction")->willReturnSelf(); return $notification; } /** * getID returns the app name. */ public function testGetIdReturnsAppName(): void { $this->assertSame($this->appName, $this->notifier->getID()); } /** * getName returns the app name. */ public function testGetNameReturnsAppName(): void { $this->assertSame($this->appName, $this->notifier->getName()); } /** * prepare throws UnknownNotificationException when the notification is from a different app. */ public function testPrepareThrowsForUnknownApp(): void { $notification = $this->createStub(INotification::class); $notification->method("getApp")->willReturn("other_app"); $this->expectException(UnknownNotificationException::class); $this->notifier->prepare($notification, "en"); } /** * Sets the notification subject to the object ID and a descriptive message for editorsCheck notifications. */ public function testPrepareEditorsCheckSetsParsedSubjectAndAction(): void { $notification = $this->makeNotification("editorsCheck", "Document server is not available"); $parsedSubject = ""; $parsedMessage = ""; $actionAdded = false; $notification->method("setParsedSubject")->willReturnCallback(function ($s) use ($notification, &$parsedSubject) { $parsedSubject = $s; return $notification; }); $notification->method("setParsedMessage")->willReturnCallback(function ($m) use ($notification, &$parsedMessage) { $parsedMessage = $m; return $notification; }); $notification->method("addParsedAction")->willReturnCallback(function () use ($notification, &$actionAdded) { $actionAdded = true; return $notification; }); $this->notifier->prepare($notification, "en"); $this->assertSame("Document server is not available", $parsedSubject); $this->assertNotEmpty($parsedMessage); $this->assertTrue($actionAdded); } /** * Sets a subject containing the notifier's display name and the file name for mention notifications. */ public function testPrepareMentionSetsSubjectWithNotifierAndFileName(): void { $user = $this->createStub(IUser::class); $user->method("getDisplayName")->willReturn("Jane Doe"); $this->userManager->method("get")->willReturn($user); $notification = $this->makeNotification("mention", "Comment text", [ "notifierId" => "janedoe", "fileId" => 42, "fileName" => "report.docx", "anchor" => "anchor1", ]); $parsedSubject = ""; $notification->method("setParsedSubject")->willReturnCallback(function ($s) use ($notification, &$parsedSubject) { $parsedSubject = $s; return $notification; }); $this->notifier->prepare($notification, "en"); $this->assertStringContainsString("Jane Doe", $parsedSubject); $this->assertStringContainsString("report.docx", $parsedSubject); } /** * Sets a subject containing the file name and adds an action for document_unsaved notifications. */ public function testPrepareDocumentUnsavedSetsParsedSubjectAndAction(): void { $notification = $this->makeNotification("document_unsaved", "doc-unsaved", [ "fileId" => 99, "fileName" => "draft.docx", ]); $parsedSubject = ""; $actionAdded = false; $notification->method("setParsedSubject")->willReturnCallback(function ($s) use ($notification, &$parsedSubject) { $parsedSubject = $s; return $notification; }); $notification->method("addParsedAction")->willReturnCallback(function () use ($notification, &$actionAdded) { $actionAdded = true; return $notification; }); $this->notifier->prepare($notification, "en"); $this->assertStringContainsString("draft.docx", $parsedSubject); $this->assertTrue($actionAdded); } /** * Returns the notification unchanged for an unknown object type. */ public function testPrepareReturnsNotificationForUnknownObjectType(): void { $notification = $this->makeNotification("unknown_type"); $result = $this->notifier->prepare($notification, "en"); $this->assertSame($notification, $result); } }