nextcloud/apps/profile/tests/Reference/ProfilePickerReferenceProviderTest.php
Julien Veyssier ee44591509
feat(profile-picker): adjust tests
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
2026-02-23 15:29:27 +01:00

385 lines
13 KiB
PHP

<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Profile\Reference;
use OCP\Accounts\IAccount;
use OCP\Accounts\IAccountManager;
use OCP\Accounts\IAccountProperty;
use OCP\Collaboration\Reference\IReference;
use OCP\Collaboration\Reference\Reference;
use OCP\IAppConfig;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Profile\IProfileManager;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
class ProfilePickerReferenceProviderTest extends \Test\TestCase {
private string $userId = 'admin';
private IUser|MockObject $adminUser;
private IL10N|MockObject $l10n;
private IURLGenerator|MockObject $urlGenerator;
private IUserManager|MockObject $userManager;
private IAccountManager|MockObject $accountManager;
private IProfileManager|MockObject $profileManager;
private IAppConfig|MockObject $appConfig;
private ProfilePickerReferenceProvider $referenceProvider;
private array $testUsersData = [
'user1' => [
'user_id' => 'user1',
'displayname' => 'First User',
'email' => 'user1@domain.co',
'avatarurl' => 'https://nextcloud.local/index.php/avatar/user1/64',
],
'user2' => [
'user_id' => 'user2',
'displayname' => 'Second User',
'email' => 'user2@domain.co',
'avatarurl' => 'https://nextcloud.local/index.php/avatar/user2/64',
],
'user3' => null,
];
private array $testAccountsData = [
'user1' => [
IAccountManager::PROPERTY_BIOGRAPHY => [
'scope' => IAccountManager::SCOPE_PRIVATE,
'visible' => true,
'value' => 'This is a first test user',
],
IAccountManager::PROPERTY_HEADLINE => [
'scope' => IAccountManager::SCOPE_LOCAL,
'visible' => false,
'value' => 'I\'m a first test user',
],
IAccountManager::PROPERTY_ADDRESS => [
'scope' => IAccountManager::SCOPE_LOCAL,
'visible' => true,
'value' => 'Odessa',
],
IAccountManager::PROPERTY_WEBSITE => [
'scope' => IAccountManager::SCOPE_LOCAL,
'visible' => true,
'value' => 'https://domain.co/testuser1',
],
IAccountManager::PROPERTY_ORGANISATION => [
'scope' => IAccountManager::SCOPE_PRIVATE,
'visible' => true,
'value' => 'Nextcloud GmbH',
],
IAccountManager::PROPERTY_ROLE => [
'scope' => IAccountManager::SCOPE_LOCAL,
'visible' => true,
'value' => 'Non-existing user',
],
IAccountManager::PROPERTY_PROFILE_ENABLED => [
'scope' => IAccountManager::SCOPE_LOCAL,
'visible' => true,
'value' => '1',
],
],
'user2' => [
IAccountManager::PROPERTY_BIOGRAPHY => [
'scope' => IAccountManager::SCOPE_LOCAL,
'visible' => true,
'value' => 'This is a test user',
],
IAccountManager::PROPERTY_HEADLINE => [
'scope' => IAccountManager::SCOPE_LOCAL,
'visible' => true,
'value' => 'Second test user',
],
IAccountManager::PROPERTY_ADDRESS => [
'scope' => IAccountManager::SCOPE_LOCAL,
'visible' => true,
'value' => 'Berlin',
],
IAccountManager::PROPERTY_WEBSITE => [
'scope' => IAccountManager::SCOPE_LOCAL,
'visible' => true,
'value' => 'https://domain.co/testuser2',
],
IAccountManager::PROPERTY_ORGANISATION => [
'scope' => IAccountManager::SCOPE_PRIVATE,
'visible' => true,
'value' => 'Nextcloud GmbH',
],
IAccountManager::PROPERTY_ROLE => [
'scope' => IAccountManager::SCOPE_LOCAL,
'visible' => true,
'value' => 'Non-existing user',
],
IAccountManager::PROPERTY_PROFILE_ENABLED => [
'scope' => IAccountManager::SCOPE_LOCAL,
'visible' => true,
'value' => '1',
],
],
'user3' => null,
];
private string $baseUrl = 'https://nextcloud.local';
private string $testLink = 'https://nextcloud.local/index.php/u/user';
private array $testLinks = [
'user1' => 'https://nextcloud.local/index.php/u/user1',
'user2' => 'https://nextcloud.local/index.php/u/user2',
'user4' => 'https://nextcloud.local/index.php/u/user4',
];
public function setUp(): void {
parent::setUp();
$this->l10n = $this->createMock(IL10N::class);
$this->urlGenerator = $this->createMock(IURLGenerator::class);
$this->userManager = $this->createMock(IUserManager::class);
$this->accountManager = $this->createMock(IAccountManager::class);
$this->profileManager = $this->createMock(IProfileManager::class);
$this->appConfig = $this->createMock(IAppConfig::class);
$this->urlGenerator->expects($this->any())
->method('getBaseUrl')
->willReturn($this->baseUrl);
$this->profileManager->expects($this->any())
->method('isProfileEnabled')
->willReturn(true);
$this->appConfig->expects($this->any())
->method('getValueString')
->willReturn('1');
$this->profileManager->expects($this->any())
->method('isProfileFieldVisible')
->willReturnCallback(function (string $profileField, IUser $targetUser, ?IUser $visitingUser) {
return $this->testAccountsData[$targetUser->getUID()][$profileField]['visible']
&& $this->testAccountsData[$targetUser->getUID()][$profileField]['scope'] !== IAccountManager::SCOPE_PRIVATE;
});
$this->adminUser = $this->createMock(IUser::class);
$this->adminUser->expects($this->any())
->method('getUID')
->willReturn('admin');
$this->adminUser->expects($this->any())
->method('getDisplayName')
->willReturn('admin');
$this->referenceProvider = new ProfilePickerReferenceProvider(
$this->l10n,
$this->urlGenerator,
$this->userManager,
$this->accountManager,
$this->profileManager,
$this->appConfig,
$this->userId
);
}
private function getTestAccountPropertyValue(string $testUserId, string $property): mixed {
if (!$this->testAccountsData[$testUserId][$property]['visible']
|| $this->testAccountsData[$testUserId][$property]['scope'] === IAccountManager::SCOPE_PRIVATE) {
return null;
}
return $this->testAccountsData[$testUserId][$property]['value'];
}
/**
* @param string $userId
* @return IReference|null
*/
private function setupUserAccountReferenceExpectation(string $userId): ?IReference {
$user = $this->createMock(IUser::class);
if (isset($this->testUsersData[$userId])) {
// setup user expectations
$user->expects($this->any())
->method('getUID')
->willReturn($this->testUsersData[$userId]['user_id']);
$user->expects($this->any())
->method('getDisplayName')
->willReturn($this->testUsersData[$userId]['displayname']);
$user->expects($this->any())
->method('getEMailAddress')
->willReturn($this->testUsersData[$userId]['email']);
$this->userManager->expects($this->any())
->method('get')
->willReturnCallback(function (string $uid) use ($user, $userId) {
if ($uid === $userId) {
return $user;
} elseif ($uid === 'admin') {
return $this->adminUser;
}
return null;
});
// setup account expectations
$account = $this->createMock(IAccount::class);
$account->expects($this->any())
->method('getProperty')
->willReturnCallback(function ($property) use ($userId) {
$propertyMock = $this->createMock(IAccountProperty::class);
$propertyMock->expects($this->any())
->method('getValue')
->willReturn($this->testAccountsData[$userId][$property]['value'] ?? '');
$propertyMock->expects($this->any())
->method('getScope')
->willReturn($this->testAccountsData[$userId][$property]['scope'] ?? '');
return $propertyMock;
});
$this->accountManager->expects($this->any())
->method('getAccount')
->with($user)
->willReturn($account);
// setup reference
if ($this->testUsersData[$userId] === null) {
$expectedReference = null;
} else {
$expectedReference = new Reference($this->testLinks[$userId]);
$expectedReference->setTitle($this->testUsersData[$userId]['displayname']);
$expectedReference->setDescription($this->testUsersData[$userId]['email']);
$expectedReference->setImageUrl($this->testUsersData[$userId]['avatarurl']);
$bio = $this->getTestAccountPropertyValue($userId, IAccountManager::PROPERTY_BIOGRAPHY);
$location = $this->getTestAccountPropertyValue($userId, IAccountManager::PROPERTY_ADDRESS);
$expectedReference->setRichObject(ProfilePickerReferenceProvider::RICH_OBJECT_TYPE, [
'user_id' => $this->testUsersData[$userId]['user_id'],
'title' => $this->testUsersData[$userId]['displayname'],
'subline' => $this->testUsersData[$userId]['email'] ?? $this->testUsersData[$userId]['displayname'],
'email' => $this->testUsersData[$userId]['email'],
'bio' => isset($bio) && $bio !== ''
? (mb_strlen($bio) > 80
? (mb_substr($bio, 0, 80) . '...')
: $bio)
: null,
'full_bio' => $bio,
'headline' => $this->getTestAccountPropertyValue($userId, IAccountManager::PROPERTY_HEADLINE),
'location' => $location,
'location_url' => $location !== null ? 'https://www.openstreetmap.org/search?query=' . urlencode($location) : null,
'website' => $this->getTestAccountPropertyValue($userId, IAccountManager::PROPERTY_WEBSITE),
'organisation' => $this->getTestAccountPropertyValue($userId, IAccountManager::PROPERTY_ORGANISATION),
'role' => $this->getTestAccountPropertyValue($userId, IAccountManager::PROPERTY_ROLE),
'url' => $this->testLinks[$userId],
]);
}
$this->urlGenerator->expects($this->any())
->method('linkToRouteAbsolute')
->with('core.avatar.getAvatar', ['userId' => $userId, 'size' => 64])
->willReturn($this->testUsersData[$userId]['avatarurl']);
}
return $expectedReference ?? null;
}
/**
* Resolved reference should contain the expected reference fields according to account property scope
*/
#[DataProvider('resolveReferenceDataProvider')]
public function testResolveReference($expected, $reference, $userId) {
if (isset($userId)) {
$expectedReference = $this->setupUserAccountReferenceExpectation($userId);
}
$resultReference = $this->referenceProvider->resolveReference($reference);
$this->assertEquals($expected, isset($resultReference));
$this->assertEquals($expectedReference ?? null, $resultReference);
}
public function testGetId() {
$this->assertEquals('profile_picker', $this->referenceProvider->getId());
}
/**
*/
#[DataProvider('referenceDataProvider')]
public function testMatchReference($expected, $reference) {
$this->assertEquals($expected, $this->referenceProvider->matchReference($reference));
}
/**
*/
#[DataProvider('cacheKeyDataProvider')]
public function testGetCacheKey($expected, $reference) {
$this->assertEquals($expected, $this->referenceProvider->getCacheKey($reference));
}
public function testGetCachePrefix() {
$this->assertEquals($this->userId, $this->referenceProvider->getCachePrefix($this->testLink));
}
public function testGetTitle() {
$this->l10n->expects($this->once())
->method('t')
->with('Profile picker')
->willReturn('Profile picker');
$this->assertEquals('Profile picker', $this->referenceProvider->getTitle());
}
/**
* Test getObjectId method.
* It should return the userid extracted from the link (http(s)://domain.com/(index.php)/u/{userid}).
*/
#[DataProvider('objectIdDataProvider')]
public function testGetObjectId($expected, $reference) {
$this->assertEquals($expected, $this->referenceProvider->getObjectId($reference));
}
/**
*/
#[DataProvider('locationDataProvider')]
public function testGetOpenStreetLocationUrl($expected, $location) {
$this->assertEquals($expected, $this->referenceProvider->getOpenStreetLocationUrl($location));
}
public static function referenceDataProvider(): array {
return [
'not a link' => [false, 'profile_picker'],
'valid link to test user' => [true, 'https://nextcloud.local/index.php/u/user1'],
'pretty link to test user' => [true, 'https://nextcloud.local/u/user1'],
'not valid link' => [false, 'https://nextcloud.local'],
];
}
public static function objectIdDataProvider(): array {
return [
'valid link to test user' => ['user1', 'https://nextcloud.local/index.php/u/user1'],
'not valid link' => [null, 'https://nextcloud.local'],
];
}
public static function cacheKeyDataProvider(): array {
return [
'valid link to test user' => ['user1', 'https://nextcloud.local/index.php/u/user1'],
'not valid link' => ['https://nextcloud.local', 'https://nextcloud.local'],
];
}
public static function locationDataProvider(): array {
return [
'link to location' => ['https://www.openstreetmap.org/search?query=location', 'location'],
'link to Odessa' => ['https://www.openstreetmap.org/search?query=Odessa', 'Odessa'],
'link to Frankfurt am Main' => ['https://www.openstreetmap.org/search?query=Frankfurt+am+Main', 'Frankfurt am Main'],
];
}
public static function resolveReferenceDataProvider(): array {
return [
'test reference for user1' => [true, 'https://nextcloud.local/index.php/u/user1', 'user1'],
'test reference for user2' => [true, 'https://nextcloud.local/index.php/u/user2', 'user2'],
'test reference for non-existing user' => [false, 'https://nextcloud.local/index.php/u/user4', 'user4'],
'test reference for not valid link' => [null, 'https://nextcloud.local', null],
];
}
}