Completed
Push — master ( adc201...206b61 )
by
unknown
35:27 queued 10s
created
tests/Core/Command/Apps/AppsEnableTest.php 1 patch
Indentation   +59 added lines, -59 removed lines patch added patch discarded remove patch
@@ -21,63 +21,63 @@
 block discarded – undo
21 21
  */
22 22
 #[\PHPUnit\Framework\Attributes\Group('DB')]
23 23
 class AppsEnableTest extends TestCase {
24
-	/** @var CommandTester */
25
-	private $commandTester;
26
-
27
-	protected function setUp(): void {
28
-		parent::setUp();
29
-
30
-		$command = new Enable(
31
-			Server::get(IAppManager::class),
32
-			Server::get(IGroupManager::class),
33
-			Server::get(Installer::class),
34
-		);
35
-
36
-		$this->commandTester = new CommandTester($command);
37
-
38
-		Server::get(IAppManager::class)->disableApp('admin_audit');
39
-		Server::get(IAppManager::class)->disableApp('comments');
40
-	}
41
-
42
-	/**
43
-	 * @param $appId
44
-	 * @param $groups
45
-	 * @param $statusCode
46
-	 * @param $pattern
47
-	 */
48
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataCommandInput')]
49
-	public function testCommandInput($appId, $groups, $statusCode, $pattern): void {
50
-		$input = ['app-id' => $appId];
51
-
52
-		if (is_array($groups)) {
53
-			$input['--groups'] = $groups;
54
-		}
55
-
56
-		$this->commandTester->execute($input);
57
-
58
-		$this->assertMatchesRegularExpression('/' . $pattern . '/', $this->commandTester->getDisplay());
59
-		$this->assertSame($statusCode, $this->commandTester->getStatusCode());
60
-	}
61
-
62
-	public static function dataCommandInput(): array {
63
-		return [
64
-			[['admin_audit'], null, 0, 'admin_audit ([\d\.]*) enabled'],
65
-			[['comments'], null, 0, 'comments ([\d\.]*) enabled'],
66
-			[['comments', 'comments'], null, 0, "comments ([\d\.]*) enabled\ncomments already enabled"],
67
-			[['invalid_app'], null, 1, 'Could not download app invalid_app'],
68
-
69
-			[['admin_audit', 'comments'], null, 0, "admin_audit ([\d\.]*) enabled\ncomments ([\d\.]*) enabled"],
70
-			[['admin_audit', 'comments', 'invalid_app'], null, 1, "admin_audit ([\d\.]*) enabled\ncomments ([\d\.]*) enabled\nCould not download app invalid_app"],
71
-
72
-			[['admin_audit'], ['admin'], 1, "admin_audit can't be enabled for groups"],
73
-			[['comments'], ['admin'], 1, "comments can't be enabled for groups"],
74
-
75
-			[['updatenotification'], ['admin'], 0, 'updatenotification ([\d\.]*) enabled for groups: admin'],
76
-			[['updatenotification', 'dashboard'], ['admin'], 0, "updatenotification ([\d\.]*) enabled for groups: admin\ndashboard ([\d\.]*) enabled for groups: admin"],
77
-
78
-			[['updatenotification'], ['admin', 'invalid_group'], 0, 'updatenotification ([\d\.]*) enabled for groups: admin'],
79
-			[['updatenotification', 'dashboard'], ['admin', 'invalid_group'], 0, "updatenotification ([\d\.]*) enabled for groups: admin\ndashboard ([\d\.]*) enabled for groups: admin"],
80
-			[['updatenotification', 'dashboard', 'invalid_app'], ['admin', 'invalid_group'], 1, "updatenotification ([\d\.]*) enabled for groups: admin\ndashboard ([\d\.]*) enabled for groups: admin\nCould not download app invalid_app"],
81
-		];
82
-	}
24
+    /** @var CommandTester */
25
+    private $commandTester;
26
+
27
+    protected function setUp(): void {
28
+        parent::setUp();
29
+
30
+        $command = new Enable(
31
+            Server::get(IAppManager::class),
32
+            Server::get(IGroupManager::class),
33
+            Server::get(Installer::class),
34
+        );
35
+
36
+        $this->commandTester = new CommandTester($command);
37
+
38
+        Server::get(IAppManager::class)->disableApp('admin_audit');
39
+        Server::get(IAppManager::class)->disableApp('comments');
40
+    }
41
+
42
+    /**
43
+     * @param $appId
44
+     * @param $groups
45
+     * @param $statusCode
46
+     * @param $pattern
47
+     */
48
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataCommandInput')]
49
+    public function testCommandInput($appId, $groups, $statusCode, $pattern): void {
50
+        $input = ['app-id' => $appId];
51
+
52
+        if (is_array($groups)) {
53
+            $input['--groups'] = $groups;
54
+        }
55
+
56
+        $this->commandTester->execute($input);
57
+
58
+        $this->assertMatchesRegularExpression('/' . $pattern . '/', $this->commandTester->getDisplay());
59
+        $this->assertSame($statusCode, $this->commandTester->getStatusCode());
60
+    }
61
+
62
+    public static function dataCommandInput(): array {
63
+        return [
64
+            [['admin_audit'], null, 0, 'admin_audit ([\d\.]*) enabled'],
65
+            [['comments'], null, 0, 'comments ([\d\.]*) enabled'],
66
+            [['comments', 'comments'], null, 0, "comments ([\d\.]*) enabled\ncomments already enabled"],
67
+            [['invalid_app'], null, 1, 'Could not download app invalid_app'],
68
+
69
+            [['admin_audit', 'comments'], null, 0, "admin_audit ([\d\.]*) enabled\ncomments ([\d\.]*) enabled"],
70
+            [['admin_audit', 'comments', 'invalid_app'], null, 1, "admin_audit ([\d\.]*) enabled\ncomments ([\d\.]*) enabled\nCould not download app invalid_app"],
71
+
72
+            [['admin_audit'], ['admin'], 1, "admin_audit can't be enabled for groups"],
73
+            [['comments'], ['admin'], 1, "comments can't be enabled for groups"],
74
+
75
+            [['updatenotification'], ['admin'], 0, 'updatenotification ([\d\.]*) enabled for groups: admin'],
76
+            [['updatenotification', 'dashboard'], ['admin'], 0, "updatenotification ([\d\.]*) enabled for groups: admin\ndashboard ([\d\.]*) enabled for groups: admin"],
77
+
78
+            [['updatenotification'], ['admin', 'invalid_group'], 0, 'updatenotification ([\d\.]*) enabled for groups: admin'],
79
+            [['updatenotification', 'dashboard'], ['admin', 'invalid_group'], 0, "updatenotification ([\d\.]*) enabled for groups: admin\ndashboard ([\d\.]*) enabled for groups: admin"],
80
+            [['updatenotification', 'dashboard', 'invalid_app'], ['admin', 'invalid_group'], 1, "updatenotification ([\d\.]*) enabled for groups: admin\ndashboard ([\d\.]*) enabled for groups: admin\nCould not download app invalid_app"],
81
+        ];
82
+    }
83 83
 }
Please login to merge, or discard this patch.
tests/Core/Command/Apps/AppsDisableTest.php 1 patch
Indentation   +37 added lines, -37 removed lines patch added patch discarded remove patch
@@ -19,52 +19,52 @@
 block discarded – undo
19 19
  */
20 20
 #[\PHPUnit\Framework\Attributes\Group('DB')]
21 21
 class AppsDisableTest extends TestCase {
22
-	/** @var CommandTester */
23
-	private $commandTester;
22
+    /** @var CommandTester */
23
+    private $commandTester;
24 24
 
25
-	protected function setUp(): void {
26
-		parent::setUp();
25
+    protected function setUp(): void {
26
+        parent::setUp();
27 27
 
28
-		$command = new Disable(
29
-			Server::get(IAppManager::class)
30
-		);
28
+        $command = new Disable(
29
+            Server::get(IAppManager::class)
30
+        );
31 31
 
32
-		$this->commandTester = new CommandTester($command);
32
+        $this->commandTester = new CommandTester($command);
33 33
 
34
-		Server::get(IAppManager::class)->enableApp('admin_audit');
35
-		Server::get(IAppManager::class)->enableApp('comments');
36
-	}
34
+        Server::get(IAppManager::class)->enableApp('admin_audit');
35
+        Server::get(IAppManager::class)->enableApp('comments');
36
+    }
37 37
 
38
-	/**
39
-	 * @param $appId
40
-	 * @param $groups
41
-	 * @param $statusCode
42
-	 * @param $pattern
43
-	 */
44
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataCommandInput')]
45
-	public function testCommandInput($appId, $statusCode, $pattern): void {
46
-		$input = ['app-id' => $appId];
38
+    /**
39
+     * @param $appId
40
+     * @param $groups
41
+     * @param $statusCode
42
+     * @param $pattern
43
+     */
44
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataCommandInput')]
45
+    public function testCommandInput($appId, $statusCode, $pattern): void {
46
+        $input = ['app-id' => $appId];
47 47
 
48
-		$this->commandTester->execute($input);
48
+        $this->commandTester->execute($input);
49 49
 
50
-		$this->assertMatchesRegularExpression('/' . $pattern . '/', $this->commandTester->getDisplay());
51
-		$this->assertSame($statusCode, $this->commandTester->getStatusCode());
52
-	}
50
+        $this->assertMatchesRegularExpression('/' . $pattern . '/', $this->commandTester->getDisplay());
51
+        $this->assertSame($statusCode, $this->commandTester->getStatusCode());
52
+    }
53 53
 
54
-	public static function dataCommandInput(): array {
55
-		return [
56
-			[['admin_audit'], 0, 'admin_audit ([\d\.]*) disabled'],
57
-			[['comments'], 0, 'comments ([\d\.]*) disabled'],
58
-			[['invalid_app'], 0, 'No such app enabled: invalid_app'],
54
+    public static function dataCommandInput(): array {
55
+        return [
56
+            [['admin_audit'], 0, 'admin_audit ([\d\.]*) disabled'],
57
+            [['comments'], 0, 'comments ([\d\.]*) disabled'],
58
+            [['invalid_app'], 0, 'No such app enabled: invalid_app'],
59 59
 
60
-			[['admin_audit', 'comments'], 0, "admin_audit ([\d\.]*) disabled\ncomments ([\d\.]*) disabled"],
61
-			[['admin_audit', 'comments', 'invalid_app'], 0, "admin_audit ([\d\.]*) disabled\ncomments ([\d\.]*) disabled\nNo such app enabled: invalid_app"],
60
+            [['admin_audit', 'comments'], 0, "admin_audit ([\d\.]*) disabled\ncomments ([\d\.]*) disabled"],
61
+            [['admin_audit', 'comments', 'invalid_app'], 0, "admin_audit ([\d\.]*) disabled\ncomments ([\d\.]*) disabled\nNo such app enabled: invalid_app"],
62 62
 
63
-			[['files'], 2, "files can't be disabled"],
64
-			[['provisioning_api'], 2, "provisioning_api can't be disabled"],
63
+            [['files'], 2, "files can't be disabled"],
64
+            [['provisioning_api'], 2, "provisioning_api can't be disabled"],
65 65
 
66
-			[['files', 'admin_audit'], 2, "files can't be disabled.\nadmin_audit ([\d\.]*) disabled"],
67
-			[['provisioning_api', 'comments'], 2, "provisioning_api can't be disabled.\ncomments ([\d\.]*) disabled"],
68
-		];
69
-	}
66
+            [['files', 'admin_audit'], 2, "files can't be disabled.\nadmin_audit ([\d\.]*) disabled"],
67
+            [['provisioning_api', 'comments'], 2, "provisioning_api can't be disabled.\ncomments ([\d\.]*) disabled"],
68
+        ];
69
+    }
70 70
 }
Please login to merge, or discard this patch.
tests/lib/Accounts/AccountManagerTest.php 1 patch
Indentation   +1014 added lines, -1014 removed lines patch added patch discarded remove patch
@@ -44,1020 +44,1020 @@
 block discarded – undo
44 44
 #[\PHPUnit\Framework\Attributes\Group('DB')]
