diff options
Diffstat (limited to 'tests/lib/Accounts')
-rw-r--r-- | tests/lib/Accounts/AccountManagerTest.php | 517 | ||||
-rw-r--r-- | tests/lib/Accounts/AccountPropertyCollectionTest.php | 37 | ||||
-rw-r--r-- | tests/lib/Accounts/AccountPropertyTest.php | 47 | ||||
-rw-r--r-- | tests/lib/Accounts/AccountTest.php | 35 | ||||
-rw-r--r-- | tests/lib/Accounts/HooksTest.php | 37 |
5 files changed, 423 insertions, 250 deletions
diff --git a/tests/lib/Accounts/AccountManagerTest.php b/tests/lib/Accounts/AccountManagerTest.php index 9d54ef36c80..c625644bd96 100644 --- a/tests/lib/Accounts/AccountManagerTest.php +++ b/tests/lib/Accounts/AccountManagerTest.php @@ -1,45 +1,37 @@ <?php /** - * @author Björn Schießle <schiessle@owncloud.com> - * - * @copyright Copyright (c) 2016, ownCloud, Inc. - * @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: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace Test\Accounts; use OC\Accounts\Account; use OC\Accounts\AccountManager; +use OC\PhoneNumberUtil; use OCA\Settings\BackgroundJobs\VerifyUserData; use OCP\Accounts\IAccountManager; +use OCP\Accounts\UserUpdatedEvent; use OCP\BackgroundJob\IJobList; use OCP\Defaults; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Http\Client\IClient; +use OCP\Http\Client\IClientService; +use OCP\Http\Client\IResponse; use OCP\IConfig; use OCP\IDBConnection; +use OCP\IPhoneNumberUtil; use OCP\IURLGenerator; use OCP\IUser; use OCP\L10N\IFactory; use OCP\Mail\IMailer; use OCP\Security\ICrypto; use OCP\Security\VerificationToken\IVerificationToken; +use OCP\Server; use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\EventDispatcher\GenericEvent; use Test\TestCase; /** @@ -49,44 +41,31 @@ use Test\TestCase; * @package Test\Accounts */ class AccountManagerTest extends TestCase { - /** @var IVerificationToken|MockObject */ - protected $verificationToken; - /** @var IMailer|MockObject */ - protected $mailer; - /** @var ICrypto|MockObject */ - protected $crypto; - /** @var IURLGenerator|MockObject */ - protected $urlGenerator; - /** @var Defaults|MockObject */ - protected $defaults; - /** @var IFactory|MockObject */ - protected $l10nFactory; - - /** @var \OCP\IDBConnection */ - private $connection; - - /** @var IConfig|MockObject */ - private $config; - - /** @var EventDispatcherInterface|MockObject */ - private $eventDispatcher; - - /** @var IJobList|MockObject */ - private $jobList; - /** @var string accounts table name */ - private $table = 'accounts'; + /** accounts table name */ + private string $table = 'accounts'; + private AccountManager $accountManager; + private IDBConnection $connection; + private IPhoneNumberUtil $phoneNumberUtil; - /** @var LoggerInterface|MockObject */ - private $logger; - - /** @var AccountManager */ - private $accountManager; + protected IVerificationToken&MockObject $verificationToken; + protected IMailer&MockObject $mailer; + protected ICrypto&MockObject $crypto; + protected IURLGenerator&MockObject $urlGenerator; + protected Defaults&MockObject $defaults; + protected IFactory&MockObject $l10nFactory; + protected IConfig&MockObject $config; + protected IEventDispatcher&MockObject $eventDispatcher; + protected IJobList&MockObject $jobList; + private LoggerInterface&MockObject $logger; + private IClientService&MockObject $clientService; protected function setUp(): void { parent::setUp(); - $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class); - $this->connection = \OC::$server->get(IDBConnection::class); + $this->connection = Server::get(IDBConnection::class); + $this->phoneNumberUtil = new PhoneNumberUtil(); + + $this->eventDispatcher = $this->createMock(IEventDispatcher::class); $this->config = $this->createMock(IConfig::class); $this->jobList = $this->createMock(IJobList::class); $this->logger = $this->createMock(LoggerInterface::class); @@ -96,6 +75,7 @@ class AccountManagerTest extends TestCase { $this->l10nFactory = $this->createMock(IFactory::class); $this->urlGenerator = $this->createMock(IURLGenerator::class); $this->crypto = $this->createMock(ICrypto::class); + $this->clientService = $this->createMock(IClientService::class); $this->accountManager = new AccountManager( $this->connection, @@ -108,17 +88,19 @@ class AccountManagerTest extends TestCase { $this->defaults, $this->l10nFactory, $this->urlGenerator, - $this->crypto + $this->crypto, + $this->phoneNumberUtil, + $this->clientService, ); } protected function tearDown(): void { parent::tearDown(); $query = $this->connection->getQueryBuilder(); - $query->delete($this->table)->execute(); + $query->delete($this->table)->executeStatement(); } - protected function makeUser(string $uid, string $name, string $email = null): IUser { + protected function makeUser(string $uid, string $name, ?string $email = null): IUser { $user = $this->createMock(IUser::class); $user->expects($this->any()) ->method('getUid') @@ -156,6 +138,11 @@ class AccountManagerTest extends TestCase { 'scope' => IAccountManager::SCOPE_PUBLISHED ], [ + 'name' => IAccountManager::PROPERTY_FEDIVERSE, + 'value' => '@someMastodon@mastodon.social', + 'scope' => IAccountManager::SCOPE_PUBLISHED + ], + [ 'name' => IAccountManager::PROPERTY_PHONE, 'value' => '+491601231212', 'scope' => IAccountManager::SCOPE_FEDERATED @@ -211,6 +198,11 @@ class AccountManagerTest extends TestCase { 'scope' => IAccountManager::SCOPE_FEDERATED ], [ + 'name' => IAccountManager::PROPERTY_FEDIVERSE, + 'value' => '@a_alice@cool.social', + 'scope' => IAccountManager::SCOPE_FEDERATED + ], + [ 'name' => IAccountManager::PROPERTY_PHONE, 'value' => '+491602312121', 'scope' => IAccountManager::SCOPE_LOCAL @@ -266,6 +258,11 @@ class AccountManagerTest extends TestCase { 'scope' => IAccountManager::SCOPE_LOCAL ], [ + 'name' => IAccountManager::PROPERTY_FEDIVERSE, + 'value' => '', + 'scope' => IAccountManager::SCOPE_LOCAL + ], + [ 'name' => IAccountManager::PROPERTY_PHONE, 'value' => '+491603121212', 'scope' => IAccountManager::SCOPE_PUBLISHED @@ -321,6 +318,11 @@ class AccountManagerTest extends TestCase { scope' => IAccountManager::SCOPE_LOCAL ], [ + 'name' => IAccountManager::PROPERTY_FEDIVERSE, + 'value' => '', ' + scope' => IAccountManager::SCOPE_LOCAL + ], + [ 'name' => IAccountManager::PROPERTY_PHONE, 'value' => '+71601212123', 'scope' => IAccountManager::SCOPE_LOCAL @@ -386,6 +388,11 @@ class AccountManagerTest extends TestCase { 'scope' => IAccountManager::SCOPE_LOCAL ], [ + 'name' => IAccountManager::PROPERTY_FEDIVERSE, + 'value' => '', + 'scope' => IAccountManager::SCOPE_LOCAL + ], + [ 'name' => IAccountManager::PROPERTY_PHONE, 'value' => '+71602121231', 'scope' => IAccountManager::SCOPE_FEDERATED @@ -423,18 +430,18 @@ class AccountManagerTest extends TestCase { ], ], ]; + $this->config->expects($this->exactly(count($users)))->method('getSystemValue')->with('account_manager.default_property_scope', [])->willReturn([]); foreach ($users as $userInfo) { - $this->invokePrivate($this->accountManager, 'updateUser', [$userInfo['user'], $userInfo['data'], false]); + $this->invokePrivate($this->accountManager, 'updateUser', [$userInfo['user'], $userInfo['data'], null, false]); } } /** * get a instance of the accountManager * - * @param array $mockedMethods list of methods which should be mocked * @return MockObject | AccountManager */ - public function getInstance($mockedMethods = null) { + public function getInstance(?array $mockedMethods = null) { return $this->getMockBuilder(AccountManager::class) ->setConstructorArgs([ $this->connection, @@ -447,28 +454,20 @@ class AccountManagerTest extends TestCase { $this->defaults, $this->l10nFactory, $this->urlGenerator, - $this->crypto + $this->crypto, + $this->phoneNumberUtil, + $this->clientService, ]) - ->setMethods($mockedMethods) + ->onlyMethods($mockedMethods) ->getMock(); } - /** - * @dataProvider dataTrueFalse - * - * @param array $newData - * @param array $oldData - * @param bool $insertNew - * @param bool $updateExisting - */ - public function testUpdateUser($newData, $oldData, $insertNew, $updateExisting) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataTrueFalse')] + public function testUpdateUser(array $newData, array $oldData, bool $insertNew, bool $updateExisting): void { $accountManager = $this->getInstance(['getUser', 'insertNewUser', 'updateExistingUser']); /** @var IUser $user */ $user = $this->createMock(IUser::class); - // FIXME: should be an integration test instead of this abomination - $accountManager->expects($this->once())->method('getUser')->with($user)->willReturn($oldData); - if ($updateExisting) { $accountManager->expects($this->once())->method('updateExistingUser') ->with($user, $newData); @@ -483,24 +482,22 @@ class AccountManagerTest extends TestCase { if (!$insertNew && !$updateExisting) { $accountManager->expects($this->never())->method('updateExistingUser'); $accountManager->expects($this->never())->method('insertNewUser'); - $this->eventDispatcher->expects($this->never())->method('dispatch'); + $this->eventDispatcher->expects($this->never())->method('dispatchTyped'); } else { - $this->eventDispatcher->expects($this->once())->method('dispatch') + $this->eventDispatcher->expects($this->once())->method('dispatchTyped') ->willReturnCallback( - function ($eventName, $event) use ($user, $newData) { - $this->assertSame('OC\AccountManager::userUpdated', $eventName); - $this->assertInstanceOf(GenericEvent::class, $event); - /** @var GenericEvent $event */ - $this->assertSame($user, $event->getSubject()); - $this->assertSame($newData, $event->getArguments()); + function ($event) use ($user, $newData): void { + $this->assertInstanceOf(UserUpdatedEvent::class, $event); + $this->assertSame($user, $event->getUser()); + $this->assertSame($newData, $event->getData()); } ); } - $this->invokePrivate($accountManager, 'updateUser', [$user, $newData]); + $this->invokePrivate($accountManager, 'updateUser', [$user, $newData, $oldData]); } - public function dataTrueFalse() { + public static function dataTrueFalse(): array { return [ #$newData | $oldData | $insertNew | $updateExisting [['myProperty' => ['value' => 'newData']], ['myProperty' => ['value' => 'oldData']], false, true], @@ -508,7 +505,7 @@ class AccountManagerTest extends TestCase { ]; } - public function testAddMissingDefaults() { + public function testAddMissingDefaults(): void { $user = $this->createMock(IUser::class); $this->config @@ -578,6 +575,20 @@ class AccountManagerTest extends TestCase { ], [ + 'name' => IAccountManager::PROPERTY_BLUESKY, + 'value' => '', + 'scope' => IAccountManager::SCOPE_LOCAL, + 'verified' => IAccountManager::NOT_VERIFIED, + ], + + [ + 'name' => IAccountManager::PROPERTY_FEDIVERSE, + 'value' => '', + 'scope' => IAccountManager::SCOPE_LOCAL, + 'verified' => IAccountManager::NOT_VERIFIED, + ], + + [ 'name' => IAccountManager::PROPERTY_ORGANISATION, 'value' => '', 'scope' => IAccountManager::SCOPE_LOCAL, @@ -602,10 +613,23 @@ class AccountManagerTest extends TestCase { ], [ + 'name' => IAccountManager::PROPERTY_BIRTHDATE, + 'value' => '', + 'scope' => IAccountManager::SCOPE_LOCAL, + ], + + [ 'name' => IAccountManager::PROPERTY_PROFILE_ENABLED, 'value' => '1', ], + + [ + 'name' => IAccountManager::PROPERTY_PRONOUNS, + 'value' => '', + 'scope' => IAccountManager::SCOPE_FEDERATED, + ], ]; + $this->config->expects($this->once())->method('getSystemValue')->with('account_manager.default_property_scope', [])->willReturn([]); $defaultUserRecord = $this->invokePrivate($this->accountManager, 'buildDefaultUserRecord', [$user]); $result = $this->invokePrivate($this->accountManager, 'addMissingDefaultValues', [$input, $defaultUserRecord]); @@ -613,19 +637,7 @@ class AccountManagerTest extends TestCase { $this->assertSame($expected, $result); } - private function addDummyValuesToTable($uid, $data) { - $query = $this->connection->getQueryBuilder(); - $query->insert($this->table) - ->values( - [ - 'uid' => $query->createNamedParameter($uid), - 'data' => $query->createNamedParameter(json_encode($data)), - ] - ) - ->execute(); - } - - public function testGetAccount() { + public function testGetAccount(): void { $accountManager = $this->getInstance(['getUser']); /** @var IUser $user */ $user = $this->createMock(IUser::class); @@ -638,6 +650,12 @@ class AccountManagerTest extends TestCase { 'name' => IAccountManager::PROPERTY_TWITTER, ], [ + 'value' => '@mastohandle@mastodon.social', + 'scope' => IAccountManager::SCOPE_LOCAL, + 'verified' => IAccountManager::NOT_VERIFIED, + 'name' => IAccountManager::PROPERTY_FEDIVERSE, + ], + [ 'value' => 'test@example.com', 'scope' => IAccountManager::SCOPE_PUBLISHED, 'verified' => IAccountManager::VERIFICATION_IN_PROGRESS, @@ -652,6 +670,7 @@ class AccountManagerTest extends TestCase { ]; $expected = new Account($user); $expected->setProperty(IAccountManager::PROPERTY_TWITTER, '@twitterhandle', IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED); + $expected->setProperty(IAccountManager::PROPERTY_FEDIVERSE, '@mastohandle@mastodon.social', IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED); $expected->setProperty(IAccountManager::PROPERTY_EMAIL, 'test@example.com', IAccountManager::SCOPE_PUBLISHED, IAccountManager::VERIFICATION_IN_PROGRESS); $expected->setProperty(IAccountManager::PROPERTY_WEBSITE, 'https://example.com', IAccountManager::SCOPE_FEDERATED, IAccountManager::VERIFIED); @@ -661,7 +680,7 @@ class AccountManagerTest extends TestCase { $this->assertEquals($expected, $accountManager->getAccount($user)); } - public function dataParsePhoneNumber(): array { + public static function dataParsePhoneNumber(): array { return [ ['0711 / 25 24 28-90', 'DE', '+4971125242890'], ['0711 / 25 24 28-90', '', null], @@ -669,51 +688,222 @@ class AccountManagerTest extends TestCase { ]; } - /** - * @dataProvider dataParsePhoneNumber - * @param string $phoneInput - * @param string $defaultRegion - * @param string|null $phoneNumber - */ - public function testParsePhoneNumber(string $phoneInput, string $defaultRegion, ?string $phoneNumber): void { + #[\PHPUnit\Framework\Attributes\DataProvider('dataParsePhoneNumber')] + public function testSanitizePhoneNumberOnUpdateAccount(string $phoneInput, string $defaultRegion, ?string $phoneNumber): void { $this->config->method('getSystemValueString') ->willReturn($defaultRegion); + $user = $this->createMock(IUser::class); + $account = new Account($user); + $account->setProperty(IAccountManager::PROPERTY_PHONE, $phoneInput, IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED); + $manager = $this->getInstance(['getUser', 'updateUser']); + $manager->method('getUser') + ->with($user, false) + ->willReturn([]); + $manager->expects($phoneNumber === null ? self::never() : self::once()) + ->method('updateUser'); + if ($phoneNumber === null) { $this->expectException(\InvalidArgumentException::class); - self::invokePrivate($this->accountManager, 'parsePhoneNumber', [$phoneInput]); - } else { - self::assertEquals($phoneNumber, self::invokePrivate($this->accountManager, 'parsePhoneNumber', [$phoneInput])); + } + + $manager->updateAccount($account); + + if ($phoneNumber !== null) { + self::assertEquals($phoneNumber, $account->getProperty(IAccountManager::PROPERTY_PHONE)->getValue()); } } - public function dataParseWebsite(): array { + public static function dataSanitizeOnUpdate(): array { return [ - ['https://nextcloud.com', 'https://nextcloud.com'], - ['http://nextcloud.com', 'http://nextcloud.com'], - ['ftp://nextcloud.com', null], - ['//nextcloud.com/', null], - ['https:///?query', null], + [IAccountManager::PROPERTY_WEBSITE, 'https://nextcloud.com', 'https://nextcloud.com'], + [IAccountManager::PROPERTY_WEBSITE, 'http://nextcloud.com', 'http://nextcloud.com'], + [IAccountManager::PROPERTY_WEBSITE, 'ftp://nextcloud.com', null], + [IAccountManager::PROPERTY_WEBSITE, '//nextcloud.com/', null], + [IAccountManager::PROPERTY_WEBSITE, 'https:///?query', null], + + [IAccountManager::PROPERTY_TWITTER, '@nextcloud', 'nextcloud'], + [IAccountManager::PROPERTY_TWITTER, '_nextcloud', '_nextcloud'], + [IAccountManager::PROPERTY_TWITTER, 'FooB4r', 'FooB4r'], + [IAccountManager::PROPERTY_TWITTER, 'X', null], + [IAccountManager::PROPERTY_TWITTER, 'next.cloud', null], + [IAccountManager::PROPERTY_TWITTER, 'ab/cd.zip', null], + [IAccountManager::PROPERTY_TWITTER, 'tooLongForTwitterAndX', null], + + [IAccountManager::PROPERTY_FEDIVERSE, 'nextcloud@mastodon.social', 'nextcloud@mastodon.social'], + [IAccountManager::PROPERTY_FEDIVERSE, '@nextcloud@mastodon.xyz', 'nextcloud@mastodon.xyz'], + [IAccountManager::PROPERTY_FEDIVERSE, 'l33t.h4x0r@sub.localhost.local', 'l33t.h4x0r@sub.localhost.local'], + [IAccountManager::PROPERTY_FEDIVERSE, 'invalid/name@mastodon.social', null], + [IAccountManager::PROPERTY_FEDIVERSE, 'name@evil.host/malware.exe', null], + [IAccountManager::PROPERTY_FEDIVERSE, '@is-it-a-host-or-name', null], + [IAccountManager::PROPERTY_FEDIVERSE, 'only-a-name', null], ]; } - /** - * @dataProvider dataParseWebsite - * @param string $websiteInput - * @param string|null $websiteOutput - */ - public function testParseWebsite(string $websiteInput, ?string $websiteOutput): void { - if ($websiteOutput === null) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataSanitizeOnUpdate')] + public function testSanitizingOnUpdateAccount(string $property, string $input, ?string $output): void { + + if ($property === IAccountManager::PROPERTY_FEDIVERSE) { + // We do not test the server response here we do this in the `testSanitizingFediverseServer` + $this->config + ->method('getSystemValueBool') + ->with('has_internet_connection', true) + ->willReturn(false); + } + + $user = $this->createMock(IUser::class); + + $account = new Account($user); + $account->setProperty($property, $input, IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED); + + $manager = $this->getInstance(['getUser', 'updateUser']); + $manager->method('getUser') + ->with($user, false) + ->willReturn([]); + $manager->expects($output === null ? self::never() : self::once()) + ->method('updateUser'); + + if ($output === null) { $this->expectException(\InvalidArgumentException::class); - self::invokePrivate($this->accountManager, 'parseWebsite', [$websiteInput]); + $this->expectExceptionMessage($property); + } + + $manager->updateAccount($account); + + if ($output !== null) { + self::assertEquals($output, $account->getProperty($property)->getValue()); + } + } + + public static function dataSanitizeFediverseServer(): array { + return [ + 'no internet' => [ + '@foo@example.com', + 'foo@example.com', + false, + null, + ], + 'no internet - no at' => [ + 'foo@example.com', + 'foo@example.com', + false, + null, + ], + 'valid response' => [ + '@foo@example.com', + 'foo@example.com', + true, + json_encode([ + 'subject' => 'acct:foo@example.com', + 'links' => [ + [ + 'rel' => 'self', + 'type' => 'application/activity+json', + 'href' => 'https://example.com/users/foo', + ], + ], + ]), + ], + 'valid response - no at' => [ + 'foo@example.com', + 'foo@example.com', + true, + json_encode([ + 'subject' => 'acct:foo@example.com', + 'links' => [ + [ + 'rel' => 'self', + 'type' => 'application/activity+json', + 'href' => 'https://example.com/users/foo', + ], + ], + ]), + ], + // failures + 'invalid response' => [ + '@foo@example.com', + null, + true, + json_encode([ + 'subject' => 'acct:foo@example.com', + 'links' => [], + ]), + ], + 'no response' => [ + '@foo@example.com', + null, + true, + null, + ], + 'wrong user' => [ + '@foo@example.com', + null, + true, + json_encode([ + 'links' => [], + ]), + ], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataSanitizeFediverseServer')] + public function testSanitizingFediverseServer(string $input, ?string $output, bool $hasInternet, ?string $serverResponse): void { + $this->config->expects(self::once()) + ->method('getSystemValueBool') + ->with('has_internet_connection', true) + ->willReturn($hasInternet); + + if ($hasInternet) { + $client = $this->createMock(IClient::class); + if ($serverResponse !== null) { + $response = $this->createMock(IResponse::class); + $response->method('getBody') + ->willReturn($serverResponse); + $client->expects(self::once()) + ->method('get') + ->with('https://example.com/.well-known/webfinger?resource=acct:foo@example.com') + ->willReturn($response); + } else { + $client->expects(self::once()) + ->method('get') + ->with('https://example.com/.well-known/webfinger?resource=acct:foo@example.com') + ->willThrowException(new \Exception('404')); + } + + $this->clientService + ->expects(self::once()) + ->method('newClient') + ->willReturn($client); } else { - self::assertEquals($websiteOutput, self::invokePrivate($this->accountManager, 'parseWebsite', [$websiteInput])); + $this->clientService + ->expects(self::never()) + ->method('newClient'); + } + + $user = $this->createMock(IUser::class); + $account = new Account($user); + $account->setProperty(IAccountManager::PROPERTY_FEDIVERSE, $input, IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED); + + $manager = $this->getInstance(['getUser', 'updateUser']); + $manager->method('getUser') + ->with($user, false) + ->willReturn([]); + $manager->expects($output === null ? self::never() : self::once()) + ->method('updateUser'); + + if ($output === null) { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage(IAccountManager::PROPERTY_FEDIVERSE); + } + + $manager->updateAccount($account); + + if ($output !== null) { + self::assertEquals($output, $account->getProperty(IAccountManager::PROPERTY_FEDIVERSE)->getValue()); } } - /** - * @dataProvider searchDataProvider - */ + #[\PHPUnit\Framework\Attributes\DataProvider('searchDataProvider')] public function testSearchUsers(string $property, array $values, array $expected): void { $this->populateOrUpdate(); @@ -726,7 +916,7 @@ class AccountManagerTest extends TestCase { } } - public function searchDataProvider(): array { + public static function searchDataProvider(): array { return [ [ #0 Search for an existing name IAccountManager::PROPERTY_DISPLAYNAME, @@ -778,21 +968,22 @@ class AccountManagerTest extends TestCase { ]; } - public function dataCheckEmailVerification(): array { + public static function dataCheckEmailVerification(): array { return [ - [$this->makeUser('steve', 'Steve Smith', 'steve@steve.steve'), null], - [$this->makeUser('emma', 'Emma Morales', 'emma@emma.com'), 'emma@morales.com'], - [$this->makeUser('sarah@web.org', 'Sarah Foster', 'sarah@web.org'), null], - [$this->makeUser('cole@web.org', 'Cole Harrison', 'cole@web.org'), 'cole@example.com'], - [$this->makeUser('8d29e358-cf69-4849-bbf9-28076c0b908b', 'Alice McPherson', 'alice@example.com'), 'alice@mcpherson.com'], - [$this->makeUser('11da2744-3f4d-4c17-8c13-4c057a379237', 'James Loranger', 'james@example.com'), ''], + [['steve', 'Steve Smith', 'steve@steve.steve'], null], + [['emma', 'Emma Morales', 'emma@emma.com'], 'emma@morales.com'], + [['sarah@web.org', 'Sarah Foster', 'sarah@web.org'], null], + [['cole@web.org', 'Cole Harrison', 'cole@web.org'], 'cole@example.com'], + [['8d29e358-cf69-4849-bbf9-28076c0b908b', 'Alice McPherson', 'alice@example.com'], 'alice@mcpherson.com'], + [['11da2744-3f4d-4c17-8c13-4c057a379237', 'James Loranger', 'james@example.com'], ''], ]; } - /** - * @dataProvider dataCheckEmailVerification - */ - public function testCheckEmailVerification(IUser $user, ?string $newEmail): void { + #[\PHPUnit\Framework\Attributes\DataProvider('dataCheckEmailVerification')] + public function testCheckEmailVerification(array $userData, ?string $newEmail): void { + $user = $this->makeUser(...$userData); + // Once because of getAccount, once because of getUser + $this->config->expects($this->exactly(2))->method('getSystemValue')->with('account_manager.default_property_scope', [])->willReturn([]); $account = $this->accountManager->getAccount($user); $emailUpdated = false; @@ -815,4 +1006,56 @@ class AccountManagerTest extends TestCase { $oldData = $this->invokePrivate($this->accountManager, 'getUser', [$user, false]); $this->invokePrivate($this->accountManager, 'checkEmailVerification', [$account, $oldData]); } + + public static function dataSetDefaultPropertyScopes(): array { + return [ + [ + [], + [ + IAccountManager::PROPERTY_DISPLAYNAME => IAccountManager::SCOPE_FEDERATED, + IAccountManager::PROPERTY_ADDRESS => IAccountManager::SCOPE_LOCAL, + IAccountManager::PROPERTY_EMAIL => IAccountManager::SCOPE_FEDERATED, + IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_LOCAL, + ] + ], + [ + [ + IAccountManager::PROPERTY_DISPLAYNAME => IAccountManager::SCOPE_FEDERATED, + IAccountManager::PROPERTY_EMAIL => IAccountManager::SCOPE_LOCAL, + IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_PRIVATE, + ], [ + IAccountManager::PROPERTY_DISPLAYNAME => IAccountManager::SCOPE_FEDERATED, + IAccountManager::PROPERTY_EMAIL => IAccountManager::SCOPE_LOCAL, + IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_PRIVATE, + ] + ], + [ + [ + IAccountManager::PROPERTY_ADDRESS => 'invalid scope', + 'invalid property' => IAccountManager::SCOPE_LOCAL, + IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_PRIVATE, + ], + [ + IAccountManager::PROPERTY_ADDRESS => IAccountManager::SCOPE_LOCAL, + IAccountManager::PROPERTY_EMAIL => IAccountManager::SCOPE_FEDERATED, + IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_PRIVATE, + ] + ], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataSetDefaultPropertyScopes')] + public function testSetDefaultPropertyScopes(array $propertyScopes, array $expectedResultScopes): void { + $user = $this->makeUser('steve', 'Steve Smith', 'steve@steve.steve'); + $this->config->expects($this->once())->method('getSystemValue')->with('account_manager.default_property_scope', [])->willReturn($propertyScopes); + + $result = $this->invokePrivate($this->accountManager, 'buildDefaultUserRecord', [$user]); + $resultProperties = array_column($result, 'name'); + + $this->assertEmpty(array_diff($resultProperties, IAccountManager::ALLOWED_PROPERTIES), 'Building default user record returned non-allowed properties'); + foreach ($expectedResultScopes as $expectedResultScopeKey => $expectedResultScopeValue) { + $resultScope = $result[array_search($expectedResultScopeKey, $resultProperties)]['scope']; + $this->assertEquals($expectedResultScopeValue, $resultScope, "The result scope doesn't follow the value set into the config or defaults correctly."); + } + } } diff --git a/tests/lib/Accounts/AccountPropertyCollectionTest.php b/tests/lib/Accounts/AccountPropertyCollectionTest.php index d8a6bafd24b..fa4db10d3d9 100644 --- a/tests/lib/Accounts/AccountPropertyCollectionTest.php +++ b/tests/lib/Accounts/AccountPropertyCollectionTest.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2021 Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @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 <https://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace lib\Accounts; @@ -57,7 +40,7 @@ class AccountPropertyCollectionTest extends TestCase { return $mock; } - public function testSetAndGetProperties() { + public function testSetAndGetProperties(): void { $propsBefore = $this->collection->getProperties(); $this->assertIsArray($propsBefore); $this->assertEmpty($propsBefore); @@ -74,7 +57,7 @@ class AccountPropertyCollectionTest extends TestCase { $this->assertCount(count($props), $propsAfter); } - public function testSetPropertiesMixedInvalid() { + public function testSetPropertiesMixedInvalid(): void { $props = [ $this->makePropertyMock(self::COLLECTION_NAME), $this->makePropertyMock('sneaky_property'), @@ -85,7 +68,7 @@ class AccountPropertyCollectionTest extends TestCase { $this->collection->setProperties($props); } - public function testAddProperty() { + public function testAddProperty(): void { $props = [ $this->makePropertyMock(self::COLLECTION_NAME), $this->makePropertyMock(self::COLLECTION_NAME), @@ -101,7 +84,7 @@ class AccountPropertyCollectionTest extends TestCase { $this->assertNotFalse(array_search($additionalProperty, $propsAfter, true)); } - public function testAddPropertyInvalid() { + public function testAddPropertyInvalid(): void { $props = [ $this->makePropertyMock(self::COLLECTION_NAME), $this->makePropertyMock(self::COLLECTION_NAME), @@ -123,7 +106,7 @@ class AccountPropertyCollectionTest extends TestCase { } } - public function testRemoveProperty() { + public function testRemoveProperty(): void { $additionalProperty = $this->makePropertyMock(self::COLLECTION_NAME); $props = [ $this->makePropertyMock(self::COLLECTION_NAME), @@ -142,7 +125,7 @@ class AccountPropertyCollectionTest extends TestCase { $this->assertFalse(array_search($additionalProperty, $propsAfter, true)); } - public function testRemovePropertyNotFound() { + public function testRemovePropertyNotFound(): void { $additionalProperty = $this->makePropertyMock(self::COLLECTION_NAME); $props = [ $this->makePropertyMock(self::COLLECTION_NAME), @@ -159,7 +142,7 @@ class AccountPropertyCollectionTest extends TestCase { $this->assertCount(count($propsBefore), $propsAfter); } - public function testRemovePropertyByValue() { + public function testRemovePropertyByValue(): void { $additionalProperty = $this->makePropertyMock(self::COLLECTION_NAME); $additionalProperty->expects($this->any()) ->method('getValue') @@ -186,7 +169,7 @@ class AccountPropertyCollectionTest extends TestCase { $this->assertFalse(array_search($additionalPropertyTwo, $propsAfter, true)); } - public function testRemovePropertyByValueNotFound() { + public function testRemovePropertyByValueNotFound(): void { $additionalProperty = $this->makePropertyMock(self::COLLECTION_NAME); $additionalProperty->expects($this->any()) ->method('getValue') diff --git a/tests/lib/Accounts/AccountPropertyTest.php b/tests/lib/Accounts/AccountPropertyTest.php index 55f83513349..b92e45176a3 100644 --- a/tests/lib/Accounts/AccountPropertyTest.php +++ b/tests/lib/Accounts/AccountPropertyTest.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net> - * - * @author Julius Härtl <jus@bitgrid.net> - * - * @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: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\Accounts; @@ -33,7 +17,7 @@ use Test\TestCase; * @package Test\Accounts */ class AccountPropertyTest extends TestCase { - public function testConstructor() { + public function testConstructor(): void { $accountProperty = new AccountProperty( IAccountManager::PROPERTY_WEBSITE, 'https://example.com', @@ -47,7 +31,7 @@ class AccountPropertyTest extends TestCase { $this->assertEquals(IAccountManager::VERIFIED, $accountProperty->getVerified()); } - public function testSetValue() { + public function testSetValue(): void { $accountProperty = new AccountProperty( IAccountManager::PROPERTY_WEBSITE, 'https://example.com', @@ -60,7 +44,7 @@ class AccountPropertyTest extends TestCase { $this->assertEquals('https://example.org', $actualReturn->getValue()); } - public function testSetScope() { + public function testSetScope(): void { $accountProperty = new AccountProperty( IAccountManager::PROPERTY_WEBSITE, 'https://example.com', @@ -73,28 +57,21 @@ class AccountPropertyTest extends TestCase { $this->assertEquals(IAccountManager::SCOPE_LOCAL, $actualReturn->getScope()); } - public function scopesProvider() { + public static function scopesProvider(): array { return [ // current values [IAccountManager::SCOPE_PRIVATE, IAccountManager::SCOPE_PRIVATE], [IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_LOCAL], [IAccountManager::SCOPE_FEDERATED, IAccountManager::SCOPE_FEDERATED], [IAccountManager::SCOPE_PUBLISHED, IAccountManager::SCOPE_PUBLISHED], - // legacy values - [IAccountManager::VISIBILITY_PRIVATE, IAccountManager::SCOPE_LOCAL], - [IAccountManager::VISIBILITY_CONTACTS_ONLY, IAccountManager::SCOPE_FEDERATED], - [IAccountManager::VISIBILITY_PUBLIC, IAccountManager::SCOPE_PUBLISHED], - ['', IAccountManager::SCOPE_LOCAL], // invalid values ['unknown', null], ['v2-unknown', null], ]; } - /** - * @dataProvider scopesProvider - */ - public function testSetScopeMapping(string $storedScope, ?string $returnedScope) { + #[\PHPUnit\Framework\Attributes\DataProvider('scopesProvider')] + public function testSetScopeMapping(string $storedScope, ?string $returnedScope): void { if ($returnedScope === null) { $this->expectException(\InvalidArgumentException::class); } @@ -108,7 +85,7 @@ class AccountPropertyTest extends TestCase { $this->assertEquals($returnedScope, $accountProperty->getScope()); } - public function testSetVerified() { + public function testSetVerified(): void { $accountProperty = new AccountProperty( IAccountManager::PROPERTY_WEBSITE, 'https://example.com', @@ -121,7 +98,7 @@ class AccountPropertyTest extends TestCase { $this->assertEquals(IAccountManager::NOT_VERIFIED, $actualReturn->getVerified()); } - public function testSetVerificationData() { + public function testSetVerificationData(): void { $accountProperty = new AccountProperty( IAccountManager::PROPERTY_WEBSITE, 'https://example.com', @@ -135,7 +112,7 @@ class AccountPropertyTest extends TestCase { $this->assertEquals($token, $actualReturn->getVerificationData()); } - public function testJsonSerialize() { + public function testJsonSerialize(): void { $accountProperty = new AccountProperty( IAccountManager::PROPERTY_WEBSITE, 'https://example.com', diff --git a/tests/lib/Accounts/AccountTest.php b/tests/lib/Accounts/AccountTest.php index a86b1d0255b..ddba7c559c0 100644 --- a/tests/lib/Accounts/AccountTest.php +++ b/tests/lib/Accounts/AccountTest.php @@ -1,24 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net> - * - * @author Julius Härtl <jus@bitgrid.net> - * - * @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: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\Accounts; @@ -36,13 +20,13 @@ use Test\TestCase; * @package Test\Accounts */ class AccountTest extends TestCase { - public function testConstructor() { + public function testConstructor(): void { $user = $this->createMock(IUser::class); $account = new Account($user); $this->assertEquals($user, $account->getUser()); } - public function testSetProperty() { + public function testSetProperty(): void { $user = $this->createMock(IUser::class); $property = new AccountProperty(IAccountManager::PROPERTY_WEBSITE, 'https://example.com', IAccountManager::SCOPE_PUBLISHED, IAccountManager::NOT_VERIFIED, ''); $account = new Account($user); @@ -50,7 +34,7 @@ class AccountTest extends TestCase { $this->assertEquals($property, $account->getProperty(IAccountManager::PROPERTY_WEBSITE)); } - public function testGetAndGetAllProperties() { + public function testGetAndGetAllProperties(): void { $user = $this->createMock(IUser::class); $properties = [ IAccountManager::PROPERTY_WEBSITE => new AccountProperty(IAccountManager::PROPERTY_WEBSITE, 'https://example.com', IAccountManager::SCOPE_PUBLISHED, IAccountManager::NOT_VERIFIED, ''), @@ -70,7 +54,7 @@ class AccountTest extends TestCase { $this->assertEquals(array_values($properties), \iterator_to_array($account->getAllProperties())); } - public function testSetAllPropertiesFromJson() { + public function testSetAllPropertiesFromJson(): void { $user = $this->createMock(IUser::class); $properties = [ IAccountManager::PROPERTY_DISPLAYNAME => new AccountProperty(IAccountManager::PROPERTY_DISPLAYNAME, 'Steve', IAccountManager::SCOPE_FEDERATED, IAccountManager::NOT_VERIFIED, ''), @@ -80,6 +64,7 @@ class AccountTest extends TestCase { IAccountManager::PROPERTY_AVATAR => new AccountProperty(IAccountManager::PROPERTY_AVATAR, '', IAccountManager::SCOPE_PUBLISHED, IAccountManager::NOT_VERIFIED, ''), IAccountManager::PROPERTY_PHONE => new AccountProperty(IAccountManager::PROPERTY_PHONE, '+358407991028', IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED, ''), IAccountManager::PROPERTY_TWITTER => new AccountProperty(IAccountManager::PROPERTY_TWITTER, 'therealsteve', IAccountManager::SCOPE_PRIVATE, IAccountManager::NOT_VERIFIED, ''), + IAccountManager::PROPERTY_BLUESKY => new AccountProperty(IAccountManager::PROPERTY_BLUESKY, 'therealsteve.bsky.social', IAccountManager::SCOPE_PRIVATE, IAccountManager::NOT_VERIFIED, ''), IAccountManager::PROPERTY_ORGANISATION => new AccountProperty(IAccountManager::PROPERTY_ORGANISATION, 'Steve Incorporated', IAccountManager::SCOPE_FEDERATED, IAccountManager::NOT_VERIFIED, ''), IAccountManager::PROPERTY_ROLE => new AccountProperty(IAccountManager::PROPERTY_ROLE, 'Founder', IAccountManager::SCOPE_FEDERATED, IAccountManager::NOT_VERIFIED, ''), IAccountManager::PROPERTY_HEADLINE => new AccountProperty(IAccountManager::PROPERTY_HEADLINE, 'I am Steve', IAccountManager::SCOPE_PUBLISHED, IAccountManager::NOT_VERIFIED, ''), @@ -95,7 +80,7 @@ class AccountTest extends TestCase { $this->assertEquals($properties, $account->jsonSerialize()); } - public function testGetFilteredProperties() { + public function testGetFilteredProperties(): void { $user = $this->createMock(IUser::class); $properties = [ IAccountManager::PROPERTY_WEBSITE => new AccountProperty(IAccountManager::PROPERTY_WEBSITE, 'https://example.com', IAccountManager::SCOPE_PUBLISHED, IAccountManager::NOT_VERIFIED, ''), @@ -141,7 +126,7 @@ class AccountTest extends TestCase { ); } - public function testJsonSerialize() { + public function testJsonSerialize(): void { $user = $this->createMock(IUser::class); $properties = [ IAccountManager::PROPERTY_WEBSITE => new AccountProperty(IAccountManager::PROPERTY_WEBSITE, 'https://example.com', IAccountManager::SCOPE_PUBLISHED, IAccountManager::NOT_VERIFIED, ''), diff --git a/tests/lib/Accounts/HooksTest.php b/tests/lib/Accounts/HooksTest.php index d5c7cd60b1b..622fb3c7461 100644 --- a/tests/lib/Accounts/HooksTest.php +++ b/tests/lib/Accounts/HooksTest.php @@ -1,22 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org> - * - * @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 Test\Accounts; @@ -38,7 +24,6 @@ use Test\TestCase; * @group DB */ class HooksTest extends TestCase { - /** @var LoggerInterface|MockObject */ private $logger; @@ -59,7 +44,6 @@ class HooksTest extends TestCase { } /** - * @dataProvider dataTestChangeUserHook * * @param $params * @param $data @@ -67,7 +51,8 @@ class HooksTest extends TestCase { * @param $setDisplayName * @param $error */ - public function testChangeUserHook($params, $data, $setEmail, $setDisplayName, $error) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataTestChangeUserHook')] + public function testChangeUserHook($params, $data, $setEmail, $setDisplayName, $error): void { if ($error) { $this->accountManager->expects($this->never())->method('updateAccount'); } else { @@ -112,14 +97,14 @@ class HooksTest extends TestCase { } } + $params['user'] = $this->createMock(IUser::class); $this->hooks->changeUserHook($params['user'], $params['feature'], $params['value']); } - public function dataTestChangeUserHook() { - $user = $this->createMock(IUser::class); + public static function dataTestChangeUserHook(): array { return [ [ - ['user' => $user, 'feature' => '', 'value' => ''], + ['feature' => '', 'value' => ''], [ IAccountManager::PROPERTY_EMAIL => ['value' => ''], IAccountManager::PROPERTY_DISPLAYNAME => ['value' => ''] @@ -127,7 +112,7 @@ class HooksTest extends TestCase { false, false, true ], [ - ['user' => $user, 'feature' => 'foo', 'value' => 'bar'], + ['feature' => 'foo', 'value' => 'bar'], [ IAccountManager::PROPERTY_EMAIL => ['value' => 'oldMail@example.com'], IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'oldDisplayName'] @@ -135,7 +120,7 @@ class HooksTest extends TestCase { false, false, false ], [ - ['user' => $user, 'feature' => 'eMailAddress', 'value' => 'newMail@example.com'], + ['feature' => 'eMailAddress', 'value' => 'newMail@example.com'], [ IAccountManager::PROPERTY_EMAIL => ['value' => 'oldMail@example.com'], IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'oldDisplayName'] @@ -143,7 +128,7 @@ class HooksTest extends TestCase { true, false, false ], [ - ['user' => $user, 'feature' => 'displayName', 'value' => 'newDisplayName'], + ['feature' => 'displayName', 'value' => 'newDisplayName'], [ IAccountManager::PROPERTY_EMAIL => ['value' => 'oldMail@example.com'], IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'oldDisplayName'] |