45 45
 class AccountManagerTest extends TestCase {
46 46
 
47
-	/** accounts table name */
48
-	private string $table = 'accounts';
49
-	private AccountManager $accountManager;
50
-	private IDBConnection $connection;
51
-	private IPhoneNumberUtil $phoneNumberUtil;
52
-
53
-	protected IVerificationToken&MockObject $verificationToken;
54
-	protected IMailer&MockObject $mailer;
55
-	protected ICrypto&MockObject $crypto;
56
-	protected IURLGenerator&MockObject $urlGenerator;
57
-	protected Defaults&MockObject $defaults;
58
-	protected IFactory&MockObject $l10nFactory;
59
-	protected IConfig&MockObject $config;
60
-	protected IEventDispatcher&MockObject $eventDispatcher;
61
-	protected IJobList&MockObject $jobList;
62
-	private LoggerInterface&MockObject $logger;
63
-	private IClientService&MockObject $clientService;
64
-
65
-	protected function setUp(): void {
66
-		parent::setUp();
67
-		$this->connection = Server::get(IDBConnection::class);
68
-		$this->phoneNumberUtil = new PhoneNumberUtil();
69
-
70
-		$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
71
-		$this->config = $this->createMock(IConfig::class);
72
-		$this->jobList = $this->createMock(IJobList::class);
73
-		$this->logger = $this->createMock(LoggerInterface::class);
74
-		$this->verificationToken = $this->createMock(IVerificationToken::class);
75
-		$this->mailer = $this->createMock(IMailer::class);
76
-		$this->defaults = $this->createMock(Defaults::class);
77
-		$this->l10nFactory = $this->createMock(IFactory::class);
78
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
79
-		$this->crypto = $this->createMock(ICrypto::class);
80
-		$this->clientService = $this->createMock(IClientService::class);
81
-
82
-		$this->accountManager = new AccountManager(
83
-			$this->connection,
84
-			$this->config,
85
-			$this->eventDispatcher,
86
-			$this->jobList,
87
-			$this->logger,
88
-			$this->verificationToken,
89
-			$this->mailer,
90
-			$this->defaults,
91
-			$this->l10nFactory,
92
-			$this->urlGenerator,
93
-			$this->crypto,
94
-			$this->phoneNumberUtil,
95
-			$this->clientService,
96
-		);
97
-	}
98
-
99
-	protected function tearDown(): void {
100
-		parent::tearDown();
101
-		$query = $this->connection->getQueryBuilder();
102
-		$query->delete($this->table)->executeStatement();
103
-	}
104
-
105
-	protected function makeUser(string $uid, string $name, ?string $email = null): IUser {
106
-		$user = $this->createMock(IUser::class);
107
-		$user->expects($this->any())
108
-			->method('getUid')
109
-			->willReturn($uid);
110
-		$user->expects($this->any())
111
-			->method('getDisplayName')
112
-			->willReturn($name);
113
-		if ($email !== null) {
114
-			$user->expects($this->any())
115
-				->method('getEMailAddress')
116
-				->willReturn($email);
117
-		}
118
-
119
-		return $user;
120
-	}
121
-
122
-	protected function populateOrUpdate(): void {
123
-		$users = [
124
-			[
125
-				'user' => $this->makeUser('j.doe', 'Jane Doe', '[email protected]'),
126
-				'data' => [
127
-					[
128
-						'name' => IAccountManager::PROPERTY_DISPLAYNAME,
129
-						'value' => 'Jane Doe',
130
-						'scope' => IAccountManager::SCOPE_PUBLISHED
131
-					],
132
-					[
133
-						'name' => IAccountManager::PROPERTY_EMAIL,
134
-						'value' => '[email protected]',
135
-						'scope' => IAccountManager::SCOPE_LOCAL
136
-					],
137
-					[
138
-						'name' => IAccountManager::PROPERTY_TWITTER,
139
-						'value' => '@sometwitter',
140
-						'scope' => IAccountManager::SCOPE_PUBLISHED
141
-					],
142
-					[
143
-						'name' => IAccountManager::PROPERTY_FEDIVERSE,
144
-						'value' => '@[email protected]',
145
-						'scope' => IAccountManager::SCOPE_PUBLISHED
146
-					],
147
-					[
148
-						'name' => IAccountManager::PROPERTY_PHONE,
149
-						'value' => '+491601231212',
150
-						'scope' => IAccountManager::SCOPE_FEDERATED
151
-					],
152
-					[
153
-						'name' => IAccountManager::PROPERTY_ADDRESS,
154
-						'value' => 'some street',
155
-						'scope' => IAccountManager::SCOPE_LOCAL
156
-					],
157
-					[
158
-						'name' => IAccountManager::PROPERTY_WEBSITE,
159
-						'value' => 'https://acme.com',
160
-						'scope' => IAccountManager::SCOPE_PRIVATE
161
-					],
162
-					[
163
-						'name' => IAccountManager::PROPERTY_ORGANISATION,
164
-						'value' => 'Some organisation',
165
-						'scope' => IAccountManager::SCOPE_LOCAL
166
-					],
167
-					[
168
-						'name' => IAccountManager::PROPERTY_ROLE,
169
-						'value' => 'Human',
170
-						'scope' => IAccountManager::SCOPE_LOCAL
171
-					],
172
-					[
173
-						'name' => IAccountManager::PROPERTY_HEADLINE,
174
-						'value' => 'Hi',
175
-						'scope' => IAccountManager::SCOPE_LOCAL
176
-					],
177
-					[
178
-						'name' => IAccountManager::PROPERTY_BIOGRAPHY,
179
-						'value' => 'Biography',
180
-						'scope' => IAccountManager::SCOPE_LOCAL
181
-					],
182
-				],
183
-			],
184
-			[
185
-				'user' => $this->makeUser('a.allison', 'Alice Allison', '[email protected]'),
186
-				'data' => [
187
-					[
188
-						'name' => IAccountManager::PROPERTY_DISPLAYNAME,
189
-						'value' => 'Alice Allison',
190
-						'scope' => IAccountManager::SCOPE_LOCAL
191
-					],
192
-					[
193
-						'name' => IAccountManager::PROPERTY_EMAIL,
194
-						'value' => '[email protected]',
195
-						'scope' => IAccountManager::SCOPE_LOCAL
196
-					],
197
-					[
198
-						'name' => IAccountManager::PROPERTY_TWITTER,
199
-						'value' => '@a_alice',
200
-						'scope' => IAccountManager::SCOPE_FEDERATED
201
-					],
202
-					[
203
-						'name' => IAccountManager::PROPERTY_FEDIVERSE,
204
-						'value' => '@[email protected]',
205
-						'scope' => IAccountManager::SCOPE_FEDERATED
206
-					],
207
-					[
208
-						'name' => IAccountManager::PROPERTY_PHONE,
209
-						'value' => '+491602312121',
210
-						'scope' => IAccountManager::SCOPE_LOCAL
211
-					],
212
-					[
213
-						'name' => IAccountManager::PROPERTY_ADDRESS,
214
-						'value' => 'Dundee Road 45',
215
-						'scope' => IAccountManager::SCOPE_LOCAL
216
-					],
217
-					[
218
-						'name' => IAccountManager::PROPERTY_WEBSITE,
219
-						'value' => 'https://example.org',
220
-						'scope' => IAccountManager::SCOPE_LOCAL
221
-					],
222
-					[
223
-						'name' => IAccountManager::PROPERTY_ORGANISATION,
224
-						'value' => 'Another organisation',
225
-						'scope' => IAccountManager::SCOPE_FEDERATED
226
-					],
227
-					[
228
-						'name' => IAccountManager::PROPERTY_ROLE,
229
-						'value' => 'Alien',
230
-						'scope' => IAccountManager::SCOPE_FEDERATED
231
-					],
232
-					[
233
-						'name' => IAccountManager::PROPERTY_HEADLINE,
234
-						'value' => 'Hello',
235
-						'scope' => IAccountManager::SCOPE_FEDERATED
236
-					],
237
-					[
238
-						'name' => IAccountManager::PROPERTY_BIOGRAPHY,
239
-						'value' => 'Different biography',
240
-						'scope' => IAccountManager::SCOPE_FEDERATED
241
-					],
242
-				],
243
-			],
244
-			[
245
-				'user' => $this->makeUser('b32c5a5b-1084-4380-8856-e5223b16de9f', 'Armel Oliseh', '[email protected]'),
246
-				'data' => [
247
-					[
248
-						'name' => IAccountManager::PROPERTY_DISPLAYNAME,
249
-						'value' => 'Armel Oliseh',
250
-						'scope' => IAccountManager::SCOPE_PUBLISHED
251
-					],
252
-					[
253
-						'name' => IAccountManager::PROPERTY_EMAIL,
254
-						'value' => '[email protected]',
255
-						'scope' => IAccountManager::SCOPE_PUBLISHED
256
-					],
257
-					[
258
-						'name' => IAccountManager::PROPERTY_TWITTER,
259
-						'value' => '',
260
-						'scope' => IAccountManager::SCOPE_LOCAL
261
-					],
262
-					[
263
-						'name' => IAccountManager::PROPERTY_FEDIVERSE,
264
-						'value' => '',
265
-						'scope' => IAccountManager::SCOPE_LOCAL
266
-					],
267
-					[
268
-						'name' => IAccountManager::PROPERTY_PHONE,
269
-						'value' => '+491603121212',
270
-						'scope' => IAccountManager::SCOPE_PUBLISHED
271
-					],
272
-					[
273
-						'name' => IAccountManager::PROPERTY_ADDRESS,
274
-						'value' => 'Sunflower Blvd. 77',
275
-						'scope' => IAccountManager::SCOPE_PUBLISHED
276
-					],
277
-					[
278
-						'name' => IAccountManager::PROPERTY_WEBSITE,
279
-						'value' => 'https://example.com',
280
-						'scope' => IAccountManager::SCOPE_PUBLISHED
281
-					],
282
-					[
283
-						'name' => IAccountManager::PROPERTY_ORGANISATION,
284
-						'value' => 'Yet another organisation',
285
-						'scope' => IAccountManager::SCOPE_PUBLISHED
286
-					],
287
-					[
288
-						'name' => IAccountManager::PROPERTY_ROLE,
289
-						'value' => 'Being',
290
-						'scope' => IAccountManager::SCOPE_PUBLISHED
291
-					],
292
-					[
293
-						'name' => IAccountManager::PROPERTY_HEADLINE,
294
-						'value' => 'This is a headline',
295
-						'scope' => IAccountManager::SCOPE_PUBLISHED
296
-					],
297
-					[
298
-						'name' => IAccountManager::PROPERTY_BIOGRAPHY,
299
-						'value' => 'Some long biography',
300
-						'scope' => IAccountManager::SCOPE_PUBLISHED
301
-					],
302
-				],
303
-			],
304
-			[
305
-				'user' => $this->makeUser('31b5316a-9b57-4b17-970a-315a4cbe73eb', 'K. Cheng', '[email protected]'),
306
-				'data' => [
307
-					[
308
-						'name' => IAccountManager::PROPERTY_DISPLAYNAME,
309
-						'value' => 'K. Cheng',
310
-						'scope' => IAccountManager::SCOPE_FEDERATED
311
-					],
312
-					[
313
-						'name' => IAccountManager::PROPERTY_EMAIL,
314
-						'value' => '[email protected]',
315
-						'scope' => IAccountManager::SCOPE_FEDERATED
316
-					],
317
-					[
318
-						'name' => IAccountManager::PROPERTY_TWITTER,
319
-						'value' => '', '
47
+    /** accounts table name */
48
+    private string $table = 'accounts';
49
+    private AccountManager $accountManager;
50
+    private IDBConnection $connection;
51
+    private IPhoneNumberUtil $phoneNumberUtil;
52
+
53
+    protected IVerificationToken&MockObject $verificationToken;
54
+    protected IMailer&MockObject $mailer;
55
+    protected ICrypto&MockObject $crypto;
56
+    protected IURLGenerator&MockObject $urlGenerator;
57
+    protected Defaults&MockObject $defaults;
58
+    protected IFactory&MockObject $l10nFactory;
59
+    protected IConfig&MockObject $config;
60
+    protected IEventDispatcher&MockObject $eventDispatcher;
61
+    protected IJobList&MockObject $jobList;
62
+    private LoggerInterface&MockObject $logger;
63
+    private IClientService&MockObject $clientService;
64
+
65
+    protected function setUp(): void {
66
+        parent::setUp();
67
+        $this->connection = Server::get(IDBConnection::class);
68
+        $this->phoneNumberUtil = new PhoneNumberUtil();
69
+
70
+        $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
71
+        $this->config = $this->createMock(IConfig::class);
72
+        $this->jobList = $this->createMock(IJobList::class);
73
+        $this->logger = $this->createMock(LoggerInterface::class);
74
+        $this->verificationToken = $this->createMock(IVerificationToken::class);
75
+        $this->mailer = $this->createMock(IMailer::class);
76
+        $this->defaults = $this->createMock(Defaults::class);
77
+        $this->l10nFactory = $this->createMock(IFactory::class);
78
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
79
+        $this->crypto = $this->createMock(ICrypto::class);
80
+        $this->clientService = $this->createMock(IClientService::class);
81
+
82
+        $this->accountManager = new AccountManager(
83
+            $this->connection,
84
+            $this->config,
85
+            $this->eventDispatcher,
86
+            $this->jobList,
87
+            $this->logger,
88
+            $this->verificationToken,
89
+            $this->mailer,
90
+            $this->defaults,
91
+            $this->l10nFactory,
92
+            $this->urlGenerator,
93
+            $this->crypto,
94
+            $this->phoneNumberUtil,
95
+            $this->clientService,
96
+        );
97
+    }
98
+
99
+    protected function tearDown(): void {
100
+        parent::tearDown();
101
+        $query = $this->connection->getQueryBuilder();
102
+        $query->delete($this->table)->executeStatement();
103
+    }
104
+
105
+    protected function makeUser(string $uid, string $name, ?string $email = null): IUser {
106
+        $user = $this->createMock(IUser::class);
107
+        $user->expects($this->any())
108
+            ->method('getUid')
109
+            ->willReturn($uid);
110
+        $user->expects($this->any())
111
+            ->method('getDisplayName')
112
+            ->willReturn($name);
113
+        if ($email !== null) {
114
+            $user->expects($this->any())
115
+                ->method('getEMailAddress')
116
+                ->willReturn($email);
117
+        }
118
+
119
+        return $user;
120
+    }
121
+
122
+    protected function populateOrUpdate(): void {
123
+        $users = [
124
+            [
125
+                'user' => $this->makeUser('j.doe', 'Jane Doe', '[email protected]'),
126
+                'data' => [
127
+                    [
128
+                        'name' => IAccountManager::PROPERTY_DISPLAYNAME,
129
+                        'value' => 'Jane Doe',
130
+                        'scope' => IAccountManager::SCOPE_PUBLISHED
131
+                    ],
132
+                    [
133
+                        'name' => IAccountManager::PROPERTY_EMAIL,
134
+                        'value' => '[email protected]',
135
+                        'scope' => IAccountManager::SCOPE_LOCAL
136
+                    ],
137
+                    [
138
+                        'name' => IAccountManager::PROPERTY_TWITTER,
139
+                        'value' => '@sometwitter',
140
+                        'scope' => IAccountManager::SCOPE_PUBLISHED
141
+                    ],
142
+                    [
143
+                        'name' => IAccountManager::PROPERTY_FEDIVERSE,
144
+                        'value' => '@[email protected]',
145
+                        'scope' => IAccountManager::SCOPE_PUBLISHED
146
+                    ],
147
+                    [
148
+                        'name' => IAccountManager::PROPERTY_PHONE,
149
+                        'value' => '+491601231212',
150
+                        'scope' => IAccountManager::SCOPE_FEDERATED
151
+                    ],
152
+                    [
153
+                        'name' => IAccountManager::PROPERTY_ADDRESS,
154
+                        'value' => 'some street',
155
+                        'scope' => IAccountManager::SCOPE_LOCAL
156
+                    ],
157
+                    [
158
+                        'name' => IAccountManager::PROPERTY_WEBSITE,
159
+                        'value' => 'https://acme.com',
160
+                        'scope' => IAccountManager::SCOPE_PRIVATE
161
+                    ],
162
+                    [
163
+                        'name' => IAccountManager::PROPERTY_ORGANISATION,
164
+                        'value' => 'Some organisation',
165
+                        'scope' => IAccountManager::SCOPE_LOCAL
166
+                    ],
167
+                    [
168
+                        'name' => IAccountManager::PROPERTY_ROLE,
169
+                        'value' => 'Human',
170
+                        'scope' => IAccountManager::SCOPE_LOCAL
171
+                    ],
172
+                    [
173
+                        'name' => IAccountManager::PROPERTY_HEADLINE,
174
+                        'value' => 'Hi',
175
+                        'scope' => IAccountManager::SCOPE_LOCAL
176
+                    ],
177
+                    [
178
+                        'name' => IAccountManager::PROPERTY_BIOGRAPHY,
179
+                        'value' => 'Biography',
180
+                        'scope' => IAccountManager::SCOPE_LOCAL
181
+                    ],
182
+                ],
183
+            ],
184
+            [
185
+                'user' => $this->makeUser('a.allison', 'Alice Allison', '[email protected]'),
186
+                'data' => [
187
+                    [
188
+                        'name' => IAccountManager::PROPERTY_DISPLAYNAME,
189
+                        'value' => 'Alice Allison',
190
+                        'scope' => IAccountManager::SCOPE_LOCAL
191
+                    ],
192
+                    [
193
+                        'name' => IAccountManager::PROPERTY_EMAIL,
194
+                        'value' => '[email protected]',
195
+                        'scope' => IAccountManager::SCOPE_LOCAL
196
+                    ],
197
+                    [
198
+                        'name' => IAccountManager::PROPERTY_TWITTER,
199
+                        'value' => '@a_alice',
200
+                        'scope' => IAccountManager::SCOPE_FEDERATED
201
+                    ],
202
+                    [
203
+                        'name' => IAccountManager::PROPERTY_FEDIVERSE,
204
+                        'value' => '@[email protected]',
205
+                        'scope' => IAccountManager::SCOPE_FEDERATED
206
+                    ],
207
+                    [
208
+                        'name' => IAccountManager::PROPERTY_PHONE,
209
+                        'value' => '+491602312121',
210
+                        'scope' => IAccountManager::SCOPE_LOCAL
211
+                    ],
212
+                    [
213
+                        'name' => IAccountManager::PROPERTY_ADDRESS,
214
+                        'value' => 'Dundee Road 45',
215
+                        'scope' => IAccountManager::SCOPE_LOCAL
216
+                    ],
217
+                    [
218
+                        'name' => IAccountManager::PROPERTY_WEBSITE,
219
+                        'value' => 'https://example.org',
220
+                        'scope' => IAccountManager::SCOPE_LOCAL
221
+                    ],
222
+                    [
223
+                        'name' => IAccountManager::PROPERTY_ORGANISATION,
224
+                        'value' => 'Another organisation',
225
+                        'scope' => IAccountManager::SCOPE_FEDERATED
226
+                    ],
227
+                    [
228
+                        'name' => IAccountManager::PROPERTY_ROLE,
229
+                        'value' => 'Alien',
230
+                        'scope' => IAccountManager::SCOPE_FEDERATED
231
+                    ],
232
+                    [
233
+                        'name' => IAccountManager::PROPERTY_HEADLINE,
234
+                        'value' => 'Hello',
235
+                        'scope' => IAccountManager::SCOPE_FEDERATED
236
+                    ],
237
+                    [
238
+                        'name' => IAccountManager::PROPERTY_BIOGRAPHY,
239
+                        'value' => 'Different biography',
240
+                        'scope' => IAccountManager::SCOPE_FEDERATED
241
+                    ],
242
+                ],
243
+            ],
244
+            [
245
+                'user' => $this->makeUser('b32c5a5b-1084-4380-8856-e5223b16de9f', 'Armel Oliseh', '[email protected]'),
246
+                'data' => [
247
+                    [
248
+                        'name' => IAccountManager::PROPERTY_DISPLAYNAME,
249
+                        'value' => 'Armel Oliseh',
250
+                        'scope' => IAccountManager::SCOPE_PUBLISHED
251
+                    ],
252
+                    [
253
+                        'name' => IAccountManager::PROPERTY_EMAIL,
254
+                        'value' => '[email protected]',
255
+                        'scope' => IAccountManager::SCOPE_PUBLISHED
256
+                    ],
257
+                    [
258
+                        'name' => IAccountManager::PROPERTY_TWITTER,
259
+                        'value' => '',
260
+                        'scope' => IAccountManager::SCOPE_LOCAL
261
+                    ],
262
+                    [
263
+                        'name' => IAccountManager::PROPERTY_FEDIVERSE,
264
+                        'value' => '',
265
+                        'scope' => IAccountManager::SCOPE_LOCAL
266
+                    ],
267
+                    [
268
+                        'name' => IAccountManager::PROPERTY_PHONE,
269
+                        'value' => '+491603121212',
270
+                        'scope' => IAccountManager::SCOPE_PUBLISHED
271
+                    ],
272
+                    [
273
+                        'name' => IAccountManager::PROPERTY_ADDRESS,
274
+                        'value' => 'Sunflower Blvd. 77',
275
+                        'scope' => IAccountManager::SCOPE_PUBLISHED
276
+                    ],
277
+                    [
278
+                        'name' => IAccountManager::PROPERTY_WEBSITE,
279
+                        'value' => 'https://example.com',
280
+                        'scope' => IAccountManager::SCOPE_PUBLISHED
281
+                    ],
282
+                    [
283
+                        'name' => IAccountManager::PROPERTY_ORGANISATION,
284
+                        'value' => 'Yet another organisation',
285
+                        'scope' => IAccountManager::SCOPE_PUBLISHED
286
+                    ],
287
+                    [
288
+                        'name' => IAccountManager::PROPERTY_ROLE,
289
+                        'value' => 'Being',
290
+                        'scope' => IAccountManager::SCOPE_PUBLISHED
291
+                    ],
292
+                    [
293
+                        'name' => IAccountManager::PROPERTY_HEADLINE,
294
+                        'value' => 'This is a headline',
295
+                        'scope' => IAccountManager::SCOPE_PUBLISHED
296
+                    ],
297
+                    [
298
+                        'name' => IAccountManager::PROPERTY_BIOGRAPHY,
299
+                        'value' => 'Some long biography',
300
+                        'scope' => IAccountManager::SCOPE_PUBLISHED
301
+                    ],
302
+                ],
303
+            ],
304
+            [
305
+                'user' => $this->makeUser('31b5316a-9b57-4b17-970a-315a4cbe73eb', 'K. Cheng', '[email protected]'),
306
+                'data' => [
307
+                    [
308
+                        'name' => IAccountManager::PROPERTY_DISPLAYNAME,
309
+                        'value' => 'K. Cheng',
310
+                        'scope' => IAccountManager::SCOPE_FEDERATED
311
+                    ],
312
+                    [
313
+                        'name' => IAccountManager::PROPERTY_EMAIL,
314
+                        'value' => '[email protected]',
315
+                        'scope' => IAccountManager::SCOPE_FEDERATED
316
+                    ],
317
+                    [
318
+                        'name' => IAccountManager::PROPERTY_TWITTER,
319
+                        'value' => '', '
320 320
 						scope' => IAccountManager::SCOPE_LOCAL
321
-					],
322
-					[
323
-						'name' => IAccountManager::PROPERTY_FEDIVERSE,
324
-						'value' => '', '
321
+                    ],
322
+                    [
323
+                        'name' => IAccountManager::PROPERTY_FEDIVERSE,
324
+                        'value' => '', '
325 325
 						scope' => IAccountManager::SCOPE_LOCAL
326
-					],
327
-					[
328
-						'name' => IAccountManager::PROPERTY_PHONE,
329
-						'value' => '+71601212123',
330
-						'scope' => IAccountManager::SCOPE_LOCAL
331
-					],
332
-					[
333
-						'name' => IAccountManager::PROPERTY_ADDRESS,
334
-						'value' => 'Pinapple Street 22',
335
-						'scope' => IAccountManager::SCOPE_LOCAL
336
-					],
337
-					[
338
-						'name' => IAccountManager::PROPERTY_WEBSITE,
339
-						'value' => 'https://emca.com',
340
-						'scope' => IAccountManager::SCOPE_FEDERATED
341
-					],
342
-					[
343
-						'name' => IAccountManager::PROPERTY_ORGANISATION,
344
-						'value' => 'Organisation A',
345
-						'scope' => IAccountManager::SCOPE_LOCAL
346
-					],
347
-					[
348
-						'name' => IAccountManager::PROPERTY_ROLE,
349
-						'value' => 'Animal',
350
-						'scope' => IAccountManager::SCOPE_LOCAL
351
-					],
352
-					[
353
-						'name' => IAccountManager::PROPERTY_HEADLINE,
354
-						'value' => 'My headline',
355
-						'scope' => IAccountManager::SCOPE_LOCAL
356
-					],
357
-					[
358
-						'name' => IAccountManager::PROPERTY_BIOGRAPHY,
359
-						'value' => 'Short biography',
360
-						'scope' => IAccountManager::SCOPE_LOCAL
361
-					],
362
-					[
363
-						'name' => IAccountManager::COLLECTION_EMAIL,
364
-						'value' => '[email protected]',
365
-						'scope' => IAccountManager::SCOPE_LOCAL
366
-					],
367
-					[
368
-						'name' => IAccountManager::COLLECTION_EMAIL,
369
-						'value' => '[email protected]',
370
-						'scope' => IAccountManager::SCOPE_LOCAL
371
-					],
372
-				],
373
-			],
374
-			[
375
-				'user' => $this->makeUser('[email protected]', 'Goodpal, Kim', '[email protected]'),
376
-				'data' => [
377
-					[
378
-						'name' => IAccountManager::PROPERTY_DISPLAYNAME,
379
-						'value' => 'Goodpal, Kim',
380
-						'scope' => IAccountManager::SCOPE_PUBLISHED
381
-					],
382
-					[
383
-						'name' => IAccountManager::PROPERTY_EMAIL,
384
-						'value' => '[email protected]',
385
-						'scope' => IAccountManager::SCOPE_PUBLISHED
386
-					],
387
-					[
388
-						'name' => IAccountManager::PROPERTY_TWITTER,
389
-						'value' => '',
390
-						'scope' => IAccountManager::SCOPE_LOCAL
391
-					],
392
-					[
393
-						'name' => IAccountManager::PROPERTY_FEDIVERSE,
394
-						'value' => '',
395
-						'scope' => IAccountManager::SCOPE_LOCAL
396
-					],
397
-					[
398
-						'name' => IAccountManager::PROPERTY_PHONE,
399
-						'value' => '+71602121231',
400
-						'scope' => IAccountManager::SCOPE_FEDERATED
401
-					],
402
-					[
403
-						'name' => IAccountManager::PROPERTY_ADDRESS,
404
-						'value' => 'Octopus Ave 17',
405
-						'scope' => IAccountManager::SCOPE_FEDERATED
406
-					],
407
-					[
408
-						'name' => IAccountManager::PROPERTY_WEBSITE,
409
-						'value' => 'https://elpmaxe.org',
410
-						'scope' => IAccountManager::SCOPE_PUBLISHED
411
-					],
412
-					[
413
-						'name' => IAccountManager::PROPERTY_ORGANISATION,
414
-						'value' => 'Organisation B',
415
-						'scope' => IAccountManager::SCOPE_FEDERATED
416
-					],
417
-					[
418
-						'name' => IAccountManager::PROPERTY_ROLE,
419
-						'value' => 'Organism',
420
-						'scope' => IAccountManager::SCOPE_FEDERATED
421
-					],
422
-					[
423
-						'name' => IAccountManager::PROPERTY_HEADLINE,
424
-						'value' => 'Best headline',
425
-						'scope' => IAccountManager::SCOPE_FEDERATED
426
-					],
427
-					[
428
-						'name' => IAccountManager::PROPERTY_BIOGRAPHY,
429
-						'value' => 'Autobiography',
430
-						'scope' => IAccountManager::SCOPE_FEDERATED
431
-					],
432
-				],
433
-			],
434
-		];
435
-		$this->config->expects($this->exactly(count($users)))->method('getSystemValue')->with('account_manager.default_property_scope', [])->willReturn([]);
436
-		foreach ($users as $userInfo) {
437
-			$this->invokePrivate($this->accountManager, 'updateUser', [$userInfo['user'], $userInfo['data'], null, false]);
438
-		}
439
-	}
440
-
441
-	/**
442
-	 * get a instance of the accountManager
443
-	 *
444
-	 * @return MockObject | AccountManager
445
-	 */
446
-	public function getInstance(?array $mockedMethods = null) {
447
-		return $this->getMockBuilder(AccountManager::class)
448
-			->setConstructorArgs([
449
-				$this->connection,
450
-				$this->config,
451
-				$this->eventDispatcher,
452
-				$this->jobList,
453
-				$this->logger,
454
-				$this->verificationToken,
455
-				$this->mailer,
456
-				$this->defaults,
457
-				$this->l10nFactory,
458
-				$this->urlGenerator,
459
-				$this->crypto,
460
-				$this->phoneNumberUtil,
461
-				$this->clientService,
462
-			])
463
-			->onlyMethods($mockedMethods)
464
-			->getMock();
465
-	}
466
-
467
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTrueFalse')]
468
-	public function testUpdateUser(array $newData, array $oldData, bool $insertNew, bool $updateExisting): void {
469
-		$accountManager = $this->getInstance(['getUser', 'insertNewUser', 'updateExistingUser']);
470
-		/** @var IUser $user */
471
-		$user = $this->createMock(IUser::class);
472
-
473
-		if ($updateExisting) {
474
-			$accountManager->expects($this->once())->method('updateExistingUser')
475
-				->with($user, $newData);
476
-			$accountManager->expects($this->never())->method('insertNewUser');
477
-		}
478
-		if ($insertNew) {
479
-			$accountManager->expects($this->once())->method('insertNewUser')
480
-				->with($user, $newData);
481
-			$accountManager->expects($this->never())->method('updateExistingUser');
482
-		}
483
-
484
-		if (!$insertNew && !$updateExisting) {
485
-			$accountManager->expects($this->never())->method('updateExistingUser');
486
-			$accountManager->expects($this->never())->method('insertNewUser');
487
-			$this->eventDispatcher->expects($this->never())->method('dispatchTyped');
488
-		} else {
489
-			$this->eventDispatcher->expects($this->once())->method('dispatchTyped')
490
-				->willReturnCallback(
491
-					function ($event) use ($user, $newData): void {
492
-						$this->assertInstanceOf(UserUpdatedEvent::class, $event);
493
-						$this->assertSame($user, $event->getUser());
494
-						$this->assertSame($newData, $event->getData());
495
-					}
496
-				);
497
-		}
498
-
499
-		$this->invokePrivate($accountManager, 'updateUser', [$user, $newData, $oldData]);
500
-	}
501
-
502
-	public static function dataTrueFalse(): array {
503
-		return [
504
-			#$newData | $oldData | $insertNew | $updateExisting
505
-			[['myProperty' => ['value' => 'newData']], ['myProperty' => ['value' => 'oldData']], false, true],
506
-			[['myProperty' => ['value' => 'oldData']], ['myProperty' => ['value' => 'oldData']], false, false]
507
-		];
508
-	}
509
-
510
-	public function testAddMissingDefaults(): void {
511
-		$user = $this->createMock(IUser::class);
512
-
513
-		$this->config
514
-			->expects($this->once())
515
-			->method('getAppValue')
516
-			->with('settings', 'profile_enabled_by_default', '1')
517
-			->willReturn('1');
518
-
519
-		$input = [
520
-			[
521
-				'name' => IAccountManager::PROPERTY_DISPLAYNAME,
522
-				'value' => 'bob',
523
-				'verified' => IAccountManager::NOT_VERIFIED,
524
-			],
525
-			[
526
-				'name' => IAccountManager::PROPERTY_EMAIL,
527
-				'value' => '[email protected]',
528
-			],
529
-		];
530
-
531
-		$expected = [
532
-			[
533
-				'name' => IAccountManager::PROPERTY_DISPLAYNAME,
534
-				'value' => 'bob',
535
-				'scope' => IAccountManager::SCOPE_FEDERATED,
536
-				'verified' => IAccountManager::NOT_VERIFIED,
537
-			],
538
-
539
-			[
540
-				'name' => IAccountManager::PROPERTY_EMAIL,
541
-				'value' => '[email protected]',
542
-				'scope' => IAccountManager::SCOPE_FEDERATED,
543
-				'verified' => IAccountManager::NOT_VERIFIED,
544
-			],
545
-
546
-			[
547
-				'name' => IAccountManager::PROPERTY_ADDRESS,
548
-				'value' => '',
549
-				'scope' => IAccountManager::SCOPE_LOCAL,
550
-				'verified' => IAccountManager::NOT_VERIFIED,
551
-			],
552
-
553
-			[
554
-				'name' => IAccountManager::PROPERTY_WEBSITE,
555
-				'value' => '',
556
-				'scope' => IAccountManager::SCOPE_LOCAL,
557
-				'verified' => IAccountManager::NOT_VERIFIED,
558
-			],
559
-
560
-			[
561
-				'name' => IAccountManager::PROPERTY_AVATAR,
562
-				'scope' => IAccountManager::SCOPE_FEDERATED
563
-			],
564
-
565
-			[
566
-				'name' => IAccountManager::PROPERTY_PHONE,
567
-				'value' => '',
568
-				'scope' => IAccountManager::SCOPE_LOCAL,
569
-				'verified' => IAccountManager::NOT_VERIFIED,
570
-			],
571
-
572
-			[
573
-				'name' => IAccountManager::PROPERTY_TWITTER,
574
-				'value' => '',
575
-				'scope' => IAccountManager::SCOPE_LOCAL,
576
-				'verified' => IAccountManager::NOT_VERIFIED,
577
-			],
578
-
579
-			[
580
-				'name' => IAccountManager::PROPERTY_BLUESKY,
581
-				'value' => '',
582
-				'scope' => IAccountManager::SCOPE_LOCAL,
583
-				'verified' => IAccountManager::NOT_VERIFIED,
584
-			],
585
-
586
-			[
587
-				'name' => IAccountManager::PROPERTY_FEDIVERSE,
588
-				'value' => '',
589
-				'scope' => IAccountManager::SCOPE_LOCAL,
590
-				'verified' => IAccountManager::NOT_VERIFIED,
591
-			],
592
-
593
-			[
594
-				'name' => IAccountManager::PROPERTY_ORGANISATION,
595
-				'value' => '',
596
-				'scope' => IAccountManager::SCOPE_LOCAL,
597
-			],
598
-
599
-			[
600
-				'name' => IAccountManager::PROPERTY_ROLE,
601
-				'value' => '',
602
-				'scope' => IAccountManager::SCOPE_LOCAL,
603
-			],
604
-
605
-			[
606
-				'name' => IAccountManager::PROPERTY_HEADLINE,
607
-				'value' => '',
608
-				'scope' => IAccountManager::SCOPE_LOCAL,
609
-			],
610
-
611
-			[
612
-				'name' => IAccountManager::PROPERTY_BIOGRAPHY,
613
-				'value' => '',
614
-				'scope' => IAccountManager::SCOPE_LOCAL,
615
-			],
616
-
617
-			[
618
-				'name' => IAccountManager::PROPERTY_BIRTHDATE,
619
-				'value' => '',
620
-				'scope' => IAccountManager::SCOPE_LOCAL,
621
-			],
622
-
623
-			[
624
-				'name' => IAccountManager::PROPERTY_PROFILE_ENABLED,
625
-				'value' => '1',
626
-			],
627
-
628
-			[
629
-				'name' => IAccountManager::PROPERTY_PRONOUNS,
630
-				'value' => '',
631
-				'scope' => IAccountManager::SCOPE_FEDERATED,
632
-			],
633
-		];
634
-		$this->config->expects($this->once())->method('getSystemValue')->with('account_manager.default_property_scope', [])->willReturn([]);
635
-
636
-		$defaultUserRecord = $this->invokePrivate($this->accountManager, 'buildDefaultUserRecord', [$user]);
637
-		$result = $this->invokePrivate($this->accountManager, 'addMissingDefaultValues', [$input, $defaultUserRecord]);
638
-
639
-		$this->assertSame($expected, $result);
640
-	}
641
-
642
-	public function testGetAccount(): void {
643
-		$accountManager = $this->getInstance(['getUser']);
644
-		/** @var IUser $user */
645
-		$user = $this->createMock(IUser::class);
646
-
647
-		$data = [
648
-			[
649
-				'value' => '@twitterhandle',
650
-				'scope' => IAccountManager::SCOPE_LOCAL,
651
-				'verified' => IAccountManager::NOT_VERIFIED,
652
-				'name' => IAccountManager::PROPERTY_TWITTER,
653
-			],
654
-			[
655
-				'value' => '@[email protected]',
656
-				'scope' => IAccountManager::SCOPE_LOCAL,
657
-				'verified' => IAccountManager::NOT_VERIFIED,
658
-				'name' => IAccountManager::PROPERTY_FEDIVERSE,
659
-			],
660
-			[
661
-				'value' => '[email protected]',
662
-				'scope' => IAccountManager::SCOPE_PUBLISHED,
663
-				'verified' => IAccountManager::VERIFICATION_IN_PROGRESS,
664
-				'name' => IAccountManager::PROPERTY_EMAIL,
665
-			],
666
-			[
667
-				'value' => 'https://example.com',
668
-				'scope' => IAccountManager::SCOPE_FEDERATED,
669
-				'verified' => IAccountManager::VERIFIED,
670
-				'name' => IAccountManager::PROPERTY_WEBSITE,
671
-			],
672
-		];
673
-		$expected = new Account($user);
674
-		$expected->setProperty(IAccountManager::PROPERTY_TWITTER, '@twitterhandle', IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
675
-		$expected->setProperty(IAccountManager::PROPERTY_FEDIVERSE, '@[email protected]', IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
676
-		$expected->setProperty(IAccountManager::PROPERTY_EMAIL, '[email protected]', IAccountManager::SCOPE_PUBLISHED, IAccountManager::VERIFICATION_IN_PROGRESS);
677
-		$expected->setProperty(IAccountManager::PROPERTY_WEBSITE, 'https://example.com', IAccountManager::SCOPE_FEDERATED, IAccountManager::VERIFIED);
678
-
679
-		$accountManager->expects($this->once())
680
-			->method('getUser')
681
-			->willReturn($data);
682
-		$this->assertEquals($expected, $accountManager->getAccount($user));
683
-	}
684
-
685
-	public static function dataParsePhoneNumber(): array {
686
-		return [
687
-			['0711 / 25 24 28-90', 'DE', '+4971125242890'],
688
-			['0711 / 25 24 28-90', '', null],
689
-			['+49 711 / 25 24 28-90', '', '+4971125242890'],
690
-		];
691
-	}
692
-
693
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataParsePhoneNumber')]
694
-	public function testSanitizePhoneNumberOnUpdateAccount(string $phoneInput, string $defaultRegion, ?string $phoneNumber): void {
695
-		$this->config->method('getSystemValueString')
696
-			->willReturn($defaultRegion);
697
-
698
-		$user = $this->createMock(IUser::class);
699
-		$account = new Account($user);
700
-		$account->setProperty(IAccountManager::PROPERTY_PHONE, $phoneInput, IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
701
-		$manager = $this->getInstance(['getUser', 'updateUser']);
702
-		$manager->method('getUser')
703
-			->with($user, false)
704
-			->willReturn([]);
705
-		$manager->expects($phoneNumber === null ? self::never() : self::once())
706
-			->method('updateUser');
707
-
708
-		if ($phoneNumber === null) {
709
-			$this->expectException(\InvalidArgumentException::class);
710
-		}
711
-
712
-		$manager->updateAccount($account);
713
-
714
-		if ($phoneNumber !== null) {
715
-			self::assertEquals($phoneNumber, $account->getProperty(IAccountManager::PROPERTY_PHONE)->getValue());
716
-		}
717
-	}
718
-
719
-	public static function dataSanitizeOnUpdate(): array {
720
-		return [
721
-			[IAccountManager::PROPERTY_WEBSITE, 'https://nextcloud.com', 'https://nextcloud.com'],
722
-			[IAccountManager::PROPERTY_WEBSITE, 'http://nextcloud.com', 'http://nextcloud.com'],
723
-			[IAccountManager::PROPERTY_WEBSITE, 'ftp://nextcloud.com', null],
724
-			[IAccountManager::PROPERTY_WEBSITE, '//nextcloud.com/', null],
725
-			[IAccountManager::PROPERTY_WEBSITE, 'https:///?query', null],
726
-
727
-			[IAccountManager::PROPERTY_TWITTER, '@nextcloud', 'nextcloud'],
728
-			[IAccountManager::PROPERTY_TWITTER, '_nextcloud', '_nextcloud'],
729
-			[IAccountManager::PROPERTY_TWITTER, 'FooB4r', 'FooB4r'],
730
-			[IAccountManager::PROPERTY_TWITTER, 'X', null],
731
-			[IAccountManager::PROPERTY_TWITTER, 'next.cloud', null],
732
-			[IAccountManager::PROPERTY_TWITTER, 'ab/cd.zip', null],
733
-			[IAccountManager::PROPERTY_TWITTER, 'tooLongForTwitterAndX', null],
734
-
735
-			[IAccountManager::PROPERTY_FEDIVERSE, '[email protected]', '[email protected]'],
736
-			[IAccountManager::PROPERTY_FEDIVERSE, '@[email protected]', '[email protected]'],
737
-			[IAccountManager::PROPERTY_FEDIVERSE, '[email protected]', '[email protected]'],
738
-			[IAccountManager::PROPERTY_FEDIVERSE, 'invalid/[email protected]', null],
739
-			[IAccountManager::PROPERTY_FEDIVERSE, '[email protected]/malware.exe', null],
740
-			[IAccountManager::PROPERTY_FEDIVERSE, '@is-it-a-host-or-name', null],
741
-			[IAccountManager::PROPERTY_FEDIVERSE, 'only-a-name', null],
742
-		];
743
-	}
744
-
745
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataSanitizeOnUpdate')]
746
-	public function testSanitizingOnUpdateAccount(string $property, string $input, ?string $output): void {
747
-
748
-		if ($property === IAccountManager::PROPERTY_FEDIVERSE) {
749
-			// We do not test the server response here we do this in the `testSanitizingFediverseServer`
750
-			$this->config
751
-				->method('getSystemValueBool')
752
-				->with('has_internet_connection', true)
753
-				->willReturn(false);
754
-		}
755
-
756
-		$user = $this->createMock(IUser::class);
757
-
758
-		$account = new Account($user);
759
-		$account->setProperty($property, $input, IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
760
-
761
-		$manager = $this->getInstance(['getUser', 'updateUser']);
762
-		$manager->method('getUser')
763
-			->with($user, false)
764
-			->willReturn([]);
765
-		$manager->expects($output === null ? self::never() : self::once())
766
-			->method('updateUser');
767
-
768
-		if ($output === null) {
769
-			$this->expectException(\InvalidArgumentException::class);
770
-			$this->expectExceptionMessage($property);
771
-		}
772
-
773
-		$manager->updateAccount($account);
774
-
775
-		if ($output !== null) {
776
-			self::assertEquals($output, $account->getProperty($property)->getValue());
777
-		}
778
-	}
779
-
780
-	public static function dataSanitizeFediverseServer(): array {
781
-		return [
782
-			'no internet' => [
783
-				'@[email protected]',
784
-				'[email protected]',
785
-				false,
786
-				null,
787
-			],
788
-			'no internet - no at' => [
789
-				'[email protected]',
790
-				'[email protected]',
791
-				false,
792
-				null,
793
-			],
794
-			'valid response' => [
795
-				'@[email protected]',
796
-				'[email protected]',
797
-				true,
798
-				json_encode([
799
-					'subject' => 'acct:[email protected]',
800
-					'links' => [
801
-						[
802
-							'rel' => 'self',
803
-							'type' => 'application/activity+json',
804
-							'href' => 'https://example.com/users/foo',
805
-						],
806
-					],
807
-				]),
808
-			],
809
-			'valid response - no at' => [
810
-				'[email protected]',
811
-				'[email protected]',
812
-				true,
813
-				json_encode([
814
-					'subject' => 'acct:[email protected]',
815
-					'links' => [
816
-						[
817
-							'rel' => 'self',
818
-							'type' => 'application/activity+json',
819
-							'href' => 'https://example.com/users/foo',
820
-						],
821
-					],
822
-				]),
823
-			],
824
-			// failures
825
-			'invalid response' => [
826
-				'@[email protected]',
827
-				null,
828
-				true,
829
-				json_encode([
830
-					'subject' => 'acct:[email protected]',
831
-					'links' => [],
832
-				]),
833
-			],
834
-			'no response' => [
835
-				'@[email protected]',
836
-				null,
837
-				true,
838
-				null,
839
-			],
840
-			'wrong user' => [
841
-				'@[email protected]',
842
-				null,
843
-				true,
844
-				json_encode([
845
-					'links' => [],
846
-				]),
847
-			],
848
-		];
849
-	}
850
-
851
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataSanitizeFediverseServer')]
852
-	public function testSanitizingFediverseServer(string $input, ?string $output, bool $hasInternet, ?string $serverResponse): void {
853
-		$this->config->expects(self::once())
854
-			->method('getSystemValueBool')
855
-			->with('has_internet_connection', true)
856
-			->willReturn($hasInternet);
857
-
858
-		if ($hasInternet) {
859
-			$client = $this->createMock(IClient::class);
860
-			if ($serverResponse !== null) {
861
-				$response = $this->createMock(IResponse::class);
862
-				$response->method('getBody')
863
-					->willReturn($serverResponse);
864
-				$client->expects(self::once())
865
-					->method('get')
866
-					->with('https://example.com/.well-known/webfinger?resource=acct:[email protected]')
867
-					->willReturn($response);
868
-			} else {
869
-				$client->expects(self::once())
870
-					->method('get')
871
-					->with('https://example.com/.well-known/webfinger?resource=acct:[email protected]')
872
-					->willThrowException(new \Exception('404'));
873
-			}
874
-
875
-			$this->clientService
876
-				->expects(self::once())
877
-				->method('newClient')
878
-				->willReturn($client);
879
-		} else {
880
-			$this->clientService
881
-				->expects(self::never())
882
-				->method('newClient');
883
-		}
884
-
885
-		$user = $this->createMock(IUser::class);
886
-		$account = new Account($user);
887
-		$account->setProperty(IAccountManager::PROPERTY_FEDIVERSE, $input, IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
888
-
889
-		$manager = $this->getInstance(['getUser', 'updateUser']);
890
-		$manager->method('getUser')
891
-			->with($user, false)
892
-			->willReturn([]);
893
-		$manager->expects($output === null ? self::never() : self::once())
894
-			->method('updateUser');
895
-
896
-		if ($output === null) {
897
-			$this->expectException(\InvalidArgumentException::class);
898
-			$this->expectExceptionMessage(IAccountManager::PROPERTY_FEDIVERSE);
899
-		}
900
-
901
-		$manager->updateAccount($account);
902
-
903
-		if ($output !== null) {
904
-			self::assertEquals($output, $account->getProperty(IAccountManager::PROPERTY_FEDIVERSE)->getValue());
905
-		}
906
-	}
907
-
908
-	#[\PHPUnit\Framework\Attributes\DataProvider('searchDataProvider')]
909
-	public function testSearchUsers(string $property, array $values, array $expected): void {
910
-		$this->populateOrUpdate();
911
-
912
-		$matchedUsers = $this->accountManager->searchUsers($property, $values);
913
-		foreach ($expected as $expectedEntry) {
914
-			$this->assertContains($expectedEntry, $matchedUsers);
915
-		}
916
-		if (empty($expected)) {
917
-			$this->assertEmpty($matchedUsers);
918
-		}
919
-	}
920
-
921
-	public static function searchDataProvider(): array {
922
-		return [
923
-			[ #0 Search for an existing name
924
-				IAccountManager::PROPERTY_DISPLAYNAME,
925
-				['Jane Doe'],
926
-				['Jane Doe' => 'j.doe']
927
-			],
928
-			[ #1 Search for part of a name (no result)
929
-				IAccountManager::PROPERTY_DISPLAYNAME,
930
-				['Jane'],
931
-				[]
932
-			],
933
-			[ #2 Search for part of a name (no result, test wildcard)
934
-				IAccountManager::PROPERTY_DISPLAYNAME,
935
-				['Jane%'],
936
-				[]
937
-			],
938
-			[ #3 Search for phone
939
-				IAccountManager::PROPERTY_PHONE,
940
-				['+491603121212'],
941
-				['+491603121212' => 'b32c5a5b-1084-4380-8856-e5223b16de9f'],
942
-			],
943
-			[ #4 Search for twitter handles
944
-				IAccountManager::PROPERTY_TWITTER,
945
-				['@sometwitter', '@a_alice', '@unseen'],
946
-				['@sometwitter' => 'j.doe', '@a_alice' => 'a.allison'],
947
-			],
948
-			[ #5 Search for email
949
-				IAccountManager::PROPERTY_EMAIL,
950
-				['[email protected]'],
951
-				['[email protected]' => '31b5316a-9b57-4b17-970a-315a4cbe73eb'],
952
-			],
953
-			[ #6 Search for email by additional email
954
-				IAccountManager::PROPERTY_EMAIL,
955
-				['[email protected]'],
956
-				['[email protected]' => '31b5316a-9b57-4b17-970a-315a4cbe73eb'],
957
-			],
958
-			[ #7 Search for additional email
959
-				IAccountManager::COLLECTION_EMAIL,
960
-				['[email protected]', '[email protected]'],
961
-				['[email protected]' => '31b5316a-9b57-4b17-970a-315a4cbe73eb'],
962
-			],
963
-			[ #8 Search for email by additional email (two valid search values, but the same user)
964
-				IAccountManager::PROPERTY_EMAIL,
965
-				['[email protected]', '[email protected]'],
966
-				[
967
-					'[email protected]' => '31b5316a-9b57-4b17-970a-315a4cbe73eb',
968
-				],
969
-			],
970
-		];
971
-	}
972
-
973
-	public static function dataCheckEmailVerification(): array {
974
-		return [
975
-			[['steve', 'Steve Smith', '[email protected]'], null],
976
-			[['emma', 'Emma Morales', '[email protected]'], '[email protected]'],
977
-			[['[email protected]', 'Sarah Foster', '[email protected]'], null],
978
-			[['[email protected]', 'Cole Harrison', '[email protected]'], '[email protected]'],
979
-			[['8d29e358-cf69-4849-bbf9-28076c0b908b', 'Alice McPherson', '[email protected]'], '[email protected]'],
980
-			[['11da2744-3f4d-4c17-8c13-4c057a379237', 'James Loranger', '[email protected]'], ''],
981
-		];
982
-	}
983
-
984
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataCheckEmailVerification')]
985
-	public function testCheckEmailVerification(array $userData, ?string $newEmail): void {
986
-		$user = $this->makeUser(...$userData);
987
-		// Once because of getAccount, once because of getUser
988
-		$this->config->expects($this->exactly(2))->method('getSystemValue')->with('account_manager.default_property_scope', [])->willReturn([]);
989
-		$account = $this->accountManager->getAccount($user);
990
-		$emailUpdated = false;
991
-
992
-		if (!empty($newEmail)) {
993
-			$account->getProperty(IAccountManager::PROPERTY_EMAIL)->setValue($newEmail);
994
-			$emailUpdated = true;
995
-		}
996
-
997
-		if ($emailUpdated) {
998
-			$this->jobList->expects($this->once())
999
-				->method('add')
1000
-				->with(VerifyUserData::class);
1001
-		} else {
1002
-			$this->jobList->expects($this->never())
1003
-				->method('add')
1004
-				->with(VerifyUserData::class);
1005
-		}
1006
-
1007
-		/** @var array $oldData */
1008
-		$oldData = $this->invokePrivate($this->accountManager, 'getUser', [$user, false]);
1009
-		$this->invokePrivate($this->accountManager, 'checkEmailVerification', [$account, $oldData]);
1010
-	}
1011
-
1012
-	public static function dataSetDefaultPropertyScopes(): array {
1013
-		return [
1014
-			[
1015
-				[],
1016
-				[
1017
-					IAccountManager::PROPERTY_DISPLAYNAME => IAccountManager::SCOPE_FEDERATED,
1018
-					IAccountManager::PROPERTY_ADDRESS => IAccountManager::SCOPE_LOCAL,
1019
-					IAccountManager::PROPERTY_EMAIL => IAccountManager::SCOPE_FEDERATED,
1020
-					IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_LOCAL,
1021
-				]
1022
-			],
1023
-			[
1024
-				[
1025
-					IAccountManager::PROPERTY_DISPLAYNAME => IAccountManager::SCOPE_FEDERATED,
1026
-					IAccountManager::PROPERTY_EMAIL => IAccountManager::SCOPE_LOCAL,
1027
-					IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_PRIVATE,
1028
-				], [
1029
-					IAccountManager::PROPERTY_DISPLAYNAME => IAccountManager::SCOPE_FEDERATED,
1030
-					IAccountManager::PROPERTY_EMAIL => IAccountManager::SCOPE_LOCAL,
1031
-					IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_PRIVATE,
1032
-				]
1033
-			],
1034
-			[
1035
-				[
1036
-					IAccountManager::PROPERTY_ADDRESS => 'invalid scope',
1037
-					'invalid property' => IAccountManager::SCOPE_LOCAL,
1038
-					IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_PRIVATE,
1039
-				],
1040
-				[
1041
-					IAccountManager::PROPERTY_ADDRESS => IAccountManager::SCOPE_LOCAL,
1042
-					IAccountManager::PROPERTY_EMAIL => IAccountManager::SCOPE_FEDERATED,
1043
-					IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_PRIVATE,
1044
-				]
1045
-			],
1046
-		];
1047
-	}
1048
-
1049
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataSetDefaultPropertyScopes')]
1050
-	public function testSetDefaultPropertyScopes(array $propertyScopes, array $expectedResultScopes): void {
1051
-		$user = $this->makeUser('steve', 'Steve Smith', '[email protected]');
1052
-		$this->config->expects($this->once())->method('getSystemValue')->with('account_manager.default_property_scope', [])->willReturn($propertyScopes);
1053
-
1054
-		$result = $this->invokePrivate($this->accountManager, 'buildDefaultUserRecord', [$user]);
1055
-		$resultProperties = array_column($result, 'name');
1056
-
1057
-		$this->assertEmpty(array_diff($resultProperties, IAccountManager::ALLOWED_PROPERTIES), 'Building default user record returned non-allowed properties');
1058
-		foreach ($expectedResultScopes as $expectedResultScopeKey => $expectedResultScopeValue) {
1059
-			$resultScope = $result[array_search($expectedResultScopeKey, $resultProperties)]['scope'];
1060
-			$this->assertEquals($expectedResultScopeValue, $resultScope, "The result scope doesn't follow the value set into the config or defaults correctly.");
1061
-		}
1062
-	}
326
+                    ],
327
+                    [
328
+                        'name' => IAccountManager::PROPERTY_PHONE,
329
+                        'value' => '+71601212123',
330
+                        'scope' => IAccountManager::SCOPE_LOCAL
331
+                    ],
332
+                    [
333
+                        'name' => IAccountManager::PROPERTY_ADDRESS,
334
+                        'value' => 'Pinapple Street 22',
335
+                        'scope' => IAccountManager::SCOPE_LOCAL
336
+                    ],
337
+                    [
338
+                        'name' => IAccountManager::PROPERTY_WEBSITE,
339
+                        'value' => 'https://emca.com',
340
+                        'scope' => IAccountManager::SCOPE_FEDERATED
341
+                    ],
342
+                    [
343
+                        'name' => IAccountManager::PROPERTY_ORGANISATION,
344
+                        'value' => 'Organisation A',
345
+                        'scope' => IAccountManager::SCOPE_LOCAL
346
+                    ],
347
+                    [
348
+                        'name' => IAccountManager::PROPERTY_ROLE,
349
+                        'value' => 'Animal',
350
+                        'scope' => IAccountManager::SCOPE_LOCAL
351
+                    ],
352
+                    [
353
+                        'name' => IAccountManager::PROPERTY_HEADLINE,
354
+                        'value' => 'My headline',
355
+                        'scope' => IAccountManager::SCOPE_LOCAL
356
+                    ],
357
+                    [
358
+                        'name' => IAccountManager::PROPERTY_BIOGRAPHY,
359
+                        'value' => 'Short biography',
360
+                        'scope' => IAccountManager::SCOPE_LOCAL
361
+                    ],
362
+                    [
363
+                        'name' => IAccountManager::COLLECTION_EMAIL,
364
+                        'value' => '[email protected]',
365
+                        'scope' => IAccountManager::SCOPE_LOCAL
366
+                    ],
367
+                    [
368
+                        'name' => IAccountManager::COLLECTION_EMAIL,
369
+                        'value' => '[email protected]',
370
+                        'scope' => IAccountManager::SCOPE_LOCAL
371
+                    ],
372
+                ],
373
+            ],
374
+            [
375
+                'user' => $this->makeUser('[email protected]', 'Goodpal, Kim', '[email protected]'),
376
+                'data' => [
377
+                    [
378
+                        'name' => IAccountManager::PROPERTY_DISPLAYNAME,
379
+                        'value' => 'Goodpal, Kim',
380
+                        'scope' => IAccountManager::SCOPE_PUBLISHED
381
+                    ],
382
+                    [
383
+                        'name' => IAccountManager::PROPERTY_EMAIL,
384
+                        'value' => '[email protected]',
385
+                        'scope' => IAccountManager::SCOPE_PUBLISHED
386
+                    ],
387
+                    [
388
+                        'name' => IAccountManager::PROPERTY_TWITTER,
389
+                        'value' => '',
390
+                        'scope' => IAccountManager::SCOPE_LOCAL
391
+                    ],
392
+                    [
393
+                        'name' => IAccountManager::PROPERTY_FEDIVERSE,
394
+                        'value' => '',
395
+                        'scope' => IAccountManager::SCOPE_LOCAL
396
+                    ],
397
+                    [
398
+                        'name' => IAccountManager::PROPERTY_PHONE,
399
+                        'value' => '+71602121231',
400
+                        'scope' => IAccountManager::SCOPE_FEDERATED
401
+                    ],
402
+                    [
403
+                        'name' => IAccountManager::PROPERTY_ADDRESS,
404
+                        'value' => 'Octopus Ave 17',
405
+                        'scope' => IAccountManager::SCOPE_FEDERATED
406
+                    ],
407
+                    [
408
+                        'name' => IAccountManager::PROPERTY_WEBSITE,
409
+                        'value' => 'https://elpmaxe.org',
410
+                        'scope' => IAccountManager::SCOPE_PUBLISHED
411
+                    ],
412
+                    [
413
+                        'name' => IAccountManager::PROPERTY_ORGANISATION,
414
+                        'value' => 'Organisation B',
415
+                        'scope' => IAccountManager::SCOPE_FEDERATED
416
+                    ],
417
+                    [
418
+                        'name' => IAccountManager::PROPERTY_ROLE,
419
+                        'value' => 'Organism',
420
+                        'scope' => IAccountManager::SCOPE_FEDERATED
421
+                    ],
422
+                    [
423
+                        'name' => IAccountManager::PROPERTY_HEADLINE,
424
+                        'value' => 'Best headline',
425
+                        'scope' => IAccountManager::SCOPE_FEDERATED
426
+                    ],
427
+                    [
428
+                        'name' => IAccountManager::PROPERTY_BIOGRAPHY,
429
+                        'value' => 'Autobiography',
430
+                        'scope' => IAccountManager::SCOPE_FEDERATED
431
+                    ],
432
+                ],
433
+            ],
434
+        ];
435
+        $this->config->expects($this->exactly(count($users)))->method('getSystemValue')->with('account_manager.default_property_scope', [])->willReturn([]);
436
+        foreach ($users as $userInfo) {
437
+            $this->invokePrivate($this->accountManager, 'updateUser', [$userInfo['user'], $userInfo['data'], null, false]);
438
+        }
439
+    }
440
+
441
+    /**
442
+     * get a instance of the accountManager
443
+     *
444
+     * @return MockObject | AccountManager
445
+     */
446
+    public function getInstance(?array $mockedMethods = null) {
447
+        return $this->getMockBuilder(AccountManager::class)
448
+            ->setConstructorArgs([
449
+                $this->connection,
450
+                $this->config,
451
+                $this->eventDispatcher,
452
+                $this->jobList,
453
+                $this->logger,
454
+                $this->verificationToken,
455
+                $this->mailer,
456
+                $this->defaults,
457
+                $this->l10nFactory,
458
+                $this->urlGenerator,
459
+                $this->crypto,
460
+                $this->phoneNumberUtil,
461
+                $this->clientService,
462
+            ])
463
+            ->onlyMethods($mockedMethods)
464
+            ->getMock();
465
+    }
466
+
467
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTrueFalse')]
468
+    public function testUpdateUser(array $newData, array $oldData, bool $insertNew, bool $updateExisting): void {
469
+        $accountManager = $this->getInstance(['getUser', 'insertNewUser', 'updateExistingUser']);
470
+        /** @var IUser $user */
471
+        $user = $this->createMock(IUser::class);
472
+
473
+        if ($updateExisting) {
474
+            $accountManager->expects($this->once())->method('updateExistingUser')
475
+                ->with($user, $newData);
476
+            $accountManager->expects($this->never())->method('insertNewUser');
477
+        }
478
+        if ($insertNew) {
479
+            $accountManager->expects($this->once())->method('insertNewUser')
480
+                ->with($user, $newData);
481
+            $accountManager->expects($this->never())->method('updateExistingUser');
482
+        }
483
+
484
+        if (!$insertNew && !$updateExisting) {
485
+            $accountManager->expects($this->never())->method('updateExistingUser');
486
+            $accountManager->expects($this->never())->method('insertNewUser');
487
+            $this->eventDispatcher->expects($this->never())->method('dispatchTyped');
488
+        } else {
489
+            $this->eventDispatcher->expects($this->once())->method('dispatchTyped')
490
+                ->willReturnCallback(
491
+                    function ($event) use ($user, $newData): void {
492
+                        $this->assertInstanceOf(UserUpdatedEvent::class, $event);
493
+                        $this->assertSame($user, $event->getUser());
494
+                        $this->assertSame($newData, $event->getData());
495
+                    }
496
+                );
497
+        }
498
+
499
+        $this->invokePrivate($accountManager, 'updateUser', [$user, $newData, $oldData]);
500
+    }
501
+
502
+    public static function dataTrueFalse(): array {
503
+        return [
504
+            #$newData | $oldData | $insertNew | $updateExisting
505
+            [['myProperty' => ['value' => 'newData']], ['myProperty' => ['value' => 'oldData']], false, true],
506
+            [['myProperty' => ['value' => 'oldData']], ['myProperty' => ['value' => 'oldData']], false, false]
507
+        ];
508
+    }
509
+
510
+    public function testAddMissingDefaults(): void {
511
+        $user = $this->createMock(IUser::class);
512
+
513
+        $this->config
514
+            ->expects($this->once())
515
+            ->method('getAppValue')
516
+            ->with('settings', 'profile_enabled_by_default', '1')
517
+            ->willReturn('1');
518
+
519
+        $input = [
520
+            [
521
+                'name' => IAccountManager::PROPERTY_DISPLAYNAME,
522
+                'value' => 'bob',
523
+                'verified' => IAccountManager::NOT_VERIFIED,
524
+            ],
525
+            [
526
+                'name' => IAccountManager::PROPERTY_EMAIL,
527
+                'value' => '[email protected]',
528
+            ],
529
+        ];
530
+
531
+        $expected = [
532
+            [
533
+                'name' => IAccountManager::PROPERTY_DISPLAYNAME,
534
+                'value' => 'bob',
535
+                'scope' => IAccountManager::SCOPE_FEDERATED,
536
+                'verified' => IAccountManager::NOT_VERIFIED,
537
+            ],
538
+
539
+            [
540
+                'name' => IAccountManager::PROPERTY_EMAIL,
541
+                'value' => '[email protected]',
542
+                'scope' => IAccountManager::SCOPE_FEDERATED,
543
+                'verified' => IAccountManager::NOT_VERIFIED,
544
+            ],
545
+
546
+            [
547
+                'name' => IAccountManager::PROPERTY_ADDRESS,
548
+                'value' => '',
549
+                'scope' => IAccountManager::SCOPE_LOCAL,
550
+                'verified' => IAccountManager::NOT_VERIFIED,
551
+            ],
552
+
553
+            [
554
+                'name' => IAccountManager::PROPERTY_WEBSITE,
555
+                'value' => '',
556
+                'scope' => IAccountManager::SCOPE_LOCAL,
557
+                'verified' => IAccountManager::NOT_VERIFIED,
558
+            ],
559
+
560
+            [
561
+                'name' => IAccountManager::PROPERTY_AVATAR,
562
+                'scope' => IAccountManager::SCOPE_FEDERATED
563
+            ],
564
+
565
+            [
566
+                'name' => IAccountManager::PROPERTY_PHONE,
567
+                'value' => '',
568
+                'scope' => IAccountManager::SCOPE_LOCAL,
569
+                'verified' => IAccountManager::NOT_VERIFIED,
570
+            ],
571
+
572
+            [
573
+                'name' => IAccountManager::PROPERTY_TWITTER,
574
+                'value' => '',
575
+                'scope' => IAccountManager::SCOPE_LOCAL,
576
+                'verified' => IAccountManager::NOT_VERIFIED,
577
+            ],
578
+
579
+            [
580
+                'name' => IAccountManager::PROPERTY_BLUESKY,
581
+                'value' => '',
582
+                'scope' => IAccountManager::SCOPE_LOCAL,
583
+                'verified' => IAccountManager::NOT_VERIFIED,
584
+            ],
585
+
586
+            [
587
+                'name' => IAccountManager::PROPERTY_FEDIVERSE,
588
+                'value' => '',
589
+                'scope' => IAccountManager::SCOPE_LOCAL,
590
+                'verified' => IAccountManager::NOT_VERIFIED,
591
+            ],
592
+
593
+            [
594
+                'name' => IAccountManager::PROPERTY_ORGANISATION,
595
+                'value' => '',
596
+                'scope' => IAccountManager::SCOPE_LOCAL,
597
+            ],
598
+
599
+            [
600
+                'name' => IAccountManager::PROPERTY_ROLE,
601
+                'value' => '',
602
+                'scope' => IAccountManager::SCOPE_LOCAL,
603
+            ],
604
+
605
+            [
606
+                'name' => IAccountManager::PROPERTY_HEADLINE,
607
+                'value' => '',
608
+                'scope' => IAccountManager::SCOPE_LOCAL,
609
+            ],
610
+
611
+            [
612
+                'name' => IAccountManager::PROPERTY_BIOGRAPHY,
613
+                'value' => '',
614
+                'scope' => IAccountManager::SCOPE_LOCAL,
615
+            ],
616
+
617
+            [
618
+                'name' => IAccountManager::PROPERTY_BIRTHDATE,
619
+                'value' => '',
620
+                'scope' => IAccountManager::SCOPE_LOCAL,
621
+            ],
622
+
623
+            [
624
+                'name' => IAccountManager::PROPERTY_PROFILE_ENABLED,
625
+                'value' => '1',
626
+            ],
627
+
628
+            [
629
+                'name' => IAccountManager::PROPERTY_PRONOUNS,
630
+                'value' => '',
631
+                'scope' => IAccountManager::SCOPE_FEDERATED,
632
+            ],
633
+        ];
634
+        $this->config->expects($this->once())->method('getSystemValue')->with('account_manager.default_property_scope', [])->willReturn([]);
635
+
636
+        $defaultUserRecord = $this->invokePrivate($this->accountManager, 'buildDefaultUserRecord', [$user]);
637
+        $result = $this->invokePrivate($this->accountManager, 'addMissingDefaultValues', [$input, $defaultUserRecord]);
638
+
639
+        $this->assertSame($expected, $result);
640
+    }
641
+
642
+    public function testGetAccount(): void {
643
+        $accountManager = $this->getInstance(['getUser']);
644
+        /** @var IUser $user */
645
+        $user = $this->createMock(IUser::class);
646
+
647
+        $data = [
648
+            [
649
+                'value' => '@twitterhandle',
650
+                'scope' => IAccountManager::SCOPE_LOCAL,
651
+                'verified' => IAccountManager::NOT_VERIFIED,
652
+                'name' => IAccountManager::PROPERTY_TWITTER,
653
+            ],
654
+            [
655
+                'value' => '@[email protected]',
656
+                'scope' => IAccountManager::SCOPE_LOCAL,
657
+                'verified' => IAccountManager::NOT_VERIFIED,
658
+                'name' => IAccountManager::PROPERTY_FEDIVERSE,
659
+            ],
660
+            [
661
+                'value' => '[email protected]',
662
+                'scope' => IAccountManager::SCOPE_PUBLISHED,
663
+                'verified' => IAccountManager::VERIFICATION_IN_PROGRESS,
664
+                'name' => IAccountManager::PROPERTY_EMAIL,
665
+            ],
666
+            [
667
+                'value' => 'https://example.com',
668
+                'scope' => IAccountManager::SCOPE_FEDERATED,
669
+                'verified' => IAccountManager::VERIFIED,
670
+                'name' => IAccountManager::PROPERTY_WEBSITE,
671
+            ],
672
+        ];
673
+        $expected = new Account($user);
674
+        $expected->setProperty(IAccountManager::PROPERTY_TWITTER, '@twitterhandle', IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
675
+        $expected->setProperty(IAccountManager::PROPERTY_FEDIVERSE, '@[email protected]', IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
676
+        $expected->setProperty(IAccountManager::PROPERTY_EMAIL, '[email protected]', IAccountManager::SCOPE_PUBLISHED, IAccountManager::VERIFICATION_IN_PROGRESS);
677
+        $expected->setProperty(IAccountManager::PROPERTY_WEBSITE, 'https://example.com', IAccountManager::SCOPE_FEDERATED, IAccountManager::VERIFIED);
678
+
679
+        $accountManager->expects($this->once())
680
+            ->method('getUser')
681
+            ->willReturn($data);
682
+        $this->assertEquals($expected, $accountManager->getAccount($user));
683
+    }
684
+
685
+    public static function dataParsePhoneNumber(): array {
686
+        return [
687
+            ['0711 / 25 24 28-90', 'DE', '+4971125242890'],
688
+            ['0711 / 25 24 28-90', '', null],
689
+            ['+49 711 / 25 24 28-90', '', '+4971125242890'],
690
+        ];
691
+    }
692
+
693
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataParsePhoneNumber')]
694
+    public function testSanitizePhoneNumberOnUpdateAccount(string $phoneInput, string $defaultRegion, ?string $phoneNumber): void {
695
+        $this->config->method('getSystemValueString')
696
+            ->willReturn($defaultRegion);
697
+
698
+        $user = $this->createMock(IUser::class);
699
+        $account = new Account($user);
700
+        $account->setProperty(IAccountManager::PROPERTY_PHONE, $phoneInput, IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
701
+        $manager = $this->getInstance(['getUser', 'updateUser']);
702
+        $manager->method('getUser')
703
+            ->with($user, false)
704
+            ->willReturn([]);
705
+        $manager->expects($phoneNumber === null ? self::never() : self::once())
706
+            ->method('updateUser');
707
+
708
+        if ($phoneNumber === null) {
709
+            $this->expectException(\InvalidArgumentException::class);
710
+        }
711
+
712
+        $manager->updateAccount($account);
713
+
714
+        if ($phoneNumber !== null) {
715
+            self::assertEquals($phoneNumber, $account->getProperty(IAccountManager::PROPERTY_PHONE)->getValue());
716
+        }
717
+    }
718
+
719
+    public static function dataSanitizeOnUpdate(): array {
720
+        return [
721
+            [IAccountManager::PROPERTY_WEBSITE, 'https://nextcloud.com', 'https://nextcloud.com'],
722
+            [IAccountManager::PROPERTY_WEBSITE, 'http://nextcloud.com', 'http://nextcloud.com'],
723
+            [IAccountManager::PROPERTY_WEBSITE, 'ftp://nextcloud.com', null],
724
+            [IAccountManager::PROPERTY_WEBSITE, '//nextcloud.com/', null],
725
+            [IAccountManager::PROPERTY_WEBSITE, 'https:///?query', null],
726
+
727
+            [IAccountManager::PROPERTY_TWITTER, '@nextcloud', 'nextcloud'],
728
+            [IAccountManager::PROPERTY_TWITTER, '_nextcloud', '_nextcloud'],
729
+            [IAccountManager::PROPERTY_TWITTER, 'FooB4r', 'FooB4r'],
730
+            [IAccountManager::PROPERTY_TWITTER, 'X', null],
731
+            [IAccountManager::PROPERTY_TWITTER, 'next.cloud', null],
732
+            [IAccountManager::PROPERTY_TWITTER, 'ab/cd.zip', null],
733
+            [IAccountManager::PROPERTY_TWITTER, 'tooLongForTwitterAndX', null],
734
+
735
+            [IAccountManager::PROPERTY_FEDIVERSE, '[email protected]', '[email protected]'],
736
+            [IAccountManager::PROPERTY_FEDIVERSE, '@[email protected]', '[email protected]'],
737
+            [IAccountManager::PROPERTY_FEDIVERSE, '[email protected]', '[email protected]'],
738
+            [IAccountManager::PROPERTY_FEDIVERSE, 'invalid/[email protected]', null],
739
+            [IAccountManager::PROPERTY_FEDIVERSE, '[email protected]/malware.exe', null],
740
+            [IAccountManager::PROPERTY_FEDIVERSE, '@is-it-a-host-or-name', null],
741
+            [IAccountManager::PROPERTY_FEDIVERSE, 'only-a-name', null],
742
+        ];
743
+    }
744
+
745
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataSanitizeOnUpdate')]
746
+    public function testSanitizingOnUpdateAccount(string $property, string $input, ?string $output): void {
747
+
748
+        if ($property === IAccountManager::PROPERTY_FEDIVERSE) {
749
+            // We do not test the server response here we do this in the `testSanitizingFediverseServer`
750
+            $this->config
751
+                ->method('getSystemValueBool')
752
+                ->with('has_internet_connection', true)
753
+                ->willReturn(false);
754
+        }
755
+
756
+        $user = $this->createMock(IUser::class);
757
+
758
+        $account = new Account($user);
759
+        $account->setProperty($property, $input, IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
760
+
761
+        $manager = $this->getInstance(['getUser', 'updateUser']);
762
+        $manager->method('getUser')
763
+            ->with($user, false)
764
+            ->willReturn([]);
765
+        $manager->expects($output === null ? self::never() : self::once())
766
+            ->method('updateUser');
767
+
768
+        if ($output === null) {
769
+            $this->expectException(\InvalidArgumentException::class);
770
+            $this->expectExceptionMessage($property);
771
+        }
772
+
773
+        $manager->updateAccount($account);
774
+
775
+        if ($output !== null) {
776
+            self::assertEquals($output, $account->getProperty($property)->getValue());
777
+        }
778
+    }
779
+
780
+    public static function dataSanitizeFediverseServer(): array {
781
+        return [
782
+            'no internet' => [
783
+                '@[email protected]',
784
+                '[email protected]',
785
+                false,
786
+                null,
787
+            ],
788
+            'no internet - no at' => [
789
+                '[email protected]',
790
+                '[email protected]',
791
+                false,
792
+                null,
793
+            ],
794
+            'valid response' => [
795
+                '@[email protected]',
796
+                '[email protected]',
797
+                true,
798
+                json_encode([
799
+                    'subject' => 'acct:[email protected]',
800
+                    'links' => [
801
+                        [
802
+                            'rel' => 'self',
803
+                            'type' => 'application/activity+json',
804
+                            'href' => 'https://example.com/users/foo',
805
+                        ],
806
+                    ],
807
+                ]),
808
+            ],
809
+            'valid response - no at' => [
810
+                '[email protected]',
811
+                '[email protected]',
812
+                true,
813
+                json_encode([
814
+                    'subject' => 'acct:[email protected]',
815
+                    'links' => [
816
+                        [
817
+                            'rel' => 'self',
818
+                            'type' => 'application/activity+json',
819
+                            'href' => 'https://example.com/users/foo',
820
+                        ],
821
+                    ],
822
+                ]),
823
+            ],
824
+            // failures
825
+            'invalid response' => [
826
+                '@[email protected]',
827
+                null,
828
+                true,
829
+                json_encode([
830
+                    'subject' => 'acct:[email protected]',
831
+                    'links' => [],
832
+                ]),
833
+            ],
834
+            'no response' => [
835
+                '@[email protected]',
836
+                null,
837
+                true,
838
+                null,
839
+            ],
840
+            'wrong user' => [
841
+                '@[email protected]',
842
+                null,
843
+                true,
844
+                json_encode([
845
+                    'links' => [],
846
+                ]),
847
+            ],
848
+        ];
849
+    }
850
+
851
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataSanitizeFediverseServer')]
852
+    public function testSanitizingFediverseServer(string $input, ?string $output, bool $hasInternet, ?string $serverResponse): void {
853
+        $this->config->expects(self::once())
854
+            ->method('getSystemValueBool')
855
+            ->with('has_internet_connection', true)
856
+            ->willReturn($hasInternet);
857
+
858
+        if ($hasInternet) {
859
+            $client = $this->createMock(IClient::class);
860
+            if ($serverResponse !== null) {
861
+                $response = $this->createMock(IResponse::class);
862
+                $response->method('getBody')
863
+                    ->willReturn($serverResponse);
864
+                $client->expects(self::once())
865
+                    ->method('get')
866
+                    ->with('https://example.com/.well-known/webfinger?resource=acct:[email protected]')
867
+                    ->willReturn($response);
868
+            } else {
869
+                $client->expects(self::once())
870
+                    ->method('get')
871
+                    ->with('https://example.com/.well-known/webfinger?resource=acct:[email protected]')
872
+                    ->willThrowException(new \Exception('404'));
873
+            }
874
+
875
+            $this->clientService
876
+                ->expects(self::once())
877
+                ->method('newClient')
878
+                ->willReturn($client);
879
+        } else {
880
+            $this->clientService
881
+                ->expects(self::never())
882
+                ->method('newClient');
883
+        }
884
+
885
+        $user = $this->createMock(IUser::class);
886
+        $account = new Account($user);
887
+        $account->setProperty(IAccountManager::PROPERTY_FEDIVERSE, $input, IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
888
+
889
+        $manager = $this->getInstance(['getUser', 'updateUser']);
890
+        $manager->method('getUser')
891
+            ->with($user, false)
892
+            ->willReturn([]);
893
+        $manager->expects($output === null ? self::never() : self::once())
894
+            ->method('updateUser');
895
+
896
+        if ($output === null) {
897
+            $this->expectException(\InvalidArgumentException::class);
898
+            $this->expectExceptionMessage(IAccountManager::PROPERTY_FEDIVERSE);
899
+        }
900
+
901
+        $manager->updateAccount($account);
902
+
903
+        if ($output !== null) {
904
+            self::assertEquals($output, $account->getProperty(IAccountManager::PROPERTY_FEDIVERSE)->getValue());
905
+        }
906
+    }
907
+
908
+    #[\PHPUnit\Framework\Attributes\DataProvider('searchDataProvider')]
909
+    public function testSearchUsers(string $property, array $values, array $expected): void {
910
+        $this->populateOrUpdate();
911
+
912
+        $matchedUsers = $this->accountManager->searchUsers($property, $values);
913
+        foreach ($expected as $expectedEntry) {
914
+            $this->assertContains($expectedEntry, $matchedUsers);
915
+        }
916
+        if (empty($expected)) {
917
+            $this->assertEmpty($matchedUsers);
918
+        }
919
+    }
920
+
921
+    public static function searchDataProvider(): array {
922
+        return [
923
+            [ #0 Search for an existing name
924
+                IAccountManager::PROPERTY_DISPLAYNAME,
925
+                ['Jane Doe'],
926
+                ['Jane Doe' => 'j.doe']
927
+            ],
928
+            [ #1 Search for part of a name (no result)
929
+                IAccountManager::PROPERTY_DISPLAYNAME,
930
+                ['Jane'],
931
+                []
932
+            ],
933
+            [ #2 Search for part of a name (no result, test wildcard)
934
+                IAccountManager::PROPERTY_DISPLAYNAME,
935
+                ['Jane%'],
936
+                []
937
+            ],
938
+            [ #3 Search for phone
939
+                IAccountManager::PROPERTY_PHONE,
940
+                ['+491603121212'],
941
+                ['+491603121212' => 'b32c5a5b-1084-4380-8856-e5223b16de9f'],
942
+            ],
943
+            [ #4 Search for twitter handles
944
+                IAccountManager::PROPERTY_TWITTER,
945
+                ['@sometwitter', '@a_alice', '@unseen'],
946
+                ['@sometwitter' => 'j.doe', '@a_alice' => 'a.allison'],
947
+            ],
948
+            [ #5 Search for email
949
+                IAccountManager::PROPERTY_EMAIL,
950
+                ['[email protected]'],
951
+                ['[email protected]' => '31b5316a-9b57-4b17-970a-315a4cbe73eb'],
952
+            ],
953
+            [ #6 Search for email by additional email
954
+                IAccountManager::PROPERTY_EMAIL,
955
+                ['[email protected]'],
956
+                ['[email protected]' => '31b5316a-9b57-4b17-970a-315a4cbe73eb'],
957
+            ],
958
+            [ #7 Search for additional email
959
+                IAccountManager::COLLECTION_EMAIL,
960
+                ['[email protected]', '[email protected]'],
961
+                ['[email protected]' => '31b5316a-9b57-4b17-970a-315a4cbe73eb'],
962
+            ],
963
+            [ #8 Search for email by additional email (two valid search values, but the same user)
964
+                IAccountManager::PROPERTY_EMAIL,
965
+                ['[email protected]', '[email protected]'],
966
+                [
967
+                    '[email protected]' => '31b5316a-9b57-4b17-970a-315a4cbe73eb',
968
+                ],
969
+            ],
970
+        ];
971
+    }
972
+
973
+    public static function dataCheckEmailVerification(): array {
974
+        return [
975
+            [['steve', 'Steve Smith', '[email protected]'], null],
976
+            [['emma', 'Emma Morales', '[email protected]'], '[email protected]'],
977
+            [['[email protected]', 'Sarah Foster', '[email protected]'], null],
978
+            [['[email protected]', 'Cole Harrison', '[email protected]'], '[email protected]'],
979
+            [['8d29e358-cf69-4849-bbf9-28076c0b908b', 'Alice McPherson', '[email protected]'], '[email protected]'],
980
+            [['11da2744-3f4d-4c17-8c13-4c057a379237', 'James Loranger', '[email protected]'], ''],
981
+        ];
982
+    }
983
+
984
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataCheckEmailVerification')]
985
+    public function testCheckEmailVerification(array $userData, ?string $newEmail): void {
986
+        $user = $this->makeUser(...$userData);
987
+        // Once because of getAccount, once because of getUser
988
+        $this->config->expects($this->exactly(2))->method('getSystemValue')->with('account_manager.default_property_scope', [])->willReturn([]);
989
+        $account = $this->accountManager->getAccount($user);
990
+        $emailUpdated = false;
991
+
992
+        if (!empty($newEmail)) {
993
+            $account->getProperty(IAccountManager::PROPERTY_EMAIL)->setValue($newEmail);
994
+            $emailUpdated = true;
995
+        }
996
+
997
+        if ($emailUpdated) {
998
+            $this->jobList->expects($this->once())
999
+                ->method('add')
1000
+                ->with(VerifyUserData::class);
1001
+        } else {
1002
+            $this->jobList->expects($this->never())
1003
+                ->method('add')
1004
+                ->with(VerifyUserData::class);
1005
+        }
1006
+
1007
+        /** @var array $oldData */
1008
+        $oldData = $this->invokePrivate($this->accountManager, 'getUser', [$user, false]);
1009
+        $this->invokePrivate($this->accountManager, 'checkEmailVerification', [$account, $oldData]);
1010
+    }
1011
+
1012
+    public static function dataSetDefaultPropertyScopes(): array {
1013
+        return [
1014
+            [
1015
+                [],
1016
+                [
1017
+                    IAccountManager::PROPERTY_DISPLAYNAME => IAccountManager::SCOPE_FEDERATED,
1018
+                    IAccountManager::PROPERTY_ADDRESS => IAccountManager::SCOPE_LOCAL,
1019
+                    IAccountManager::PROPERTY_EMAIL => IAccountManager::SCOPE_FEDERATED,
1020
+                    IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_LOCAL,
1021
+                ]
1022
+            ],
1023
+            [
1024
+                [
1025
+                    IAccountManager::PROPERTY_DISPLAYNAME => IAccountManager::SCOPE_FEDERATED,
1026
+                    IAccountManager::PROPERTY_EMAIL => IAccountManager::SCOPE_LOCAL,
1027
+                    IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_PRIVATE,
1028
+                ], [
1029
+                    IAccountManager::PROPERTY_DISPLAYNAME => IAccountManager::SCOPE_FEDERATED,
1030
+                    IAccountManager::PROPERTY_EMAIL => IAccountManager::SCOPE_LOCAL,
1031
+                    IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_PRIVATE,
1032
+                ]
1033
+            ],
1034
+            [
1035
+                [
1036
+                    IAccountManager::PROPERTY_ADDRESS => 'invalid scope',
1037
+                    'invalid property' => IAccountManager::SCOPE_LOCAL,
1038
+                    IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_PRIVATE,
1039
+                ],
1040
+                [
1041
+                    IAccountManager::PROPERTY_ADDRESS => IAccountManager::SCOPE_LOCAL,
1042
+                    IAccountManager::PROPERTY_EMAIL => IAccountManager::SCOPE_FEDERATED,
1043
+                    IAccountManager::PROPERTY_ROLE => IAccountManager::SCOPE_PRIVATE,
1044
+                ]
1045
+            ],
1046
+        ];
1047
+    }
1048
+
1049
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataSetDefaultPropertyScopes')]
1050
+    public function testSetDefaultPropertyScopes(array $propertyScopes, array $expectedResultScopes): void {
1051
+        $user = $this->makeUser('steve', 'Steve Smith', '[email protected]');
1052
+        $this->config->expects($this->once())->method('getSystemValue')->with('account_manager.default_property_scope', [])->willReturn($propertyScopes);
1053
+
1054
+        $result = $this->invokePrivate($this->accountManager, 'buildDefaultUserRecord', [$user]);
1055
+        $resultProperties = array_column($result, 'name');
1056
+
1057
+        $this->assertEmpty(array_diff($resultProperties, IAccountManager::ALLOWED_PROPERTIES), 'Building default user record returned non-allowed properties');
1058
+        foreach ($expectedResultScopes as $expectedResultScopeKey => $expectedResultScopeValue) {
1059
+            $resultScope = $result[array_search($expectedResultScopeKey, $resultProperties)]['scope'];
1060
+            $this->assertEquals($expectedResultScopeValue, $resultScope, "The result scope doesn't follow the value set into the config or defaults correctly.");
1061
+        }
1062
+    }
1063 1063
 }
Please login to merge, or discard this patch.
tests/lib/Accounts/HooksTest.php 1 patch
Indentation   +108 added lines, -108 removed lines patch added patch discarded remove patch
@@ -27,112 +27,112 @@
 block discarded – undo
27 27
 #[\PHPUnit\Framework\Attributes\Group('DB')]
28 28
 class HooksTest extends TestCase {
29 29
 
30
-	private LoggerInterface&MockObject $logger;
31
-	private AccountManager&MockObject $accountManager;
32
-	private Hooks $hooks;
33
-
34
-	protected function setUp(): void {
35
-		parent::setUp();
36
-
37
-		$this->logger = $this->createMock(LoggerInterface::class);
38
-		$this->accountManager = $this->getMockBuilder(AccountManager::class)
39
-			->disableOriginalConstructor()->getMock();
40
-
41
-		$this->hooks = new Hooks($this->logger, $this->accountManager);
42
-	}
43
-
44
-	/**
45
-	 *
46
-	 * @param $params
47
-	 * @param $data
48
-	 * @param $setEmail
49
-	 * @param $setDisplayName
50
-	 * @param $error
51
-	 */
52
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestChangeUserHook')]
53
-	public function testChangeUserHook($params, $data, $setEmail, $setDisplayName, $error): void {
54
-		if ($error) {
55
-			$this->accountManager->expects($this->never())->method('updateAccount');
56
-		} else {
57
-			$account = $this->createMock(IAccount::class);
58
-			$this->accountManager->expects($this->atLeastOnce())->method('getAccount')->willReturn($account);
59
-			if ($setEmail) {
60
-				$property = $this->createMock(IAccountProperty::class);
61
-				$property->expects($this->atLeastOnce())
62
-					->method('getValue')
63
-					->willReturn($data[IAccountManager::PROPERTY_EMAIL]['value']);
64
-				$property->expects($this->atLeastOnce())
65
-					->method('setValue')
66
-					->with($params['value']);
67
-
68
-				$account->expects($this->atLeastOnce())
69
-					->method('getProperty')
70
-					->with(IAccountManager::PROPERTY_EMAIL)
71
-					->willReturn($property);
72
-
73
-				$this->accountManager->expects($this->once())
74
-					->method('updateAccount')
75
-					->with($account);
76
-			} elseif ($setDisplayName) {
77
-				$property = $this->createMock(IAccountProperty::class);
78
-				$property->expects($this->atLeastOnce())
79
-					->method('getValue')
80
-					->willReturn($data[IAccountManager::PROPERTY_DISPLAYNAME]['value']);
81
-				$property->expects($this->atLeastOnce())
82
-					->method('setValue')
83
-					->with($params['value']);
84
-
85
-				$account->expects($this->atLeastOnce())
86
-					->method('getProperty')
87
-					->with(IAccountManager::PROPERTY_DISPLAYNAME)
88
-					->willReturn($property);
89
-
90
-				$this->accountManager->expects($this->once())
91
-					->method('updateAccount')
92
-					->with($account);
93
-			} else {
94
-				$this->accountManager->expects($this->never())->method('updateAccount');
95
-			}
96
-		}
97
-
98
-		$params['user'] = $this->createMock(IUser::class);
99
-		$this->hooks->changeUserHook($params['user'], $params['feature'], $params['value']);
100
-	}
101
-
102
-	public static function dataTestChangeUserHook(): array {
103
-		return [
104
-			[
105
-				['feature' => '', 'value' => ''],
106
-				[
107
-					IAccountManager::PROPERTY_EMAIL => ['value' => ''],
108
-					IAccountManager::PROPERTY_DISPLAYNAME => ['value' => '']
109
-				],
110
-				false, false, true
111
-			],
112
-			[
113
-				['feature' => 'foo', 'value' => 'bar'],
114
-				[
115
-					IAccountManager::PROPERTY_EMAIL => ['value' => '[email protected]'],
116
-					IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'oldDisplayName']
117
-				],
118
-				false, false, false
119
-			],
120
-			[
121
-				['feature' => 'eMailAddress', 'value' => '[email protected]'],
122
-				[
123
-					IAccountManager::PROPERTY_EMAIL => ['value' => '[email protected]'],
124
-					IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'oldDisplayName']
125
-				],
126
-				true, false, false
127
-			],
128
-			[
129
-				['feature' => 'displayName', 'value' => 'newDisplayName'],
130
-				[
131
-					IAccountManager::PROPERTY_EMAIL => ['value' => '[email protected]'],
132
-					IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'oldDisplayName']
133
-				],
134
-				false, true, false
135
-			],
136
-		];
137
-	}
30
+    private LoggerInterface&MockObject $logger;
31
+    private AccountManager&MockObject $accountManager;
32
+    private Hooks $hooks;
33
+
34
+    protected function setUp(): void {
35
+        parent::setUp();
36
+
37
+        $this->logger = $this->createMock(LoggerInterface::class);
38
+        $this->accountManager = $this->getMockBuilder(AccountManager::class)
39
+            ->disableOriginalConstructor()->getMock();
40
+
41
+        $this->hooks = new Hooks($this->logger, $this->accountManager);
42
+    }
43
+
44
+    /**
45
+     *
46
+     * @param $params
47
+     * @param $data
48
+     * @param $setEmail
49
+     * @param $setDisplayName
50
+     * @param $error
51
+     */
52
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestChangeUserHook')]
53
+    public function testChangeUserHook($params, $data, $setEmail, $setDisplayName, $error): void {
54
+        if ($error) {
55
+            $this->accountManager->expects($this->never())->method('updateAccount');
56
+        } else {
57
+            $account = $this->createMock(IAccount::class);
58
+            $this->accountManager->expects($this->atLeastOnce())->method('getAccount')->willReturn($account);
59
+            if ($setEmail) {
60
+                $property = $this->createMock(IAccountProperty::class);
61
+                $property->expects($this->atLeastOnce())
62
+                    ->method('getValue')
63
+                    ->willReturn($data[IAccountManager::PROPERTY_EMAIL]['value']);
64
+                $property->expects($this->atLeastOnce())
65
+                    ->method('setValue')
66
+                    ->with($params['value']);
67
+
68
+                $account->expects($this->atLeastOnce())
69
+                    ->method('getProperty')
70
+                    ->with(IAccountManager::PROPERTY_EMAIL)
71
+                    ->willReturn($property);
72
+
73
+                $this->accountManager->expects($this->once())
74
+                    ->method('updateAccount')
75
+                    ->with($account);
76
+            } elseif ($setDisplayName) {
77
+                $property = $this->createMock(IAccountProperty::class);
78
+                $property->expects($this->atLeastOnce())
79
+                    ->method('getValue')
80
+                    ->willReturn($data[IAccountManager::PROPERTY_DISPLAYNAME]['value']);
81
+                $property->expects($this->atLeastOnce())
82
+                    ->method('setValue')
83
+                    ->with($params['value']);
84
+
85
+                $account->expects($this->atLeastOnce())
86
+                    ->method('getProperty')
87
+                    ->with(IAccountManager::PROPERTY_DISPLAYNAME)
88
+                    ->willReturn($property);
89
+
90
+                $this->accountManager->expects($this->once())
91
+                    ->method('updateAccount')
92
+                    ->with($account);
93
+            } else {
94
+                $this->accountManager->expects($this->never())->method('updateAccount');
95
+            }
96
+        }
97
+
98
+        $params['user'] = $this->createMock(IUser::class);
99
+        $this->hooks->changeUserHook($params['user'], $params['feature'], $params['value']);
100
+    }
101
+
102
+    public static function dataTestChangeUserHook(): array {
103
+        return [
104
+            [
105
+                ['feature' => '', 'value' => ''],
106
+                [
107
+                    IAccountManager::PROPERTY_EMAIL => ['value' => ''],
108
+                    IAccountManager::PROPERTY_DISPLAYNAME => ['value' => '']
109
+                ],
110
+                false, false, true
111
+            ],
112
+            [
113
+                ['feature' => 'foo', 'value' => 'bar'],
114
+                [
115
+                    IAccountManager::PROPERTY_EMAIL => ['value' => '[email protected]'],
116
+                    IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'oldDisplayName']
117
+                ],
118
+                false, false, false
119
+            ],
120
+            [
121
+                ['feature' => 'eMailAddress', 'value' => '[email protected]'],
122
+                [
123
+                    IAccountManager::PROPERTY_EMAIL => ['value' => '[email protected]'],
124
+                    IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'oldDisplayName']
125
+                ],
126
+                true, false, false
127
+            ],
128
+            [
129
+                ['feature' => 'displayName', 'value' => 'newDisplayName'],
130
+                [
131
+                    IAccountManager::PROPERTY_EMAIL => ['value' => '[email protected]'],
132
+                    IAccountManager::PROPERTY_DISPLAYNAME => ['value' => 'oldDisplayName']
133
+                ],
134
+                false, true, false
135
+            ],
136
+        ];
137
+    }
138 138
 }
Please login to merge, or discard this patch.
tests/lib/Memcache/FactoryTest.php 1 patch
Indentation   +105 added lines, -105 removed lines patch added patch discarded remove patch
@@ -16,126 +16,126 @@
 block discarded – undo
16 16
 use Psr\Log\LoggerInterface;
17 17
 
18 18
 class Test_Factory_Available_Cache1 extends NullCache {
19
-	public function __construct($prefix = '') {
20
-	}
19
+    public function __construct($prefix = '') {
20
+    }
21 21
 
22
-	public static function isAvailable(): bool {
23
-		return true;
24
-	}
22
+    public static function isAvailable(): bool {
23
+        return true;
24
+    }
25 25
 }
26 26
 
27 27
 class Test_Factory_Available_Cache2 extends NullCache {
28
-	public function __construct($prefix = '') {
29
-	}
28
+    public function __construct($prefix = '') {
29
+    }
30 30
 
31
-	public static function isAvailable(): bool {
32
-		return true;
33
-	}
31
+    public static function isAvailable(): bool {
32
+        return true;
33
+    }
34 34
 }
35 35
 
36 36
 class Test_Factory_Unavailable_Cache1 extends NullCache {
37
-	public function __construct($prefix = '') {
38
-	}
37
+    public function __construct($prefix = '') {
38
+    }
39 39
 
40
-	public static function isAvailable(): bool {
41
-		return false;
42
-	}
40
+    public static function isAvailable(): bool {
41
+        return false;
42
+    }
43 43
 }
44 44
 
45 45
 class Test_Factory_Unavailable_Cache2 extends NullCache {
46
-	public function __construct($prefix = '') {
47
-	}
46
+    public function __construct($prefix = '') {
47
+    }
48 48
 
49
-	public static function isAvailable(): bool {
50
-		return false;
51
-	}
49
+    public static function isAvailable(): bool {
50
+        return false;
51
+    }
52 52
 }
53 53
 
54 54
 #[\PHPUnit\Framework\Attributes\Group('Memcache')]
55 55
 class FactoryTest extends \Test\TestCase {
56
-	public const AVAILABLE1 = '\\Test\\Memcache\\Test_Factory_Available_Cache1';
57
-	public const AVAILABLE2 = '\\Test\\Memcache\\Test_Factory_Available_Cache2';
58
-	public const UNAVAILABLE1 = '\\Test\\Memcache\\Test_Factory_Unavailable_Cache1';
59
-	public const UNAVAILABLE2 = '\\Test\\Memcache\\Test_Factory_Unavailable_Cache2';
60
-
61
-	public static function cacheAvailabilityProvider(): array {
62
-		return [
63
-			[
64
-				// local and distributed available
65
-				self::AVAILABLE1, self::AVAILABLE2, null,
66
-				self::AVAILABLE1, self::AVAILABLE2, Factory::NULL_CACHE
67
-			],
68
-			[
69
-				// local and distributed null
70
-				null, null, null,
71
-				Factory::NULL_CACHE, Factory::NULL_CACHE, Factory::NULL_CACHE
72
-			],
73
-			[
74
-				// local available, distributed null (most common scenario)
75
-				self::AVAILABLE1, null, null,
76
-				self::AVAILABLE1, self::AVAILABLE1, Factory::NULL_CACHE
77
-			],
78
-			[
79
-				// locking cache available
80
-				null, null, self::AVAILABLE1,
81
-				Factory::NULL_CACHE, Factory::NULL_CACHE, self::AVAILABLE1
82
-			],
83
-			[
84
-				// locking cache unavailable: no exception here in the factory
85
-				null, null, self::UNAVAILABLE1,
86
-				Factory::NULL_CACHE, Factory::NULL_CACHE, Factory::NULL_CACHE
87
-			]
88
-		];
89
-	}
90
-
91
-	public static function cacheUnavailableProvider(): array {
92
-		return [
93
-			[
94
-				// local available, distributed unavailable
95
-				self::AVAILABLE1, self::UNAVAILABLE1
96
-			],
97
-			[
98
-				// local unavailable, distributed available
99
-				self::UNAVAILABLE1, self::AVAILABLE1
100
-			],
101
-			[
102
-				// local and distributed unavailable
103
-				self::UNAVAILABLE1, self::UNAVAILABLE2
104
-			],
105
-		];
106
-	}
107
-
108
-	#[\PHPUnit\Framework\Attributes\DataProvider('cacheAvailabilityProvider')]
109
-	public function testCacheAvailability($localCache, $distributedCache, $lockingCache,
110
-		$expectedLocalCache, $expectedDistributedCache, $expectedLockingCache): void {
111
-		$logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
112
-		$profiler = $this->getMockBuilder(IProfiler::class)->getMock();
113
-		$serverVersion = $this->createMock(ServerVersion::class);
114
-		$factory = new Factory($logger, $profiler, $serverVersion, $localCache, $distributedCache, $lockingCache);
115
-		$this->assertTrue(is_a($factory->createLocal(), $expectedLocalCache));
116
-		$this->assertTrue(is_a($factory->createDistributed(), $expectedDistributedCache));
117
-		$this->assertTrue(is_a($factory->createLocking(), $expectedLockingCache));
118
-	}
119
-
120
-	#[\PHPUnit\Framework\Attributes\DataProvider('cacheUnavailableProvider')]
121
-	public function testCacheNotAvailableException($localCache, $distributedCache): void {
122
-		$this->expectException(HintException::class);
123
-
124
-		$logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
125
-		$profiler = $this->getMockBuilder(IProfiler::class)->getMock();
126
-		$serverVersion = $this->createMock(ServerVersion::class);
127
-		new Factory($logger, $profiler, $serverVersion, $localCache, $distributedCache);
128
-	}
129
-
130
-	public function testCreateInMemory(): void {
131
-		$logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
132
-		$profiler = $this->getMockBuilder(IProfiler::class)->getMock();
133
-		$serverVersion = $this->createMock(ServerVersion::class);
134
-		$factory = new Factory($logger, $profiler, $serverVersion, null, null, null);
135
-
136
-		$cache = $factory->createInMemory();
137
-		$cache->set('test', 48);
138
-
139
-		self::assertSame(48, $cache->get('test'));
140
-	}
56
+    public const AVAILABLE1 = '\\Test\\Memcache\\Test_Factory_Available_Cache1';
57
+    public const AVAILABLE2 = '\\Test\\Memcache\\Test_Factory_Available_Cache2';
58
+    public const UNAVAILABLE1 = '\\Test\\Memcache\\Test_Factory_Unavailable_Cache1';
59
+    public const UNAVAILABLE2 = '\\Test\\Memcache\\Test_Factory_Unavailable_Cache2';
60
+
61
+    public static function cacheAvailabilityProvider(): array {
62
+        return [
63
+            [
64
+                // local and distributed available
65
+                self::AVAILABLE1, self::AVAILABLE2, null,
66
+                self::AVAILABLE1, self::AVAILABLE2, Factory::NULL_CACHE
67
+            ],
68
+            [
69
+                // local and distributed null
70
+                null, null, null,
71
+                Factory::NULL_CACHE, Factory::NULL_CACHE, Factory::NULL_CACHE
72
+            ],
73
+            [
74
+                // local available, distributed null (most common scenario)
75
+                self::AVAILABLE1, null, null,
76
+                self::AVAILABLE1, self::AVAILABLE1, Factory::NULL_CACHE
77
+            ],
78
+            [
79
+                // locking cache available
80
+                null, null, self::AVAILABLE1,
81
+                Factory::NULL_CACHE, Factory::NULL_CACHE, self::AVAILABLE1
82
+            ],
83
+            [
84
+                // locking cache unavailable: no exception here in the factory
85
+                null, null, self::UNAVAILABLE1,
86
+                Factory::NULL_CACHE, Factory::NULL_CACHE, Factory::NULL_CACHE
87
+            ]
88
+        ];
89
+    }
90
+
91
+    public static function cacheUnavailableProvider(): array {
92
+        return [
93
+            [
94
+                // local available, distributed unavailable
95
+                self::AVAILABLE1, self::UNAVAILABLE1
96
+            ],
97
+            [
98
+                // local unavailable, distributed available
99
+                self::UNAVAILABLE1, self::AVAILABLE1
100
+            ],
101
+            [
102
+                // local and distributed unavailable
103
+                self::UNAVAILABLE1, self::UNAVAILABLE2
104
+            ],
105
+        ];
106
+    }
107
+
108
+    #[\PHPUnit\Framework\Attributes\DataProvider('cacheAvailabilityProvider')]
109
+    public function testCacheAvailability($localCache, $distributedCache, $lockingCache,
110
+        $expectedLocalCache, $expectedDistributedCache, $expectedLockingCache): void {
111
+        $logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
112
+        $profiler = $this->getMockBuilder(IProfiler::class)->getMock();
113
+        $serverVersion = $this->createMock(ServerVersion::class);
114
+        $factory = new Factory($logger, $profiler, $serverVersion, $localCache, $distributedCache, $lockingCache);
115
+        $this->assertTrue(is_a($factory->createLocal(), $expectedLocalCache));
116
+        $this->assertTrue(is_a($factory->createDistributed(), $expectedDistributedCache));
117
+        $this->assertTrue(is_a($factory->createLocking(), $expectedLockingCache));
118
+    }
119
+
120
+    #[\PHPUnit\Framework\Attributes\DataProvider('cacheUnavailableProvider')]
121
+    public function testCacheNotAvailableException($localCache, $distributedCache): void {
122
+        $this->expectException(HintException::class);
123
+
124
+        $logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
125
+        $profiler = $this->getMockBuilder(IProfiler::class)->getMock();
126
+        $serverVersion = $this->createMock(ServerVersion::class);
127
+        new Factory($logger, $profiler, $serverVersion, $localCache, $distributedCache);
128
+    }
129
+
130
+    public function testCreateInMemory(): void {
131
+        $logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
132
+        $profiler = $this->getMockBuilder(IProfiler::class)->getMock();
133
+        $serverVersion = $this->createMock(ServerVersion::class);
134
+        $factory = new Factory($logger, $profiler, $serverVersion, null, null, null);
135
+
136
+        $cache = $factory->createInMemory();
137
+        $cache->set('test', 48);
138
+
139
+        self::assertSame(48, $cache->get('test'));
140
+    }
141 141
 }
Please login to merge, or discard this patch.
tests/lib/Memcache/MemcachedTest.php 1 patch
Indentation   +39 added lines, -39 removed lines patch added patch discarded remove patch
@@ -13,43 +13,43 @@
 block discarded – undo
13 13
 #[\PHPUnit\Framework\Attributes\Group('Memcache')]
14 14
 #[\PHPUnit\Framework\Attributes\Group('Memcached')]
15 15
 class MemcachedTest extends Cache {
16
-	public static function setUpBeforeClass(): void {
17
-		parent::setUpBeforeClass();
18
-
19
-		if (!Memcached::isAvailable()) {
20
-			self::markTestSkipped('The memcached extension is not available.');
21
-		}
22
-		$instance = new Memcached(self::getUniqueID());
23
-		if ($instance->set(self::getUniqueID(), self::getUniqueID()) === false) {
24
-			self::markTestSkipped('memcached server seems to be down.');
25
-		}
26
-	}
27
-
28
-	protected function setUp(): void {
29
-		parent::setUp();
30
-		$this->instance = new Memcached($this->getUniqueID());
31
-	}
32
-
33
-	public function testClear(): void {
34
-		// Memcached is sometimes broken with clear(), so we don't test it thoroughly
35
-		$value = 'ipsum lorum';
36
-		$this->instance->set('1_value1', $value);
37
-		$this->instance->set('1_value2', $value);
38
-		$this->instance->set('2_value1', $value);
39
-		$this->instance->set('3_value1', $value);
40
-
41
-		$this->assertTrue($this->instance->clear('1_'));
42
-
43
-		$this->assertFalse($this->instance->hasKey('1_value1'));
44
-		$this->assertFalse($this->instance->hasKey('1_value2'));
45
-		//$this->assertTrue($this->instance->hasKey('2_value1'));
46
-		//$this->assertTrue($this->instance->hasKey('3_value1'));
47
-
48
-		$this->assertTrue($this->instance->clear());
49
-
50
-		$this->assertFalse($this->instance->hasKey('1_value1'));
51
-		$this->assertFalse($this->instance->hasKey('1_value2'));
52
-		$this->assertFalse($this->instance->hasKey('2_value1'));
53
-		$this->assertFalse($this->instance->hasKey('3_value1'));
54
-	}
16
+    public static function setUpBeforeClass(): void {
17
+        parent::setUpBeforeClass();
18
+
19
+        if (!Memcached::isAvailable()) {
20
+            self::markTestSkipped('The memcached extension is not available.');
21
+        }
22
+        $instance = new Memcached(self::getUniqueID());
23
+        if ($instance->set(self::getUniqueID(), self::getUniqueID()) === false) {
24
+            self::markTestSkipped('memcached server seems to be down.');
25
+        }
26
+    }
27
+
28
+    protected function setUp(): void {
29
+        parent::setUp();
30
+        $this->instance = new Memcached($this->getUniqueID());
31
+    }
32
+
33
+    public function testClear(): void {
34
+        // Memcached is sometimes broken with clear(), so we don't test it thoroughly
35
+        $value = 'ipsum lorum';
36
+        $this->instance->set('1_value1', $value);
37
+        $this->instance->set('1_value2', $value);
38
+        $this->instance->set('2_value1', $value);
39
+        $this->instance->set('3_value1', $value);
40
+
41
+        $this->assertTrue($this->instance->clear('1_'));
42
+
43
+        $this->assertFalse($this->instance->hasKey('1_value1'));
44
+        $this->assertFalse($this->instance->hasKey('1_value2'));
45
+        //$this->assertTrue($this->instance->hasKey('2_value1'));
46
+        //$this->assertTrue($this->instance->hasKey('3_value1'));
47
+
48
+        $this->assertTrue($this->instance->clear());
49
+
50
+        $this->assertFalse($this->instance->hasKey('1_value1'));
51
+        $this->assertFalse($this->instance->hasKey('1_value2'));
52
+        $this->assertFalse($this->instance->hasKey('2_value1'));
53
+        $this->assertFalse($this->instance->hasKey('3_value1'));
54
+    }
55 55
 }
Please login to merge, or discard this patch.
tests/lib/Memcache/CasTraitTest.php 1 patch
Indentation   +46 added lines, -46 removed lines patch added patch discarded remove patch
@@ -13,50 +13,50 @@
 block discarded – undo
13 13
 
14 14
 #[\PHPUnit\Framework\Attributes\Group('Memcache')]
15 15
 class CasTraitTest extends TestCase {
16
-	/**
17
-	 * @return \OC\Memcache\CasTrait
18
-	 */
19
-	private function getCache() {
20
-		$sourceCache = new ArrayCache();
21
-		$mock = $this->getMockForTrait('\OC\Memcache\CasTrait');
22
-
23
-		$mock->expects($this->any())
24
-			->method('set')
25
-			->willReturnCallback(function ($key, $value, $ttl) use ($sourceCache) {
26
-				return $sourceCache->set($key, $value, $ttl);
27
-			});
28
-
29
-		$mock->expects($this->any())
30
-			->method('get')
31
-			->willReturnCallback(function ($key) use ($sourceCache) {
32
-				return $sourceCache->get($key);
33
-			});
34
-
35
-		$mock->expects($this->any())
36
-			->method('add')
37
-			->willReturnCallback(function ($key, $value, $ttl) use ($sourceCache) {
38
-				return $sourceCache->add($key, $value, $ttl);
39
-			});
40
-
41
-		$mock->expects($this->any())
42
-			->method('remove')
43
-			->willReturnCallback(function ($key) use ($sourceCache) {
44
-				return $sourceCache->remove($key);
45
-			});
46
-		return $mock;
47
-	}
48
-
49
-	public function testCasNotChanged(): void {
50
-		$cache = $this->getCache();
51
-		$cache->set('foo', 'bar');
52
-		$this->assertTrue($cache->cas('foo', 'bar', 'asd'));
53
-		$this->assertEquals('asd', $cache->get('foo'));
54
-	}
55
-
56
-	public function testCasChanged(): void {
57
-		$cache = $this->getCache();
58
-		$cache->set('foo', 'bar1');
59
-		$this->assertFalse($cache->cas('foo', 'bar', 'asd'));
60
-		$this->assertEquals('bar1', $cache->get('foo'));
61
-	}
16
+    /**
17
+     * @return \OC\Memcache\CasTrait
18
+     */
19
+    private function getCache() {
20
+        $sourceCache = new ArrayCache();
21
+        $mock = $this->getMockForTrait('\OC\Memcache\CasTrait');
22
+
23
+        $mock->expects($this->any())
24
+            ->method('set')
25
+            ->willReturnCallback(function ($key, $value, $ttl) use ($sourceCache) {
26
+                return $sourceCache->set($key, $value, $ttl);
27
+            });
28
+
29
+        $mock->expects($this->any())
30
+            ->method('get')
31
+            ->willReturnCallback(function ($key) use ($sourceCache) {
32
+                return $sourceCache->get($key);
33
+            });
34
+
35
+        $mock->expects($this->any())
36
+            ->method('add')
37
+            ->willReturnCallback(function ($key, $value, $ttl) use ($sourceCache) {
38
+                return $sourceCache->add($key, $value, $ttl);
39
+            });
40
+
41
+        $mock->expects($this->any())
42
+            ->method('remove')
43
+            ->willReturnCallback(function ($key) use ($sourceCache) {
44
+                return $sourceCache->remove($key);
45
+            });
46
+        return $mock;
47
+    }
48
+
49
+    public function testCasNotChanged(): void {
50
+        $cache = $this->getCache();
51
+        $cache->set('foo', 'bar');
52
+        $this->assertTrue($cache->cas('foo', 'bar', 'asd'));
53
+        $this->assertEquals('asd', $cache->get('foo'));
54
+    }
55
+
56
+    public function testCasChanged(): void {
57
+        $cache = $this->getCache();
58
+        $cache->set('foo', 'bar1');
59
+        $this->assertFalse($cache->cas('foo', 'bar', 'asd'));
60
+        $this->assertEquals('bar1', $cache->get('foo'));
61
+    }
62 62
 }
Please login to merge, or discard this patch.
tests/lib/Memcache/ArrayCacheTest.php 1 patch
Indentation   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -12,8 +12,8 @@
 block discarded – undo
12 12
 
13 13
 #[\PHPUnit\Framework\Attributes\Group('Memcache')]
14 14
 class ArrayCacheTest extends Cache {
15
-	protected function setUp(): void {
16
-		parent::setUp();
17
-		$this->instance = new ArrayCache('');
18
-	}
15
+    protected function setUp(): void {
16
+        parent::setUp();
17
+        $this->instance = new ArrayCache('');
18
+    }
19 19
 }
Please login to merge, or discard this patch.
tests/lib/Memcache/APCuTest.php 1 patch
Indentation   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -13,25 +13,25 @@
 block discarded – undo
13 13
 #[\PHPUnit\Framework\Attributes\Group('Memcache')]
14 14
 #[\PHPUnit\Framework\Attributes\Group('APCu')]
15 15
 class APCuTest extends Cache {
16
-	protected function setUp(): void {
17
-		parent::setUp();
16
+    protected function setUp(): void {
17
+        parent::setUp();
18 18
 
19
-		if (!APCu::isAvailable()) {
20
-			$this->markTestSkipped('The APCu extension is not available.');
21
-			return;
22
-		}
23
-		$this->instance = new APCu($this->getUniqueID());
24
-	}
19
+        if (!APCu::isAvailable()) {
20
+            $this->markTestSkipped('The APCu extension is not available.');
21
+            return;
22
+        }
23
+        $this->instance = new APCu($this->getUniqueID());
24
+    }
25 25
 
26
-	public function testCasIntChanged(): void {
27
-		$this->instance->set('foo', 1);
28
-		$this->assertTrue($this->instance->cas('foo', 1, 2));
29
-		$this->assertEquals(2, $this->instance->get('foo'));
30
-	}
26
+    public function testCasIntChanged(): void {
27
+        $this->instance->set('foo', 1);
28
+        $this->assertTrue($this->instance->cas('foo', 1, 2));
29
+        $this->assertEquals(2, $this->instance->get('foo'));
30
+    }
31 31
 
32
-	public function testCasIntNotChanged(): void {
33
-		$this->instance->set('foo', 1);
34
-		$this->assertFalse($this->instance->cas('foo', 2, 3));
35
-		$this->assertEquals(1, $this->instance->get('foo'));
36
-	}
32
+    public function testCasIntNotChanged(): void {
33
+        $this->instance->set('foo', 1);
34
+        $this->assertFalse($this->instance->cas('foo', 2, 3));
35
+        $this->assertEquals(1, $this->instance->get('foo'));
36
+    }
37 37
 }
Please login to merge, or discard this patch.