Completed
Push — master ( 453450...6f0537 )
by
unknown
37:16
created
tests/lib/Share20/DefaultShareProviderTest.php 1 patch
Indentation   +3063 added lines, -3063 removed lines patch added patch discarded remove patch
@@ -44,3071 +44,3071 @@
 block discarded – undo
44 44
  */
45 45
 #[\PHPUnit\Framework\Attributes\Group('DB')]
46 46
 class DefaultShareProviderTest extends \Test\TestCase {
47
-	/** @var IDBConnection */
48
-	protected $dbConn;
49
-
50
-	/** @var IUserManager | MockObject */
51
-	protected $userManager;
52
-
53
-	/** @var IGroupManager | MockObject */
54
-	protected $groupManager;
55
-
56
-	/** @var IRootFolder | MockObject */
57
-	protected $rootFolder;
58
-
59
-	/** @var DefaultShareProvider */
60
-	protected $provider;
61
-
62
-	/** @var MockObject|IMailer */
63
-	protected $mailer;
64
-
65
-	/** @var IFactory|MockObject */
66
-	protected $l10nFactory;
67
-
68
-	/** @var MockObject|IL10N */
69
-	protected $l10n;
70
-
71
-	/** @var MockObject|Defaults */
72
-	protected $defaults;
73
-
74
-	/** @var MockObject|IURLGenerator */
75
-	protected $urlGenerator;
76
-
77
-	/** @var ITimeFactory|MockObject */
78
-	protected $timeFactory;
79
-
80
-	/** @var LoggerInterface|MockObject */
81
-	protected $logger;
82
-
83
-	protected IConfig&MockObject $config;
84
-
85
-	protected IShareManager&MockObject $shareManager;
86
-
87
-	protected function setUp(): void {
88
-		$this->dbConn = Server::get(IDBConnection::class);
89
-		$this->userManager = $this->createMock(IUserManager::class);
90
-		$this->groupManager = $this->createMock(IGroupManager::class);
91
-		$this->rootFolder = $this->createMock(IRootFolder::class);
92
-		$this->mailer = $this->createMock(IMailer::class);
93
-		$this->l10nFactory = $this->createMock(IFactory::class);
94
-		$this->l10n = $this->createMock(IL10N::class);
95
-		$this->defaults = $this->getMockBuilder(Defaults::class)->disableOriginalConstructor()->getMock();
96
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
97
-		$this->timeFactory = $this->createMock(ITimeFactory::class);
98
-		$this->logger = $this->createMock(LoggerInterface::class);
99
-		$this->shareManager = $this->createMock(IShareManager::class);
100
-		$this->config = $this->createMock(IConfig::class);
101
-
102
-		$this->userManager->expects($this->any())->method('userExists')->willReturn(true);
103
-		$this->timeFactory->expects($this->any())->method('now')->willReturn(new \DateTimeImmutable('2023-05-04 00:00 Europe/Berlin'));
104
-
105
-		//Empty share table
106
-		$this->dbConn->getQueryBuilder()->delete('share')->executeStatement();
107
-
108
-		$this->provider = new DefaultShareProvider(
109
-			$this->dbConn,
110
-			$this->userManager,
111
-			$this->groupManager,
112
-			$this->rootFolder,
113
-			$this->mailer,
114
-			$this->defaults,
115
-			$this->l10nFactory,
116
-			$this->urlGenerator,
117
-			$this->timeFactory,
118
-			$this->logger,
119
-			$this->shareManager,
120
-			$this->config,
121
-		);
122
-	}
123
-
124
-	protected function tearDown(): void {
125
-		$this->dbConn->getQueryBuilder()->delete('share')->executeStatement();
126
-		$this->dbConn->getQueryBuilder()->delete('filecache')->runAcrossAllShards()->executeStatement();
127
-		$this->dbConn->getQueryBuilder()->delete('storages')->executeStatement();
128
-	}
129
-
130
-	/**
131
-	 * @param int $shareType
132
-	 * @param string $sharedWith
133
-	 * @param string $sharedBy
134
-	 * @param string $shareOwner
135
-	 * @param string $itemType
136
-	 * @param int $fileSource
137
-	 * @param string $fileTarget
138
-	 * @param int $permissions
139
-	 * @param $token
140
-	 * @param $expiration
141
-	 * @return int
142
-	 */
143
-	private function addShareToDB($shareType, $sharedWith, $sharedBy, $shareOwner,
144
-		$itemType, $fileSource, $fileTarget, $permissions, $token, $expiration,
145
-		$parent = null) {
146
-		$qb = $this->dbConn->getQueryBuilder();
147
-		$qb->insert('share');
148
-
149
-		if ($shareType) {
150
-			$qb->setValue('share_type', $qb->expr()->literal($shareType));
151
-		}
152
-		if ($sharedWith) {
153
-			$qb->setValue('share_with', $qb->expr()->literal($sharedWith));
154
-		}
155
-		if ($sharedBy) {
156
-			$qb->setValue('uid_initiator', $qb->expr()->literal($sharedBy));
157
-		}
158
-		if ($shareOwner) {
159
-			$qb->setValue('uid_owner', $qb->expr()->literal($shareOwner));
160
-		}
161
-		if ($itemType) {
162
-			$qb->setValue('item_type', $qb->expr()->literal($itemType));
163
-		}
164
-		if ($fileSource) {
165
-			$qb->setValue('file_source', $qb->expr()->literal($fileSource));
166
-		}
167
-		if ($fileTarget) {
168
-			$qb->setValue('file_target', $qb->expr()->literal($fileTarget));
169
-		}
170
-		if ($permissions) {
171
-			$qb->setValue('permissions', $qb->expr()->literal($permissions));
172
-		}
173
-		if ($token) {
174
-			$qb->setValue('token', $qb->expr()->literal($token));
175
-		}
176
-		if ($expiration) {
177
-			$qb->setValue('expiration', $qb->createNamedParameter($expiration, IQueryBuilder::PARAM_DATETIME_MUTABLE));
178
-		}
179
-		if ($parent) {
180
-			$qb->setValue('parent', $qb->expr()->literal($parent));
181
-		}
182
-
183
-		$this->assertEquals(1, $qb->executeStatement());
184
-		return $qb->getLastInsertId();
185
-	}
186
-
187
-
188
-
189
-
190
-	public function testGetShareByIdNotExist(): void {
191
-		$this->expectException(ShareNotFound::class);
192
-
193
-		$this->provider->getShareById(1);
194
-	}
195
-
196
-	public function testGetShareByIdUserShare(): void {
197
-		$qb = $this->dbConn->getQueryBuilder();
198
-
199
-		$qb->insert('share')
200
-			->values([
201
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
202
-				'share_with' => $qb->expr()->literal('sharedWith'),
203
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
204
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
205
-				'item_type' => $qb->expr()->literal('file'),
206
-				'file_source' => $qb->expr()->literal(42),
207
-				'file_target' => $qb->expr()->literal('myTarget'),
208
-				'permissions' => $qb->expr()->literal(13),
209
-			]);
210
-		$qb->executeStatement();
211
-
212
-		$id = $qb->getLastInsertId();
213
-
214
-		$sharedBy = $this->createMock(IUser::class);
215
-		$sharedBy->method('getUID')->willReturn('sharedBy');
216
-		$shareOwner = $this->createMock(IUser::class);
217
-		$shareOwner->method('getUID')->willReturn('shareOwner');
218
-
219
-		$ownerPath = $this->createMock(File::class);
220
-		$shareOwnerFolder = $this->createMock(Folder::class);
221
-		$shareOwnerFolder->method('getFirstNodeById')->with(42)->willReturn($ownerPath);
222
-
223
-		$this->rootFolder
224
-			->method('getUserFolder')
225
-			->willReturnMap([
226
-				['shareOwner', $shareOwnerFolder],
227
-			]);
228
-
229
-		$share = $this->provider->getShareById($id);
230
-
231
-		$this->assertEquals($id, $share->getId());
232
-		$this->assertEquals(IShare::TYPE_USER, $share->getShareType());
233
-		$this->assertEquals('sharedWith', $share->getSharedWith());
234
-		$this->assertEquals('sharedBy', $share->getSharedBy());
235
-		$this->assertEquals('shareOwner', $share->getShareOwner());
236
-		$this->assertEquals($ownerPath, $share->getNode());
237
-		$this->assertEquals(13, $share->getPermissions());
238
-		$this->assertEquals(null, $share->getToken());
239
-		$this->assertEquals(null, $share->getExpirationDate());
240
-		$this->assertEquals('myTarget', $share->getTarget());
241
-	}
242
-
243
-	public function testGetShareByIdLazy(): void {
244
-		$qb = $this->dbConn->getQueryBuilder();
245
-
246
-		$qb->insert('share')
247
-			->values([
248
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
249
-				'share_with' => $qb->expr()->literal('sharedWith'),
250
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
251
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
252
-				'item_type' => $qb->expr()->literal('file'),
253
-				'file_source' => $qb->expr()->literal(42),
254
-				'file_target' => $qb->expr()->literal('myTarget'),
255
-				'permissions' => $qb->expr()->literal(13),
256
-			]);
257
-		$qb->executeStatement();
258
-
259
-		$id = $qb->getLastInsertId();
260
-
261
-		$this->rootFolder->expects($this->never())->method('getUserFolder');
262
-
263
-		$share = $this->provider->getShareById($id);
264
-
265
-		// We do not fetch the node so the rootfolder is never called.
266
-
267
-		$this->assertEquals($id, $share->getId());
268
-		$this->assertEquals(IShare::TYPE_USER, $share->getShareType());
269
-		$this->assertEquals('sharedWith', $share->getSharedWith());
270
-		$this->assertEquals('sharedBy', $share->getSharedBy());
271
-		$this->assertEquals('shareOwner', $share->getShareOwner());
272
-		$this->assertEquals(13, $share->getPermissions());
273
-		$this->assertEquals(null, $share->getToken());
274
-		$this->assertEquals(null, $share->getExpirationDate());
275
-		$this->assertEquals('myTarget', $share->getTarget());
276
-	}
277
-
278
-	public function testGetShareByIdLazy2(): void {
279
-		$qb = $this->dbConn->getQueryBuilder();
280
-
281
-		$qb->insert('share')
282
-			->values([
283
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
284
-				'share_with' => $qb->expr()->literal('sharedWith'),
285
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
286
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
287
-				'item_type' => $qb->expr()->literal('file'),
288
-				'file_source' => $qb->expr()->literal(42),
289
-				'file_target' => $qb->expr()->literal('myTarget'),
290
-				'permissions' => $qb->expr()->literal(13),
291
-			]);
292
-		$qb->executeStatement();
293
-
294
-		$id = $qb->getLastInsertId();
295
-
296
-		$ownerPath = $this->createMock(File::class);
297
-
298
-		$shareOwnerFolder = $this->createMock(Folder::class);
299
-		$shareOwnerFolder->method('getFirstNodeById')->with(42)->willReturn($ownerPath);
300
-
301
-		$this->rootFolder
302
-			->method('getUserFolder')
303
-			->with('shareOwner')
304
-			->willReturn($shareOwnerFolder);
305
-
306
-		$share = $this->provider->getShareById($id);
307
-
308
-		// We fetch the node so the root folder is eventually called
309
-
310
-		$this->assertEquals($id, $share->getId());
311
-		$this->assertEquals(IShare::TYPE_USER, $share->getShareType());
312
-		$this->assertEquals('sharedWith', $share->getSharedWith());
313
-		$this->assertEquals('sharedBy', $share->getSharedBy());
314
-		$this->assertEquals('shareOwner', $share->getShareOwner());
315
-		$this->assertEquals($ownerPath, $share->getNode());
316
-		$this->assertEquals(13, $share->getPermissions());
317
-		$this->assertEquals(null, $share->getToken());
318
-		$this->assertEquals(null, $share->getExpirationDate());
319
-		$this->assertEquals('myTarget', $share->getTarget());
320
-	}
321
-
322
-	public function testGetShareByIdGroupShare(): void {
323
-		$qb = $this->dbConn->getQueryBuilder();
324
-
325
-		$qb->insert('share')
326
-			->values([
327
-				'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
328
-				'share_with' => $qb->expr()->literal('sharedWith'),
329
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
330
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
331
-				'item_type' => $qb->expr()->literal('file'),
332
-				'file_source' => $qb->expr()->literal(42),
333
-				'file_target' => $qb->expr()->literal('myTarget'),
334
-				'permissions' => $qb->expr()->literal(13),
335
-			]);
336
-		$this->assertEquals(1, $qb->executeStatement());
337
-
338
-		// Get the id
339
-		$id = $qb->getLastInsertId();
340
-
341
-		$ownerPath = $this->createMock(Folder::class);
342
-		$shareOwnerFolder = $this->createMock(Folder::class);
343
-		$shareOwnerFolder->method('getFirstNodeById')->with(42)->willReturn($ownerPath);
344
-
345
-		$this->rootFolder
346
-			->method('getUserFolder')
347
-			->willReturnMap([
348
-				['shareOwner', $shareOwnerFolder],
349
-			]);
350
-
351
-		$share = $this->provider->getShareById($id);
352
-
353
-		$this->assertEquals($id, $share->getId());
354
-		$this->assertEquals(IShare::TYPE_GROUP, $share->getShareType());
355
-		$this->assertEquals('sharedWith', $share->getSharedWith());
356
-		$this->assertEquals('sharedBy', $share->getSharedBy());
357
-		$this->assertEquals('shareOwner', $share->getShareOwner());
358
-		$this->assertEquals($ownerPath, $share->getNode());
359
-		$this->assertEquals(13, $share->getPermissions());
360
-		$this->assertEquals(null, $share->getToken());
361
-		$this->assertEquals(null, $share->getExpirationDate());
362
-		$this->assertEquals('myTarget', $share->getTarget());
363
-	}
364
-
365
-	public function testGetShareByIdUserGroupShare(): void {
366
-		$id = $this->addShareToDB(IShare::TYPE_GROUP, 'group0', 'user0', 'user0', 'file', 42, 'myTarget', 31, null, null);
367
-		$this->addShareToDB(2, 'user1', 'user0', 'user0', 'file', 42, 'userTarget', 0, null, null, $id);
368
-
369
-		$user0 = $this->createMock(IUser::class);
370
-		$user0->method('getUID')->willReturn('user0');
371
-		$user1 = $this->createMock(IUser::class);
372
-		$user1->method('getUID')->willReturn('user1');
373
-
374
-		$group0 = $this->createMock(IGroup::class);
375
-		$group0->method('inGroup')->with($user1)->willReturn(true);
376
-		$group0->method('getDisplayName')->willReturn('g0-displayname');
377
-
378
-		$node = $this->createMock(Folder::class);
379
-		$node->method('getId')->willReturn(42);
380
-		$node->method('getName')->willReturn('myTarget');
381
-
382
-		$this->rootFolder->method('getUserFolder')->with('user0')->willReturnSelf();
383
-		$this->rootFolder->method('getFirstNodeById')->willReturn($node);
384
-
385
-		$this->userManager->method('get')->willReturnMap([
386
-			['user0', $user0],
387
-			['user1', $user1],
388
-		]);
389
-		$this->groupManager->method('get')->with('group0')->willReturn($group0);
390
-
391
-		$share = $this->provider->getShareById($id, 'user1');
392
-
393
-		$this->assertEquals($id, $share->getId());
394
-		$this->assertEquals(IShare::TYPE_GROUP, $share->getShareType());
395
-		$this->assertSame('group0', $share->getSharedWith());
396
-		$this->assertSame('user0', $share->getSharedBy());
397
-		$this->assertSame('user0', $share->getShareOwner());
398
-		$this->assertSame($node, $share->getNode());
399
-		$this->assertEquals(0, $share->getPermissions());
400
-		$this->assertEquals(null, $share->getToken());
401
-		$this->assertEquals(null, $share->getExpirationDate());
402
-		$this->assertEquals('userTarget', $share->getTarget());
403
-	}
404
-
405
-	public function testGetShareByIdLinkShare(): void {
406
-		$qb = $this->dbConn->getQueryBuilder();
407
-
408
-		$qb->insert('share')
409
-			->values([
410
-				'share_type' => $qb->expr()->literal(IShare::TYPE_LINK),
411
-				'password' => $qb->expr()->literal('password'),
412
-				'password_by_talk' => $qb->expr()->literal(true),
413
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
414
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
415
-				'item_type' => $qb->expr()->literal('file'),
416
-				'file_source' => $qb->expr()->literal(42),
417
-				'file_target' => $qb->expr()->literal('myTarget'),
418
-				'permissions' => $qb->expr()->literal(13),
419
-				'token' => $qb->expr()->literal('token'),
420
-				'expiration' => $qb->expr()->literal('2000-01-02 00:00:00'),
421
-			]);
422
-		$this->assertEquals(1, $qb->executeStatement());
423
-
424
-		$id = $qb->getLastInsertId();
425
-
426
-		$ownerPath = $this->createMock(Folder::class);
427
-		$shareOwnerFolder = $this->createMock(Folder::class);
428
-		$shareOwnerFolder->method('getFirstNodeById')->with(42)->willReturn($ownerPath);
429
-
430
-		$this->rootFolder
431
-			->method('getUserFolder')
432
-			->willReturnMap([
433
-				['shareOwner', $shareOwnerFolder],
434
-			]);
435
-
436
-		$share = $this->provider->getShareById($id);
437
-
438
-		$this->assertEquals($id, $share->getId());
439
-		$this->assertEquals(IShare::TYPE_LINK, $share->getShareType());
440
-		$this->assertNull($share->getSharedWith());
441
-		$this->assertEquals('password', $share->getPassword());
442
-		$this->assertEquals(true, $share->getSendPasswordByTalk());
443
-		$this->assertEquals('sharedBy', $share->getSharedBy());
444
-		$this->assertEquals('shareOwner', $share->getShareOwner());
445
-		$this->assertEquals($ownerPath, $share->getNode());
446
-		$this->assertEquals(13, $share->getPermissions());
447
-		$this->assertEquals('token', $share->getToken());
448
-		$this->assertEquals(\DateTime::createFromFormat('Y-m-d H:i:s', '2000-01-02 00:00:00'), $share->getExpirationDate());
449
-		$this->assertEquals('myTarget', $share->getTarget());
450
-	}
451
-
452
-	public function testDeleteSingleShare(): void {
453
-		$qb = $this->dbConn->getQueryBuilder();
454
-		$qb->insert('share')
455
-			->values([
456
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
457
-				'share_with' => $qb->expr()->literal('sharedWith'),
458
-				'uid_owner' => $qb->expr()->literal('sharedBy'),
459
-				'item_type' => $qb->expr()->literal('file'),
460
-				'file_source' => $qb->expr()->literal(42),
461
-				'file_target' => $qb->expr()->literal('myTarget'),
462
-				'permissions' => $qb->expr()->literal(13),
463
-			]);
464
-		$this->assertEquals(1, $qb->executeStatement());
465
-
466
-		$id = $qb->getLastInsertId();
467
-
468
-		$share = $this->createMock(IShare::class);
469
-		$share->method('getId')->willReturn($id);
470
-
471
-		/** @var DefaultShareProvider $provider */
472
-		$provider = $this->getMockBuilder(DefaultShareProvider::class)
473
-			->setConstructorArgs([
474
-				$this->dbConn,
475
-				$this->userManager,
476
-				$this->groupManager,
477
-				$this->rootFolder,
478
-				$this->mailer,
479
-				$this->defaults,
480
-				$this->l10nFactory,
481
-				$this->urlGenerator,
482
-				$this->timeFactory,
483
-				$this->logger,
484
-				$this->shareManager,
485
-				$this->config,
486
-			])
487
-			->onlyMethods(['getShareById'])
488
-			->getMock();
489
-
490
-		$provider->delete($share);
491
-
492
-		$qb = $this->dbConn->getQueryBuilder();
493
-		$qb->select('*')
494
-			->from('share');
495
-
496
-		$cursor = $qb->executeQuery();
497
-		$result = $cursor->fetchAllAssociative();
498
-		$cursor->closeCursor();
499
-
500
-		$this->assertEmpty($result);
501
-	}
502
-
503
-	public function testDeleteSingleShareLazy(): void {
504
-		$qb = $this->dbConn->getQueryBuilder();
505
-		$qb->insert('share')
506
-			->values([
507
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
508
-				'share_with' => $qb->expr()->literal('sharedWith'),
509
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
510
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
511
-				'item_type' => $qb->expr()->literal('file'),
512
-				'file_source' => $qb->expr()->literal(42),
513
-				'file_target' => $qb->expr()->literal('myTarget'),
514
-				'permissions' => $qb->expr()->literal(13),
515
-			]);
516
-		$this->assertEquals(1, $qb->executeStatement());
517
-
518
-		$id = $qb->getLastInsertId();
519
-
520
-		$this->rootFolder->expects($this->never())->method($this->anything());
521
-
522
-		$share = $this->provider->getShareById($id);
523
-		$this->provider->delete($share);
524
-
525
-		$qb = $this->dbConn->getQueryBuilder();
526
-		$qb->select('*')
527
-			->from('share');
528
-
529
-		$cursor = $qb->executeQuery();
530
-		$result = $cursor->fetchAllAssociative();
531
-		$cursor->closeCursor();
532
-
533
-		$this->assertEmpty($result);
534
-	}
535
-
536
-	public function testDeleteGroupShareWithUserGroupShares(): void {
537
-		$qb = $this->dbConn->getQueryBuilder();
538
-		$qb->insert('share')
539
-			->values([
540
-				'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
541
-				'share_with' => $qb->expr()->literal('sharedWith'),
542
-				'uid_owner' => $qb->expr()->literal('sharedBy'),
543
-				'item_type' => $qb->expr()->literal('file'),
544
-				'file_source' => $qb->expr()->literal(42),
545
-				'file_target' => $qb->expr()->literal('myTarget'),
546
-				'permissions' => $qb->expr()->literal(13),
547
-			]);
548
-		$this->assertEquals(1, $qb->executeStatement());
549
-		$id = $qb->getLastInsertId();
550
-
551
-		$qb = $this->dbConn->getQueryBuilder();
552
-		$qb->insert('share')
553
-			->values([
554
-				'share_type' => $qb->expr()->literal(2),
555
-				'share_with' => $qb->expr()->literal('sharedWithUser'),
556
-				'uid_owner' => $qb->expr()->literal('sharedBy'),
557
-				'item_type' => $qb->expr()->literal('file'),
558
-				'file_source' => $qb->expr()->literal(42),
559
-				'file_target' => $qb->expr()->literal('myTarget'),
560
-				'permissions' => $qb->expr()->literal(13),
561
-				'parent' => $qb->expr()->literal($id),
562
-			]);
563
-		$this->assertEquals(1, $qb->executeStatement());
564
-
565
-		$share = $this->createMock(IShare::class);
566
-		$share->method('getId')->willReturn($id);
567
-		$share->method('getShareType')->willReturn(IShare::TYPE_GROUP);
568
-
569
-		/** @var DefaultShareProvider $provider */
570
-		$provider = $this->getMockBuilder(DefaultShareProvider::class)
571
-			->setConstructorArgs([
572
-				$this->dbConn,
573
-				$this->userManager,
574
-				$this->groupManager,
575
-				$this->rootFolder,
576
-				$this->mailer,
577
-				$this->defaults,
578
-				$this->l10nFactory,
579
-				$this->urlGenerator,
580
-				$this->timeFactory,
581
-				$this->logger,
582
-				$this->shareManager,
583
-				$this->config,
584
-			])
585
-			->onlyMethods(['getShareById'])
586
-			->getMock();
587
-
588
-		$provider->delete($share);
589
-
590
-		$qb = $this->dbConn->getQueryBuilder();
591
-		$qb->select('*')
592
-			->from('share');
593
-
594
-		$cursor = $qb->executeQuery();
595
-		$result = $cursor->fetchAllAssociative();
596
-		$cursor->closeCursor();
597
-
598
-		$this->assertEmpty($result);
599
-	}
600
-
601
-	public function testGetChildren(): void {
602
-		$qb = $this->dbConn->getQueryBuilder();
603
-		$qb->insert('share')
604
-			->values([
605
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
606
-				'share_with' => $qb->expr()->literal('sharedWith'),
607
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
608
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
609
-				'item_type' => $qb->expr()->literal('file'),
610
-				'file_source' => $qb->expr()->literal(42),
611
-				'file_target' => $qb->expr()->literal('myTarget'),
612
-				'permissions' => $qb->expr()->literal(13),
613
-			]);
614
-		$qb->executeStatement();
615
-
616
-		// Get the id
617
-		$id = $qb->getLastInsertId();
618
-
619
-		$qb = $this->dbConn->getQueryBuilder();
620
-		$qb->insert('share')
621
-			->values([
622
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
623
-				'share_with' => $qb->expr()->literal('user1'),
624
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
625
-				'uid_initiator' => $qb->expr()->literal('user2'),
626
-				'item_type' => $qb->expr()->literal('file'),
627
-				'file_source' => $qb->expr()->literal(1),
628
-				'file_target' => $qb->expr()->literal('myTarget1'),
629
-				'permissions' => $qb->expr()->literal(2),
630
-				'parent' => $qb->expr()->literal($id),
631
-			]);
632
-		$qb->executeStatement();
633
-
634
-		$qb = $this->dbConn->getQueryBuilder();
635
-		$qb->insert('share')
636
-			->values([
637
-				'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
638
-				'share_with' => $qb->expr()->literal('group1'),
639
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
640
-				'uid_initiator' => $qb->expr()->literal('user3'),
641
-				'item_type' => $qb->expr()->literal('folder'),
642
-				'file_source' => $qb->expr()->literal(3),
643
-				'file_target' => $qb->expr()->literal('myTarget2'),
644
-				'permissions' => $qb->expr()->literal(4),
645
-				'parent' => $qb->expr()->literal($id),
646
-			]);
647
-		$qb->executeStatement();
648
-
649
-		$ownerPath = $this->createMock(Folder::class);
650
-		$ownerFolder = $this->createMock(Folder::class);
651
-		$ownerFolder->method('getFirstNodeById')->willReturn($ownerPath);
652
-
653
-		$this->rootFolder
654
-			->method('getUserFolder')
655
-			->willReturnMap([
656
-				['shareOwner', $ownerFolder],
657
-			]);
658
-
659
-		$share = $this->createMock(IShare::class);
660
-		$share->method('getId')->willReturn($id);
661
-
662
-		$children = $this->provider->getChildren($share);
663
-
664
-		$this->assertCount(2, $children);
665
-
666
-		//Child1
667
-		$this->assertEquals(IShare::TYPE_USER, $children[0]->getShareType());
668
-		$this->assertEquals('user1', $children[0]->getSharedWith());
669
-		$this->assertEquals('user2', $children[0]->getSharedBy());
670
-		$this->assertEquals('shareOwner', $children[0]->getShareOwner());
671
-		$this->assertEquals($ownerPath, $children[0]->getNode());
672
-		$this->assertEquals(2, $children[0]->getPermissions());
673
-		$this->assertEquals(null, $children[0]->getToken());
674
-		$this->assertEquals(null, $children[0]->getExpirationDate());
675
-		$this->assertEquals('myTarget1', $children[0]->getTarget());
676
-
677
-		//Child2
678
-		$this->assertEquals(IShare::TYPE_GROUP, $children[1]->getShareType());
679
-		$this->assertEquals('group1', $children[1]->getSharedWith());
680
-		$this->assertEquals('user3', $children[1]->getSharedBy());
681
-		$this->assertEquals('shareOwner', $children[1]->getShareOwner());
682
-		$this->assertEquals($ownerPath, $children[1]->getNode());
683
-		$this->assertEquals(4, $children[1]->getPermissions());
684
-		$this->assertEquals(null, $children[1]->getToken());
685
-		$this->assertEquals(null, $children[1]->getExpirationDate());
686
-		$this->assertEquals('myTarget2', $children[1]->getTarget());
687
-	}
688
-
689
-	public function testCreateUserShare(): void {
690
-		$share = new Share($this->rootFolder, $this->userManager);
691
-
692
-		$shareOwner = $this->createMock(IUser::class);
693
-		$shareOwner->method('getUID')->willReturn('shareOwner');
694
-
695
-		$path = $this->createMock(File::class);
696
-		$path->method('getId')->willReturn(100);
697
-		$path->method('getOwner')->willReturn($shareOwner);
698
-
699
-		$ownerFolder = $this->createMock(Folder::class);
700
-		$userFolder = $this->createMock(Folder::class);
701
-		$this->rootFolder
702
-			->method('getUserFolder')
703
-			->willReturnMap([
704
-				['sharedBy', $userFolder],
705
-				['shareOwner', $ownerFolder],
706
-			]);
707
-
708
-		$userFolder->method('getFirstNodeById')
709
-			->with(100)
710
-			->willReturn($path);
711
-		$ownerFolder->method('getFirstNodeById')
712
-			->with(100)
713
-			->willReturn($path);
714
-
715
-		$share->setShareType(IShare::TYPE_USER);
716
-		$share->setSharedWith('sharedWith');
717
-		$share->setSharedBy('sharedBy');
718
-		$share->setShareOwner('shareOwner');
719
-		$share->setNode($path);
720
-		$share->setSharedWithDisplayName('Displayed Name');
721
-		$share->setSharedWithAvatar('/path/to/image.svg');
722
-		$share->setPermissions(1);
723
-
724
-		$attrs = new ShareAttributes();
725
-		$attrs->setAttribute('permissions', 'download', true);
726
-		$share->setAttributes($attrs);
727
-
728
-		$share->setTarget('/target');
729
-
730
-		$share2 = $this->provider->create($share);
731
-
732
-		$this->assertNotNull($share2->getId());
733
-		$this->assertSame('ocinternal:' . $share2->getId(), $share2->getFullId());
734
-		$this->assertSame(IShare::TYPE_USER, $share2->getShareType());
735
-		$this->assertSame('sharedWith', $share2->getSharedWith());
736
-		$this->assertSame('sharedBy', $share2->getSharedBy());
737
-		$this->assertSame('shareOwner', $share2->getShareOwner());
738
-		$this->assertSame(1, $share2->getPermissions());
739
-		$this->assertSame('/target', $share2->getTarget());
740
-		$this->assertLessThanOrEqual(new \DateTime(), $share2->getShareTime());
741
-		$this->assertSame($path, $share2->getNode());
742
-
743
-		// Data is kept after creation
744
-		$this->assertSame('Displayed Name', $share->getSharedWithDisplayName());
745
-		$this->assertSame('/path/to/image.svg', $share->getSharedWithAvatar());
746
-		$this->assertSame('Displayed Name', $share2->getSharedWithDisplayName());
747
-		$this->assertSame('/path/to/image.svg', $share2->getSharedWithAvatar());
748
-
749
-		$this->assertSame(
750
-			[
751
-				[
752
-					'scope' => 'permissions',
753
-					'key' => 'download',
754
-					'value' => true
755
-				]
756
-			],
757
-			$share->getAttributes()->toArray()
758
-		);
759
-	}
760
-
761
-	public function testCreateGroupShare(): void {
762
-		$share = new Share($this->rootFolder, $this->userManager);
763
-
764
-		$shareOwner = $this->createMock(IUser::class);
765
-		$shareOwner->method('getUID')->willReturn('shareOwner');
766
-
767
-		$path = $this->createMock(Folder::class);
768
-		$path->method('getId')->willReturn(100);
769
-		$path->method('getOwner')->willReturn($shareOwner);
770
-
771
-		$ownerFolder = $this->createMock(Folder::class);
772
-		$userFolder = $this->createMock(Folder::class);
773
-		$this->rootFolder
774
-			->method('getUserFolder')
775
-			->willReturnMap([
776
-				['sharedBy', $userFolder],
777
-				['shareOwner', $ownerFolder],
778
-			]);
779
-
780
-		$userFolder->method('getFirstNodeById')
781
-			->with(100)
782
-			->willReturn($path);
783
-		$ownerFolder->method('getFirstNodeById')
784
-			->with(100)
785
-			->willReturn($path);
786
-
787
-		$share->setShareType(IShare::TYPE_GROUP);
788
-		$share->setSharedWith('sharedWith');
789
-		$share->setSharedBy('sharedBy');
790
-		$share->setShareOwner('shareOwner');
791
-		$share->setNode($path);
792
-		$share->setPermissions(1);
793
-		$share->setSharedWithDisplayName('Displayed Name');
794
-		$share->setSharedWithAvatar('/path/to/image.svg');
795
-		$share->setTarget('/target');
796
-		$attrs = new ShareAttributes();
797
-		$attrs->setAttribute('permissions', 'download', true);
798
-		$share->setAttributes($attrs);
799
-
800
-		$share2 = $this->provider->create($share);
801
-
802
-		$this->assertNotNull($share2->getId());
803
-		$this->assertSame('ocinternal:' . $share2->getId(), $share2->getFullId());
804
-		$this->assertSame(IShare::TYPE_GROUP, $share2->getShareType());
805
-		$this->assertSame('sharedWith', $share2->getSharedWith());
806
-		$this->assertSame('sharedBy', $share2->getSharedBy());
807
-		$this->assertSame('shareOwner', $share2->getShareOwner());
808
-		$this->assertSame(1, $share2->getPermissions());
809
-		$this->assertSame('/target', $share2->getTarget());
810
-		$this->assertLessThanOrEqual(new \DateTime(), $share2->getShareTime());
811
-		$this->assertSame($path, $share2->getNode());
812
-
813
-		// Data is kept after creation
814
-		$this->assertSame('Displayed Name', $share->getSharedWithDisplayName());
815
-		$this->assertSame('/path/to/image.svg', $share->getSharedWithAvatar());
816
-		$this->assertSame('Displayed Name', $share2->getSharedWithDisplayName());
817
-		$this->assertSame('/path/to/image.svg', $share2->getSharedWithAvatar());
818
-
819
-		$this->assertSame(
820
-			[
821
-				[
822
-					'scope' => 'permissions',
823
-					'key' => 'download',
824
-					'value' => true
825
-				]
826
-			],
827
-			$share->getAttributes()->toArray()
828
-		);
829
-	}
830
-
831
-	public function testCreateLinkShare(): void {
832
-		$share = new Share($this->rootFolder, $this->userManager);
833
-
834
-		$shareOwner = $this->createMock(IUser::class);
835
-		$shareOwner->method('getUID')->willReturn('shareOwner');
836
-
837
-		$path = $this->createMock(Folder::class);
838
-		$path->method('getId')->willReturn(100);
839
-		$path->method('getOwner')->willReturn($shareOwner);
840
-
841
-		$ownerFolder = $this->createMock(Folder::class);
842
-		$userFolder = $this->createMock(Folder::class);
843
-		$this->rootFolder
844
-			->method('getUserFolder')
845
-			->willReturnMap([
846
-				['sharedBy', $userFolder],
847
-				['shareOwner', $ownerFolder],
848
-			]);
849
-
850
-		$userFolder->method('getFirstNodeById')
851
-			->with(100)
852
-			->willReturn($path);
853
-		$ownerFolder->method('getFirstNodeById')
854
-			->with(100)
855
-			->willReturn($path);
856
-
857
-		$share->setShareType(IShare::TYPE_LINK);
858
-		$share->setSharedBy('sharedBy');
859
-		$share->setShareOwner('shareOwner');
860
-		$share->setNode($path);
861
-		$share->setPermissions(1);
862
-		$share->setPassword('password');
863
-		$share->setSendPasswordByTalk(true);
864
-		$share->setToken('token');
865
-		$expireDate = new \DateTime();
866
-		$share->setExpirationDate($expireDate);
867
-		$share->setTarget('/target');
868
-
869
-		$share2 = $this->provider->create($share);
870
-
871
-		$this->assertNotNull($share2->getId());
872
-		$this->assertSame('ocinternal:' . $share2->getId(), $share2->getFullId());
873
-		$this->assertSame(IShare::TYPE_LINK, $share2->getShareType());
874
-		$this->assertSame('sharedBy', $share2->getSharedBy());
875
-		$this->assertSame('shareOwner', $share2->getShareOwner());
876
-		$this->assertSame(1, $share2->getPermissions());
877
-		$this->assertSame('/target', $share2->getTarget());
878
-		$this->assertLessThanOrEqual(new \DateTime(), $share2->getShareTime());
879
-		$this->assertSame($path, $share2->getNode());
880
-		$this->assertSame('password', $share2->getPassword());
881
-		$this->assertSame(true, $share2->getSendPasswordByTalk());
882
-		$this->assertSame('token', $share2->getToken());
883
-		$this->assertEquals($expireDate->getTimestamp(), $share2->getExpirationDate()->getTimestamp());
884
-	}
885
-
886
-	public function testGetShareByToken(): void {
887
-		$qb = $this->dbConn->getQueryBuilder();
888
-
889
-		$qb->insert('share')
890
-			->values([
891
-				'share_type' => $qb->expr()->literal(IShare::TYPE_LINK),
892
-				'password' => $qb->expr()->literal('password'),
893
-				'password_by_talk' => $qb->expr()->literal(true),
894
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
895
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
896
-				'item_type' => $qb->expr()->literal('file'),
897
-				'file_source' => $qb->expr()->literal(42),
898
-				'file_target' => $qb->expr()->literal('myTarget'),
899
-				'permissions' => $qb->expr()->literal(13),
900
-				'token' => $qb->expr()->literal('secrettoken'),
901
-				'label' => $qb->expr()->literal('the label'),
902
-			]);
903
-		$qb->executeStatement();
904
-		$id = $qb->getLastInsertId();
905
-
906
-		$file = $this->createMock(File::class);
907
-
908
-		$this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
909
-		$this->rootFolder->method('getFirstNodeById')->with(42)->willReturn($file);
910
-
911
-		$share = $this->provider->getShareByToken('secrettoken');
912
-		$this->assertEquals($id, $share->getId());
913
-		$this->assertSame('shareOwner', $share->getShareOwner());
914
-		$this->assertSame('sharedBy', $share->getSharedBy());
915
-		$this->assertSame('secrettoken', $share->getToken());
916
-		$this->assertSame('password', $share->getPassword());
917
-		$this->assertSame('the label', $share->getLabel());
918
-		$this->assertSame(true, $share->getSendPasswordByTalk());
919
-		$this->assertSame(null, $share->getSharedWith());
920
-	}
921
-
922
-	/**
923
-	 * Assert that if no label is provided the label is correctly,
924
-	 * as types on IShare, a string and not null
925
-	 */
926
-	public function testGetShareByTokenNullLabel(): void {
927
-		$qb = $this->dbConn->getQueryBuilder();
928
-
929
-		$qb->insert('share')
930
-			->values([
931
-				'share_type' => $qb->expr()->literal(IShare::TYPE_LINK),
932
-				'password' => $qb->expr()->literal('password'),
933
-				'password_by_talk' => $qb->expr()->literal(true),
934
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
935
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
936
-				'item_type' => $qb->expr()->literal('file'),
937
-				'file_source' => $qb->expr()->literal(42),
938
-				'file_target' => $qb->expr()->literal('myTarget'),
939
-				'permissions' => $qb->expr()->literal(13),
940
-				'token' => $qb->expr()->literal('secrettoken'),
941
-			]);
942
-		$qb->executeStatement();
943
-		$id = $qb->getLastInsertId();
944
-
945
-		$file = $this->createMock(File::class);
946
-
947
-		$this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
948
-		$this->rootFolder->method('getFirstNodeById')->with(42)->willReturn($file);
949
-
950
-		$share = $this->provider->getShareByToken('secrettoken');
951
-		$this->assertEquals($id, $share->getId());
952
-		$this->assertSame('', $share->getLabel());
953
-	}
954
-
955
-	public function testGetShareByTokenNotFound(): void {
956
-		$this->expectException(ShareNotFound::class);
957
-
958
-		$this->provider->getShareByToken('invalidtoken');
959
-	}
960
-
961
-	private function createTestStorageEntry($storageStringId) {
962
-		$qb = $this->dbConn->getQueryBuilder();
963
-		$qb->insert('storages')
964
-			->values([
965
-				'id' => $qb->expr()->literal($storageStringId),
966
-			]);
967
-		$this->assertEquals(1, $qb->executeStatement());
968
-		return $qb->getLastInsertId();
969
-	}
970
-
971
-	private function createTestFileEntry($path, $storage = 1) {
972
-		$qb = $this->dbConn->getQueryBuilder();
973
-		$qb->insert('filecache')
974
-			->values([
975
-				'storage' => $qb->createNamedParameter($storage, IQueryBuilder::PARAM_INT),
976
-				'path' => $qb->createNamedParameter($path),
977
-				'path_hash' => $qb->createNamedParameter(md5($path)),
978
-				'name' => $qb->createNamedParameter(basename($path)),
979
-			]);
980
-		$this->assertEquals(1, $qb->executeStatement());
981
-		return $qb->getLastInsertId();
982
-	}
983
-
984
-	public static function storageAndFileNameProvider(): array {
985
-		return [
986
-			// regular file on regular storage
987
-			['home::shareOwner', 'files/test.txt', 'files/test2.txt'],
988
-			// regular file on external storage
989
-			['smb::whatever', 'files/test.txt', 'files/test2.txt'],
990
-			// regular file on external storage in trashbin-like folder,
991
-			['smb::whatever', 'files_trashbin/files/test.txt', 'files_trashbin/files/test2.txt'],
992
-		];
993
-	}
994
-
995
-	#[\PHPUnit\Framework\Attributes\DataProvider('storageAndFileNameProvider')]
996
-	public function testGetSharedWithUser($storageStringId, $fileName1, $fileName2): void {
997
-		$storageId = $this->createTestStorageEntry($storageStringId);
998
-		$fileId = $this->createTestFileEntry($fileName1, $storageId);
999
-		$fileId2 = $this->createTestFileEntry($fileName2, $storageId);
1000
-		$qb = $this->dbConn->getQueryBuilder();
1001
-		$qb->insert('share')
1002
-			->values([
1003
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1004
-				'share_with' => $qb->expr()->literal('sharedWith'),
1005
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
1006
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
1007
-				'item_type' => $qb->expr()->literal('file'),
1008
-				'file_source' => $qb->expr()->literal($fileId),
1009
-				'file_target' => $qb->expr()->literal('myTarget'),
1010
-				'permissions' => $qb->expr()->literal(13),
1011
-			]);
1012
-		$this->assertEquals(1, $qb->executeStatement());
1013
-		$id = $qb->getLastInsertId();
1014
-
1015
-		$qb = $this->dbConn->getQueryBuilder();
1016
-		$qb->insert('share')
1017
-			->values([
1018
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1019
-				'share_with' => $qb->expr()->literal('sharedWith2'),
1020
-				'uid_owner' => $qb->expr()->literal('shareOwner2'),
1021
-				'uid_initiator' => $qb->expr()->literal('sharedBy2'),
1022
-				'item_type' => $qb->expr()->literal('file2'),
1023
-				'file_source' => $qb->expr()->literal($fileId2),
1024
-				'file_target' => $qb->expr()->literal('myTarget2'),
1025
-				'permissions' => $qb->expr()->literal(14),
1026
-			]);
1027
-		$this->assertEquals(1, $qb->executeStatement());
1028
-
1029
-		$file = $this->createMock(File::class);
1030
-		$this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
1031
-		$this->rootFolder->method('getFirstNodeById')->with($fileId)->willReturn($file);
1032
-
1033
-		$share = $this->provider->getSharedWith('sharedWith', IShare::TYPE_USER, null, 1, 0);
1034
-		$this->assertCount(1, $share);
1035
-
1036
-		$share = $share[0];
1037
-		$this->assertEquals($id, $share->getId());
1038
-		$this->assertEquals('sharedWith', $share->getSharedWith());
1039
-		$this->assertEquals('shareOwner', $share->getShareOwner());
1040
-		$this->assertEquals('sharedBy', $share->getSharedBy());
1041
-		$this->assertEquals(IShare::TYPE_USER, $share->getShareType());
1042
-	}
1043
-
1044
-	#[\PHPUnit\Framework\Attributes\DataProvider('storageAndFileNameProvider')]
1045
-	public function testGetSharedWithGroup($storageStringId, $fileName1, $fileName2): void {
1046
-		$storageId = $this->createTestStorageEntry($storageStringId);
1047
-		$fileId = $this->createTestFileEntry($fileName1, $storageId);
1048
-		$fileId2 = $this->createTestFileEntry($fileName2, $storageId);
1049
-		$qb = $this->dbConn->getQueryBuilder();
1050
-		$qb->insert('share')
1051
-			->values([
1052
-				'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
1053
-				'share_with' => $qb->expr()->literal('sharedWith'),
1054
-				'uid_owner' => $qb->expr()->literal('shareOwner2'),
1055
-				'uid_initiator' => $qb->expr()->literal('sharedBy2'),
1056
-				'item_type' => $qb->expr()->literal('file'),
1057
-				'file_source' => $qb->expr()->literal($fileId2),
1058
-				'file_target' => $qb->expr()->literal('myTarget2'),
1059
-				'permissions' => $qb->expr()->literal(14),
1060
-			]);
1061
-		$this->assertEquals(1, $qb->executeStatement());
1062
-
1063
-		$qb = $this->dbConn->getQueryBuilder();
1064
-		$qb->insert('share')
1065
-			->values([
1066
-				'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
1067
-				'share_with' => $qb->expr()->literal('sharedWith'),
1068
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
1069
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
1070
-				'item_type' => $qb->expr()->literal('file'),
1071
-				'file_source' => $qb->expr()->literal($fileId),
1072
-				'file_target' => $qb->expr()->literal('myTarget'),
1073
-				'permissions' => $qb->expr()->literal(13),
1074
-			]);
1075
-		$this->assertEquals(1, $qb->executeStatement());
1076
-		$id = $qb->getLastInsertId();
1077
-
1078
-		$groups = [];
1079
-		foreach (range(0, 100) as $i) {
1080
-			$groups[] = 'group' . $i;
1081
-		}
1082
-
1083
-		$groups[] = 'sharedWith';
1084
-
1085
-		$user = $this->createMock(IUser::class);
1086
-		$user->method('getUID')->willReturn('sharedWith');
1087
-		$owner = $this->createMock(IUser::class);
1088
-		$owner->method('getUID')->willReturn('shareOwner');
1089
-		$initiator = $this->createMock(IUser::class);
1090
-		$initiator->method('getUID')->willReturn('sharedBy');
1091
-
1092
-		$this->userManager->method('get')->willReturnMap([
1093
-			['sharedWith', $user],
1094
-			['shareOwner', $owner],
1095
-			['sharedBy', $initiator],
1096
-		]);
1097
-		$this->groupManager
1098
-			->method('getUserGroupIds')
1099
-			->willReturnCallback(fn (IUser $user) => ($user->getUID() === 'sharedWith' ? $groups : []));
1100
-
1101
-		$file = $this->createMock(File::class);
1102
-		$this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
1103
-		$this->rootFolder->method('getFirstNodeById')->with($fileId)->willReturn($file);
1104
-
1105
-		$share = $this->provider->getSharedWith('sharedWith', IShare::TYPE_GROUP, null, 20, 1);
1106
-		$this->assertCount(1, $share);
1107
-
1108
-		$share = $share[0];
1109
-		$this->assertEquals($id, $share->getId());
1110
-		$this->assertEquals('sharedWith', $share->getSharedWith());
1111
-		$this->assertEquals('shareOwner', $share->getShareOwner());
1112
-		$this->assertEquals('sharedBy', $share->getSharedBy());
1113
-		$this->assertEquals(IShare::TYPE_GROUP, $share->getShareType());
1114
-	}
1115
-
1116
-	#[\PHPUnit\Framework\Attributes\DataProvider('storageAndFileNameProvider')]
1117
-	public function testGetSharedWithGroupUserModified($storageStringId, $fileName1, $fileName2): void {
1118
-		$storageId = $this->createTestStorageEntry($storageStringId);
1119
-		$fileId = $this->createTestFileEntry($fileName1, $storageId);
1120
-		$qb = $this->dbConn->getQueryBuilder();
1121
-		$qb->insert('share')
1122
-			->values([
1123
-				'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
1124
-				'share_with' => $qb->expr()->literal('sharedWith'),
1125
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
1126
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
1127
-				'item_type' => $qb->expr()->literal('file'),
1128
-				'file_source' => $qb->expr()->literal($fileId),
1129
-				'file_target' => $qb->expr()->literal('myTarget'),
1130
-				'permissions' => $qb->expr()->literal(13),
1131
-			]);
1132
-		$this->assertEquals(1, $qb->executeStatement());
1133
-		$id = $qb->getLastInsertId();
1134
-
1135
-		/*
47
+    /** @var IDBConnection */
48
+    protected $dbConn;
49
+
50
+    /** @var IUserManager | MockObject */
51
+    protected $userManager;
52
+
53
+    /** @var IGroupManager | MockObject */
54
+    protected $groupManager;
55
+
56
+    /** @var IRootFolder | MockObject */
57
+    protected $rootFolder;
58
+
59
+    /** @var DefaultShareProvider */
60
+    protected $provider;
61
+
62
+    /** @var MockObject|IMailer */
63
+    protected $mailer;
64
+
65
+    /** @var IFactory|MockObject */
66
+    protected $l10nFactory;
67
+
68
+    /** @var MockObject|IL10N */
69
+    protected $l10n;
70
+
71
+    /** @var MockObject|Defaults */
72
+    protected $defaults;
73
+
74
+    /** @var MockObject|IURLGenerator */
75
+    protected $urlGenerator;
76
+
77
+    /** @var ITimeFactory|MockObject */
78
+    protected $timeFactory;
79
+
80
+    /** @var LoggerInterface|MockObject */
81
+    protected $logger;
82
+
83
+    protected IConfig&MockObject $config;
84
+
85
+    protected IShareManager&MockObject $shareManager;
86
+
87
+    protected function setUp(): void {
88
+        $this->dbConn = Server::get(IDBConnection::class);
89
+        $this->userManager = $this->createMock(IUserManager::class);
90
+        $this->groupManager = $this->createMock(IGroupManager::class);
91
+        $this->rootFolder = $this->createMock(IRootFolder::class);
92
+        $this->mailer = $this->createMock(IMailer::class);
93
+        $this->l10nFactory = $this->createMock(IFactory::class);
94
+        $this->l10n = $this->createMock(IL10N::class);
95
+        $this->defaults = $this->getMockBuilder(Defaults::class)->disableOriginalConstructor()->getMock();
96
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
97
+        $this->timeFactory = $this->createMock(ITimeFactory::class);
98
+        $this->logger = $this->createMock(LoggerInterface::class);
99
+        $this->shareManager = $this->createMock(IShareManager::class);
100
+        $this->config = $this->createMock(IConfig::class);
101
+
102
+        $this->userManager->expects($this->any())->method('userExists')->willReturn(true);
103
+        $this->timeFactory->expects($this->any())->method('now')->willReturn(new \DateTimeImmutable('2023-05-04 00:00 Europe/Berlin'));
104
+
105
+        //Empty share table
106
+        $this->dbConn->getQueryBuilder()->delete('share')->executeStatement();
107
+
108
+        $this->provider = new DefaultShareProvider(
109
+            $this->dbConn,
110
+            $this->userManager,
111
+            $this->groupManager,
112
+            $this->rootFolder,
113
+            $this->mailer,
114
+            $this->defaults,
115
+            $this->l10nFactory,
116
+            $this->urlGenerator,
117
+            $this->timeFactory,
118
+            $this->logger,
119
+            $this->shareManager,
120
+            $this->config,
121
+        );
122
+    }
123
+
124
+    protected function tearDown(): void {
125
+        $this->dbConn->getQueryBuilder()->delete('share')->executeStatement();
126
+        $this->dbConn->getQueryBuilder()->delete('filecache')->runAcrossAllShards()->executeStatement();
127
+        $this->dbConn->getQueryBuilder()->delete('storages')->executeStatement();
128
+    }
129
+
130
+    /**
131
+     * @param int $shareType
132
+     * @param string $sharedWith
133
+     * @param string $sharedBy
134
+     * @param string $shareOwner
135
+     * @param string $itemType
136
+     * @param int $fileSource
137
+     * @param string $fileTarget
138
+     * @param int $permissions
139
+     * @param $token
140
+     * @param $expiration
141
+     * @return int
142
+     */
143
+    private function addShareToDB($shareType, $sharedWith, $sharedBy, $shareOwner,
144
+        $itemType, $fileSource, $fileTarget, $permissions, $token, $expiration,
145
+        $parent = null) {
146
+        $qb = $this->dbConn->getQueryBuilder();
147
+        $qb->insert('share');
148
+
149
+        if ($shareType) {
150
+            $qb->setValue('share_type', $qb->expr()->literal($shareType));
151
+        }
152
+        if ($sharedWith) {
153
+            $qb->setValue('share_with', $qb->expr()->literal($sharedWith));
154
+        }
155
+        if ($sharedBy) {
156
+            $qb->setValue('uid_initiator', $qb->expr()->literal($sharedBy));
157
+        }
158
+        if ($shareOwner) {
159
+            $qb->setValue('uid_owner', $qb->expr()->literal($shareOwner));
160
+        }
161
+        if ($itemType) {
162
+            $qb->setValue('item_type', $qb->expr()->literal($itemType));
163
+        }
164
+        if ($fileSource) {
165
+            $qb->setValue('file_source', $qb->expr()->literal($fileSource));
166
+        }
167
+        if ($fileTarget) {
168
+            $qb->setValue('file_target', $qb->expr()->literal($fileTarget));
169
+        }
170
+        if ($permissions) {
171
+            $qb->setValue('permissions', $qb->expr()->literal($permissions));
172
+        }
173
+        if ($token) {
174
+            $qb->setValue('token', $qb->expr()->literal($token));
175
+        }
176
+        if ($expiration) {
177
+            $qb->setValue('expiration', $qb->createNamedParameter($expiration, IQueryBuilder::PARAM_DATETIME_MUTABLE));
178
+        }
179
+        if ($parent) {
180
+            $qb->setValue('parent', $qb->expr()->literal($parent));
181
+        }
182
+
183
+        $this->assertEquals(1, $qb->executeStatement());
184
+        return $qb->getLastInsertId();
185
+    }
186
+
187
+
188
+
189
+
190
+    public function testGetShareByIdNotExist(): void {
191
+        $this->expectException(ShareNotFound::class);
192
+
193
+        $this->provider->getShareById(1);
194
+    }
195
+
196
+    public function testGetShareByIdUserShare(): void {
197
+        $qb = $this->dbConn->getQueryBuilder();
198
+
199
+        $qb->insert('share')
200
+            ->values([
201
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
202
+                'share_with' => $qb->expr()->literal('sharedWith'),
203
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
204
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
205
+                'item_type' => $qb->expr()->literal('file'),
206
+                'file_source' => $qb->expr()->literal(42),
207
+                'file_target' => $qb->expr()->literal('myTarget'),
208
+                'permissions' => $qb->expr()->literal(13),
209
+            ]);
210
+        $qb->executeStatement();
211
+
212
+        $id = $qb->getLastInsertId();
213
+
214
+        $sharedBy = $this->createMock(IUser::class);
215
+        $sharedBy->method('getUID')->willReturn('sharedBy');
216
+        $shareOwner = $this->createMock(IUser::class);
217
+        $shareOwner->method('getUID')->willReturn('shareOwner');
218
+
219
+        $ownerPath = $this->createMock(File::class);
220
+        $shareOwnerFolder = $this->createMock(Folder::class);
221
+        $shareOwnerFolder->method('getFirstNodeById')->with(42)->willReturn($ownerPath);
222
+
223
+        $this->rootFolder
224
+            ->method('getUserFolder')
225
+            ->willReturnMap([
226
+                ['shareOwner', $shareOwnerFolder],
227
+            ]);
228
+
229
+        $share = $this->provider->getShareById($id);
230
+
231
+        $this->assertEquals($id, $share->getId());
232
+        $this->assertEquals(IShare::TYPE_USER, $share->getShareType());
233
+        $this->assertEquals('sharedWith', $share->getSharedWith());
234
+        $this->assertEquals('sharedBy', $share->getSharedBy());
235
+        $this->assertEquals('shareOwner', $share->getShareOwner());
236
+        $this->assertEquals($ownerPath, $share->getNode());
237
+        $this->assertEquals(13, $share->getPermissions());
238
+        $this->assertEquals(null, $share->getToken());
239
+        $this->assertEquals(null, $share->getExpirationDate());
240
+        $this->assertEquals('myTarget', $share->getTarget());
241
+    }
242
+
243
+    public function testGetShareByIdLazy(): void {
244
+        $qb = $this->dbConn->getQueryBuilder();
245
+
246
+        $qb->insert('share')
247
+            ->values([
248
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
249
+                'share_with' => $qb->expr()->literal('sharedWith'),
250
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
251
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
252
+                'item_type' => $qb->expr()->literal('file'),
253
+                'file_source' => $qb->expr()->literal(42),
254
+                'file_target' => $qb->expr()->literal('myTarget'),
255
+                'permissions' => $qb->expr()->literal(13),
256
+            ]);
257
+        $qb->executeStatement();
258
+
259
+        $id = $qb->getLastInsertId();
260
+
261
+        $this->rootFolder->expects($this->never())->method('getUserFolder');
262
+
263
+        $share = $this->provider->getShareById($id);
264
+
265
+        // We do not fetch the node so the rootfolder is never called.
266
+
267
+        $this->assertEquals($id, $share->getId());
268
+        $this->assertEquals(IShare::TYPE_USER, $share->getShareType());
269
+        $this->assertEquals('sharedWith', $share->getSharedWith());
270
+        $this->assertEquals('sharedBy', $share->getSharedBy());
271
+        $this->assertEquals('shareOwner', $share->getShareOwner());
272
+        $this->assertEquals(13, $share->getPermissions());
273
+        $this->assertEquals(null, $share->getToken());
274
+        $this->assertEquals(null, $share->getExpirationDate());
275
+        $this->assertEquals('myTarget', $share->getTarget());
276
+    }
277
+
278
+    public function testGetShareByIdLazy2(): void {
279
+        $qb = $this->dbConn->getQueryBuilder();
280
+
281
+        $qb->insert('share')
282
+            ->values([
283
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
284
+                'share_with' => $qb->expr()->literal('sharedWith'),
285
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
286
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
287
+                'item_type' => $qb->expr()->literal('file'),
288
+                'file_source' => $qb->expr()->literal(42),
289
+                'file_target' => $qb->expr()->literal('myTarget'),
290
+                'permissions' => $qb->expr()->literal(13),
291
+            ]);
292
+        $qb->executeStatement();
293
+
294
+        $id = $qb->getLastInsertId();
295
+
296
+        $ownerPath = $this->createMock(File::class);
297
+
298
+        $shareOwnerFolder = $this->createMock(Folder::class);
299
+        $shareOwnerFolder->method('getFirstNodeById')->with(42)->willReturn($ownerPath);
300
+
301
+        $this->rootFolder
302
+            ->method('getUserFolder')
303
+            ->with('shareOwner')
304
+            ->willReturn($shareOwnerFolder);
305
+
306
+        $share = $this->provider->getShareById($id);
307
+
308
+        // We fetch the node so the root folder is eventually called
309
+
310
+        $this->assertEquals($id, $share->getId());
311
+        $this->assertEquals(IShare::TYPE_USER, $share->getShareType());
312
+        $this->assertEquals('sharedWith', $share->getSharedWith());
313
+        $this->assertEquals('sharedBy', $share->getSharedBy());
314
+        $this->assertEquals('shareOwner', $share->getShareOwner());
315
+        $this->assertEquals($ownerPath, $share->getNode());
316
+        $this->assertEquals(13, $share->getPermissions());
317
+        $this->assertEquals(null, $share->getToken());
318
+        $this->assertEquals(null, $share->getExpirationDate());
319
+        $this->assertEquals('myTarget', $share->getTarget());
320
+    }
321
+
322
+    public function testGetShareByIdGroupShare(): void {
323
+        $qb = $this->dbConn->getQueryBuilder();
324
+
325
+        $qb->insert('share')
326
+            ->values([
327
+                'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
328
+                'share_with' => $qb->expr()->literal('sharedWith'),
329
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
330
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
331
+                'item_type' => $qb->expr()->literal('file'),
332
+                'file_source' => $qb->expr()->literal(42),
333
+                'file_target' => $qb->expr()->literal('myTarget'),
334
+                'permissions' => $qb->expr()->literal(13),
335
+            ]);
336
+        $this->assertEquals(1, $qb->executeStatement());
337
+
338
+        // Get the id
339
+        $id = $qb->getLastInsertId();
340
+
341
+        $ownerPath = $this->createMock(Folder::class);
342
+        $shareOwnerFolder = $this->createMock(Folder::class);
343
+        $shareOwnerFolder->method('getFirstNodeById')->with(42)->willReturn($ownerPath);
344
+
345
+        $this->rootFolder
346
+            ->method('getUserFolder')
347
+            ->willReturnMap([
348
+                ['shareOwner', $shareOwnerFolder],
349
+            ]);
350
+
351
+        $share = $this->provider->getShareById($id);
352
+
353
+        $this->assertEquals($id, $share->getId());
354
+        $this->assertEquals(IShare::TYPE_GROUP, $share->getShareType());
355
+        $this->assertEquals('sharedWith', $share->getSharedWith());
356
+        $this->assertEquals('sharedBy', $share->getSharedBy());
357
+        $this->assertEquals('shareOwner', $share->getShareOwner());
358
+        $this->assertEquals($ownerPath, $share->getNode());
359
+        $this->assertEquals(13, $share->getPermissions());
360
+        $this->assertEquals(null, $share->getToken());
361
+        $this->assertEquals(null, $share->getExpirationDate());
362
+        $this->assertEquals('myTarget', $share->getTarget());
363
+    }
364
+
365
+    public function testGetShareByIdUserGroupShare(): void {
366
+        $id = $this->addShareToDB(IShare::TYPE_GROUP, 'group0', 'user0', 'user0', 'file', 42, 'myTarget', 31, null, null);
367
+        $this->addShareToDB(2, 'user1', 'user0', 'user0', 'file', 42, 'userTarget', 0, null, null, $id);
368
+
369
+        $user0 = $this->createMock(IUser::class);
370
+        $user0->method('getUID')->willReturn('user0');
371
+        $user1 = $this->createMock(IUser::class);
372
+        $user1->method('getUID')->willReturn('user1');
373
+
374
+        $group0 = $this->createMock(IGroup::class);
375
+        $group0->method('inGroup')->with($user1)->willReturn(true);
376
+        $group0->method('getDisplayName')->willReturn('g0-displayname');
377
+
378
+        $node = $this->createMock(Folder::class);
379
+        $node->method('getId')->willReturn(42);
380
+        $node->method('getName')->willReturn('myTarget');
381
+
382
+        $this->rootFolder->method('getUserFolder')->with('user0')->willReturnSelf();
383
+        $this->rootFolder->method('getFirstNodeById')->willReturn($node);
384
+
385
+        $this->userManager->method('get')->willReturnMap([
386
+            ['user0', $user0],
387
+            ['user1', $user1],
388
+        ]);
389
+        $this->groupManager->method('get')->with('group0')->willReturn($group0);
390
+
391
+        $share = $this->provider->getShareById($id, 'user1');
392
+
393
+        $this->assertEquals($id, $share->getId());
394
+        $this->assertEquals(IShare::TYPE_GROUP, $share->getShareType());
395
+        $this->assertSame('group0', $share->getSharedWith());
396
+        $this->assertSame('user0', $share->getSharedBy());
397
+        $this->assertSame('user0', $share->getShareOwner());
398
+        $this->assertSame($node, $share->getNode());
399
+        $this->assertEquals(0, $share->getPermissions());
400
+        $this->assertEquals(null, $share->getToken());
401
+        $this->assertEquals(null, $share->getExpirationDate());
402
+        $this->assertEquals('userTarget', $share->getTarget());
403
+    }
404
+
405
+    public function testGetShareByIdLinkShare(): void {
406
+        $qb = $this->dbConn->getQueryBuilder();
407
+
408
+        $qb->insert('share')
409
+            ->values([
410
+                'share_type' => $qb->expr()->literal(IShare::TYPE_LINK),
411
+                'password' => $qb->expr()->literal('password'),
412
+                'password_by_talk' => $qb->expr()->literal(true),
413
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
414
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
415
+                'item_type' => $qb->expr()->literal('file'),
416
+                'file_source' => $qb->expr()->literal(42),
417
+                'file_target' => $qb->expr()->literal('myTarget'),
418
+                'permissions' => $qb->expr()->literal(13),
419
+                'token' => $qb->expr()->literal('token'),
420
+                'expiration' => $qb->expr()->literal('2000-01-02 00:00:00'),
421
+            ]);
422
+        $this->assertEquals(1, $qb->executeStatement());
423
+
424
+        $id = $qb->getLastInsertId();
425
+
426
+        $ownerPath = $this->createMock(Folder::class);
427
+        $shareOwnerFolder = $this->createMock(Folder::class);
428
+        $shareOwnerFolder->method('getFirstNodeById')->with(42)->willReturn($ownerPath);
429
+
430
+        $this->rootFolder
431
+            ->method('getUserFolder')
432
+            ->willReturnMap([
433
+                ['shareOwner', $shareOwnerFolder],
434
+            ]);
435
+
436
+        $share = $this->provider->getShareById($id);
437
+
438
+        $this->assertEquals($id, $share->getId());
439
+        $this->assertEquals(IShare::TYPE_LINK, $share->getShareType());
440
+        $this->assertNull($share->getSharedWith());
441
+        $this->assertEquals('password', $share->getPassword());
442
+        $this->assertEquals(true, $share->getSendPasswordByTalk());
443
+        $this->assertEquals('sharedBy', $share->getSharedBy());
444
+        $this->assertEquals('shareOwner', $share->getShareOwner());
445
+        $this->assertEquals($ownerPath, $share->getNode());
446
+        $this->assertEquals(13, $share->getPermissions());
447
+        $this->assertEquals('token', $share->getToken());
448
+        $this->assertEquals(\DateTime::createFromFormat('Y-m-d H:i:s', '2000-01-02 00:00:00'), $share->getExpirationDate());
449
+        $this->assertEquals('myTarget', $share->getTarget());
450
+    }
451
+
452
+    public function testDeleteSingleShare(): void {
453
+        $qb = $this->dbConn->getQueryBuilder();
454
+        $qb->insert('share')
455
+            ->values([
456
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
457
+                'share_with' => $qb->expr()->literal('sharedWith'),
458
+                'uid_owner' => $qb->expr()->literal('sharedBy'),
459
+                'item_type' => $qb->expr()->literal('file'),
460
+                'file_source' => $qb->expr()->literal(42),
461
+                'file_target' => $qb->expr()->literal('myTarget'),
462
+                'permissions' => $qb->expr()->literal(13),
463
+            ]);
464
+        $this->assertEquals(1, $qb->executeStatement());
465
+
466
+        $id = $qb->getLastInsertId();
467
+
468
+        $share = $this->createMock(IShare::class);
469
+        $share->method('getId')->willReturn($id);
470
+
471
+        /** @var DefaultShareProvider $provider */
472
+        $provider = $this->getMockBuilder(DefaultShareProvider::class)
473
+            ->setConstructorArgs([
474
+                $this->dbConn,
475
+                $this->userManager,
476
+                $this->groupManager,
477
+                $this->rootFolder,
478
+                $this->mailer,
479
+                $this->defaults,
480
+                $this->l10nFactory,
481
+                $this->urlGenerator,
482
+                $this->timeFactory,
483
+                $this->logger,
484
+                $this->shareManager,
485
+                $this->config,
486
+            ])
487
+            ->onlyMethods(['getShareById'])
488
+            ->getMock();
489
+
490
+        $provider->delete($share);
491
+
492
+        $qb = $this->dbConn->getQueryBuilder();
493
+        $qb->select('*')
494
+            ->from('share');
495
+
496
+        $cursor = $qb->executeQuery();
497
+        $result = $cursor->fetchAllAssociative();
498
+        $cursor->closeCursor();
499
+
500
+        $this->assertEmpty($result);
501
+    }
502
+
503
+    public function testDeleteSingleShareLazy(): void {
504
+        $qb = $this->dbConn->getQueryBuilder();
505
+        $qb->insert('share')
506
+            ->values([
507
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
508
+                'share_with' => $qb->expr()->literal('sharedWith'),
509
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
510
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
511
+                'item_type' => $qb->expr()->literal('file'),
512
+                'file_source' => $qb->expr()->literal(42),
513
+                'file_target' => $qb->expr()->literal('myTarget'),
514
+                'permissions' => $qb->expr()->literal(13),
515
+            ]);
516
+        $this->assertEquals(1, $qb->executeStatement());
517
+
518
+        $id = $qb->getLastInsertId();
519
+
520
+        $this->rootFolder->expects($this->never())->method($this->anything());
521
+
522
+        $share = $this->provider->getShareById($id);
523
+        $this->provider->delete($share);
524
+
525
+        $qb = $this->dbConn->getQueryBuilder();
526
+        $qb->select('*')
527
+            ->from('share');
528
+
529
+        $cursor = $qb->executeQuery();
530
+        $result = $cursor->fetchAllAssociative();
531
+        $cursor->closeCursor();
532
+
533
+        $this->assertEmpty($result);
534
+    }
535
+
536
+    public function testDeleteGroupShareWithUserGroupShares(): void {
537
+        $qb = $this->dbConn->getQueryBuilder();
538
+        $qb->insert('share')
539
+            ->values([
540
+                'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
541
+                'share_with' => $qb->expr()->literal('sharedWith'),
542
+                'uid_owner' => $qb->expr()->literal('sharedBy'),
543
+                'item_type' => $qb->expr()->literal('file'),
544
+                'file_source' => $qb->expr()->literal(42),
545
+                'file_target' => $qb->expr()->literal('myTarget'),
546
+                'permissions' => $qb->expr()->literal(13),
547
+            ]);
548
+        $this->assertEquals(1, $qb->executeStatement());
549
+        $id = $qb->getLastInsertId();
550
+
551
+        $qb = $this->dbConn->getQueryBuilder();
552
+        $qb->insert('share')
553
+            ->values([
554
+                'share_type' => $qb->expr()->literal(2),
555
+                'share_with' => $qb->expr()->literal('sharedWithUser'),
556
+                'uid_owner' => $qb->expr()->literal('sharedBy'),
557
+                'item_type' => $qb->expr()->literal('file'),
558
+                'file_source' => $qb->expr()->literal(42),
559
+                'file_target' => $qb->expr()->literal('myTarget'),
560
+                'permissions' => $qb->expr()->literal(13),
561
+                'parent' => $qb->expr()->literal($id),
562
+            ]);
563
+        $this->assertEquals(1, $qb->executeStatement());
564
+
565
+        $share = $this->createMock(IShare::class);
566
+        $share->method('getId')->willReturn($id);
567
+        $share->method('getShareType')->willReturn(IShare::TYPE_GROUP);
568
+
569
+        /** @var DefaultShareProvider $provider */
570
+        $provider = $this->getMockBuilder(DefaultShareProvider::class)
571
+            ->setConstructorArgs([
572
+                $this->dbConn,
573
+                $this->userManager,
574
+                $this->groupManager,
575
+                $this->rootFolder,
576
+                $this->mailer,
577
+                $this->defaults,
578
+                $this->l10nFactory,
579
+                $this->urlGenerator,
580
+                $this->timeFactory,
581
+                $this->logger,
582
+                $this->shareManager,
583
+                $this->config,
584
+            ])
585
+            ->onlyMethods(['getShareById'])
586
+            ->getMock();
587
+
588
+        $provider->delete($share);
589
+
590
+        $qb = $this->dbConn->getQueryBuilder();
591
+        $qb->select('*')
592
+            ->from('share');
593
+
594
+        $cursor = $qb->executeQuery();
595
+        $result = $cursor->fetchAllAssociative();
596
+        $cursor->closeCursor();
597
+
598
+        $this->assertEmpty($result);
599
+    }
600
+
601
+    public function testGetChildren(): void {
602
+        $qb = $this->dbConn->getQueryBuilder();
603
+        $qb->insert('share')
604
+            ->values([
605
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
606
+                'share_with' => $qb->expr()->literal('sharedWith'),
607
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
608
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
609
+                'item_type' => $qb->expr()->literal('file'),
610
+                'file_source' => $qb->expr()->literal(42),
611
+                'file_target' => $qb->expr()->literal('myTarget'),
612
+                'permissions' => $qb->expr()->literal(13),
613
+            ]);
614
+        $qb->executeStatement();
615
+
616
+        // Get the id
617
+        $id = $qb->getLastInsertId();
618
+
619
+        $qb = $this->dbConn->getQueryBuilder();
620
+        $qb->insert('share')
621
+            ->values([
622
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
623
+                'share_with' => $qb->expr()->literal('user1'),
624
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
625
+                'uid_initiator' => $qb->expr()->literal('user2'),
626
+                'item_type' => $qb->expr()->literal('file'),
627
+                'file_source' => $qb->expr()->literal(1),
628
+                'file_target' => $qb->expr()->literal('myTarget1'),
629
+                'permissions' => $qb->expr()->literal(2),
630
+                'parent' => $qb->expr()->literal($id),
631
+            ]);
632
+        $qb->executeStatement();
633
+
634
+        $qb = $this->dbConn->getQueryBuilder();
635
+        $qb->insert('share')
636
+            ->values([
637
+                'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
638
+                'share_with' => $qb->expr()->literal('group1'),
639
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
640
+                'uid_initiator' => $qb->expr()->literal('user3'),
641
+                'item_type' => $qb->expr()->literal('folder'),
642
+                'file_source' => $qb->expr()->literal(3),
643
+                'file_target' => $qb->expr()->literal('myTarget2'),
644
+                'permissions' => $qb->expr()->literal(4),
645
+                'parent' => $qb->expr()->literal($id),
646
+            ]);
647
+        $qb->executeStatement();
648
+
649
+        $ownerPath = $this->createMock(Folder::class);
650
+        $ownerFolder = $this->createMock(Folder::class);
651
+        $ownerFolder->method('getFirstNodeById')->willReturn($ownerPath);
652
+
653
+        $this->rootFolder
654
+            ->method('getUserFolder')
655
+            ->willReturnMap([
656
+                ['shareOwner', $ownerFolder],
657
+            ]);
658
+
659
+        $share = $this->createMock(IShare::class);
660
+        $share->method('getId')->willReturn($id);
661
+
662
+        $children = $this->provider->getChildren($share);
663
+
664
+        $this->assertCount(2, $children);
665
+
666
+        //Child1
667
+        $this->assertEquals(IShare::TYPE_USER, $children[0]->getShareType());
668
+        $this->assertEquals('user1', $children[0]->getSharedWith());
669
+        $this->assertEquals('user2', $children[0]->getSharedBy());
670
+        $this->assertEquals('shareOwner', $children[0]->getShareOwner());
671
+        $this->assertEquals($ownerPath, $children[0]->getNode());
672
+        $this->assertEquals(2, $children[0]->getPermissions());
673
+        $this->assertEquals(null, $children[0]->getToken());
674
+        $this->assertEquals(null, $children[0]->getExpirationDate());
675
+        $this->assertEquals('myTarget1', $children[0]->getTarget());
676
+
677
+        //Child2
678
+        $this->assertEquals(IShare::TYPE_GROUP, $children[1]->getShareType());
679
+        $this->assertEquals('group1', $children[1]->getSharedWith());
680
+        $this->assertEquals('user3', $children[1]->getSharedBy());
681
+        $this->assertEquals('shareOwner', $children[1]->getShareOwner());
682
+        $this->assertEquals($ownerPath, $children[1]->getNode());
683
+        $this->assertEquals(4, $children[1]->getPermissions());
684
+        $this->assertEquals(null, $children[1]->getToken());
685
+        $this->assertEquals(null, $children[1]->getExpirationDate());
686
+        $this->assertEquals('myTarget2', $children[1]->getTarget());
687
+    }
688
+
689
+    public function testCreateUserShare(): void {
690
+        $share = new Share($this->rootFolder, $this->userManager);
691
+
692
+        $shareOwner = $this->createMock(IUser::class);
693
+        $shareOwner->method('getUID')->willReturn('shareOwner');
694
+
695
+        $path = $this->createMock(File::class);
696
+        $path->method('getId')->willReturn(100);
697
+        $path->method('getOwner')->willReturn($shareOwner);
698
+
699
+        $ownerFolder = $this->createMock(Folder::class);
700
+        $userFolder = $this->createMock(Folder::class);
701
+        $this->rootFolder
702
+            ->method('getUserFolder')
703
+            ->willReturnMap([
704
+                ['sharedBy', $userFolder],
705
+                ['shareOwner', $ownerFolder],
706
+            ]);
707
+
708
+        $userFolder->method('getFirstNodeById')
709
+            ->with(100)
710
+            ->willReturn($path);
711
+        $ownerFolder->method('getFirstNodeById')
712
+            ->with(100)
713
+            ->willReturn($path);
714
+
715
+        $share->setShareType(IShare::TYPE_USER);
716
+        $share->setSharedWith('sharedWith');
717
+        $share->setSharedBy('sharedBy');
718
+        $share->setShareOwner('shareOwner');
719
+        $share->setNode($path);
720
+        $share->setSharedWithDisplayName('Displayed Name');
721
+        $share->setSharedWithAvatar('/path/to/image.svg');
722
+        $share->setPermissions(1);
723
+
724
+        $attrs = new ShareAttributes();
725
+        $attrs->setAttribute('permissions', 'download', true);
726
+        $share->setAttributes($attrs);
727
+
728
+        $share->setTarget('/target');
729
+
730
+        $share2 = $this->provider->create($share);
731
+
732
+        $this->assertNotNull($share2->getId());
733
+        $this->assertSame('ocinternal:' . $share2->getId(), $share2->getFullId());
734
+        $this->assertSame(IShare::TYPE_USER, $share2->getShareType());
735
+        $this->assertSame('sharedWith', $share2->getSharedWith());
736
+        $this->assertSame('sharedBy', $share2->getSharedBy());
737
+        $this->assertSame('shareOwner', $share2->getShareOwner());
738
+        $this->assertSame(1, $share2->getPermissions());
739
+        $this->assertSame('/target', $share2->getTarget());
740
+        $this->assertLessThanOrEqual(new \DateTime(), $share2->getShareTime());
741
+        $this->assertSame($path, $share2->getNode());
742
+
743
+        // Data is kept after creation
744
+        $this->assertSame('Displayed Name', $share->getSharedWithDisplayName());
745
+        $this->assertSame('/path/to/image.svg', $share->getSharedWithAvatar());
746
+        $this->assertSame('Displayed Name', $share2->getSharedWithDisplayName());
747
+        $this->assertSame('/path/to/image.svg', $share2->getSharedWithAvatar());
748
+
749
+        $this->assertSame(
750
+            [
751
+                [
752
+                    'scope' => 'permissions',
753
+                    'key' => 'download',
754
+                    'value' => true
755
+                ]
756
+            ],
757
+            $share->getAttributes()->toArray()
758
+        );
759
+    }
760
+
761
+    public function testCreateGroupShare(): void {
762
+        $share = new Share($this->rootFolder, $this->userManager);
763
+
764
+        $shareOwner = $this->createMock(IUser::class);
765
+        $shareOwner->method('getUID')->willReturn('shareOwner');
766
+
767
+        $path = $this->createMock(Folder::class);
768
+        $path->method('getId')->willReturn(100);
769
+        $path->method('getOwner')->willReturn($shareOwner);
770
+
771
+        $ownerFolder = $this->createMock(Folder::class);
772
+        $userFolder = $this->createMock(Folder::class);
773
+        $this->rootFolder
774
+            ->method('getUserFolder')
775
+            ->willReturnMap([
776
+                ['sharedBy', $userFolder],
777
+                ['shareOwner', $ownerFolder],
778
+            ]);
779
+
780
+        $userFolder->method('getFirstNodeById')
781
+            ->with(100)
782
+            ->willReturn($path);
783
+        $ownerFolder->method('getFirstNodeById')
784
+            ->with(100)
785
+            ->willReturn($path);
786
+
787
+        $share->setShareType(IShare::TYPE_GROUP);
788
+        $share->setSharedWith('sharedWith');
789
+        $share->setSharedBy('sharedBy');
790
+        $share->setShareOwner('shareOwner');
791
+        $share->setNode($path);
792
+        $share->setPermissions(1);
793
+        $share->setSharedWithDisplayName('Displayed Name');
794
+        $share->setSharedWithAvatar('/path/to/image.svg');
795
+        $share->setTarget('/target');
796
+        $attrs = new ShareAttributes();
797
+        $attrs->setAttribute('permissions', 'download', true);
798
+        $share->setAttributes($attrs);
799
+
800
+        $share2 = $this->provider->create($share);
801
+
802
+        $this->assertNotNull($share2->getId());
803
+        $this->assertSame('ocinternal:' . $share2->getId(), $share2->getFullId());
804
+        $this->assertSame(IShare::TYPE_GROUP, $share2->getShareType());
805
+        $this->assertSame('sharedWith', $share2->getSharedWith());
806
+        $this->assertSame('sharedBy', $share2->getSharedBy());
807
+        $this->assertSame('shareOwner', $share2->getShareOwner());
808
+        $this->assertSame(1, $share2->getPermissions());
809
+        $this->assertSame('/target', $share2->getTarget());
810
+        $this->assertLessThanOrEqual(new \DateTime(), $share2->getShareTime());
811
+        $this->assertSame($path, $share2->getNode());
812
+
813
+        // Data is kept after creation
814
+        $this->assertSame('Displayed Name', $share->getSharedWithDisplayName());
815
+        $this->assertSame('/path/to/image.svg', $share->getSharedWithAvatar());
816
+        $this->assertSame('Displayed Name', $share2->getSharedWithDisplayName());
817
+        $this->assertSame('/path/to/image.svg', $share2->getSharedWithAvatar());
818
+
819
+        $this->assertSame(
820
+            [
821
+                [
822
+                    'scope' => 'permissions',
823
+                    'key' => 'download',
824
+                    'value' => true
825
+                ]
826
+            ],
827
+            $share->getAttributes()->toArray()
828
+        );
829
+    }
830
+
831
+    public function testCreateLinkShare(): void {
832
+        $share = new Share($this->rootFolder, $this->userManager);
833
+
834
+        $shareOwner = $this->createMock(IUser::class);
835
+        $shareOwner->method('getUID')->willReturn('shareOwner');
836
+
837
+        $path = $this->createMock(Folder::class);
838
+        $path->method('getId')->willReturn(100);
839
+        $path->method('getOwner')->willReturn($shareOwner);
840
+
841
+        $ownerFolder = $this->createMock(Folder::class);
842
+        $userFolder = $this->createMock(Folder::class);
843
+        $this->rootFolder
844
+            ->method('getUserFolder')
845
+            ->willReturnMap([
846
+                ['sharedBy', $userFolder],
847
+                ['shareOwner', $ownerFolder],
848
+            ]);
849
+
850
+        $userFolder->method('getFirstNodeById')
851
+            ->with(100)
852
+            ->willReturn($path);
853
+        $ownerFolder->method('getFirstNodeById')
854
+            ->with(100)
855
+            ->willReturn($path);
856
+
857
+        $share->setShareType(IShare::TYPE_LINK);
858
+        $share->setSharedBy('sharedBy');
859
+        $share->setShareOwner('shareOwner');
860
+        $share->setNode($path);
861
+        $share->setPermissions(1);
862
+        $share->setPassword('password');
863
+        $share->setSendPasswordByTalk(true);
864
+        $share->setToken('token');
865
+        $expireDate = new \DateTime();
866
+        $share->setExpirationDate($expireDate);
867
+        $share->setTarget('/target');
868
+
869
+        $share2 = $this->provider->create($share);
870
+
871
+        $this->assertNotNull($share2->getId());
872
+        $this->assertSame('ocinternal:' . $share2->getId(), $share2->getFullId());
873
+        $this->assertSame(IShare::TYPE_LINK, $share2->getShareType());
874
+        $this->assertSame('sharedBy', $share2->getSharedBy());
875
+        $this->assertSame('shareOwner', $share2->getShareOwner());
876
+        $this->assertSame(1, $share2->getPermissions());
877
+        $this->assertSame('/target', $share2->getTarget());
878
+        $this->assertLessThanOrEqual(new \DateTime(), $share2->getShareTime());
879
+        $this->assertSame($path, $share2->getNode());
880
+        $this->assertSame('password', $share2->getPassword());
881
+        $this->assertSame(true, $share2->getSendPasswordByTalk());
882
+        $this->assertSame('token', $share2->getToken());
883
+        $this->assertEquals($expireDate->getTimestamp(), $share2->getExpirationDate()->getTimestamp());
884
+    }
885
+
886
+    public function testGetShareByToken(): void {
887
+        $qb = $this->dbConn->getQueryBuilder();
888
+
889
+        $qb->insert('share')
890
+            ->values([
891
+                'share_type' => $qb->expr()->literal(IShare::TYPE_LINK),
892
+                'password' => $qb->expr()->literal('password'),
893
+                'password_by_talk' => $qb->expr()->literal(true),
894
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
895
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
896
+                'item_type' => $qb->expr()->literal('file'),
897
+                'file_source' => $qb->expr()->literal(42),
898
+                'file_target' => $qb->expr()->literal('myTarget'),
899
+                'permissions' => $qb->expr()->literal(13),
900
+                'token' => $qb->expr()->literal('secrettoken'),
901
+                'label' => $qb->expr()->literal('the label'),
902
+            ]);
903
+        $qb->executeStatement();
904
+        $id = $qb->getLastInsertId();
905
+
906
+        $file = $this->createMock(File::class);
907
+
908
+        $this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
909
+        $this->rootFolder->method('getFirstNodeById')->with(42)->willReturn($file);
910
+
911
+        $share = $this->provider->getShareByToken('secrettoken');
912
+        $this->assertEquals($id, $share->getId());
913
+        $this->assertSame('shareOwner', $share->getShareOwner());
914
+        $this->assertSame('sharedBy', $share->getSharedBy());
915
+        $this->assertSame('secrettoken', $share->getToken());
916
+        $this->assertSame('password', $share->getPassword());
917
+        $this->assertSame('the label', $share->getLabel());
918
+        $this->assertSame(true, $share->getSendPasswordByTalk());
919
+        $this->assertSame(null, $share->getSharedWith());
920
+    }
921
+
922
+    /**
923
+     * Assert that if no label is provided the label is correctly,
924
+     * as types on IShare, a string and not null
925
+     */
926
+    public function testGetShareByTokenNullLabel(): void {
927
+        $qb = $this->dbConn->getQueryBuilder();
928
+
929
+        $qb->insert('share')
930
+            ->values([
931
+                'share_type' => $qb->expr()->literal(IShare::TYPE_LINK),
932
+                'password' => $qb->expr()->literal('password'),
933
+                'password_by_talk' => $qb->expr()->literal(true),
934
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
935
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
936
+                'item_type' => $qb->expr()->literal('file'),
937
+                'file_source' => $qb->expr()->literal(42),
938
+                'file_target' => $qb->expr()->literal('myTarget'),
939
+                'permissions' => $qb->expr()->literal(13),
940
+                'token' => $qb->expr()->literal('secrettoken'),
941
+            ]);
942
+        $qb->executeStatement();
943
+        $id = $qb->getLastInsertId();
944
+
945
+        $file = $this->createMock(File::class);
946
+
947
+        $this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
948
+        $this->rootFolder->method('getFirstNodeById')->with(42)->willReturn($file);
949
+
950
+        $share = $this->provider->getShareByToken('secrettoken');
951
+        $this->assertEquals($id, $share->getId());
952
+        $this->assertSame('', $share->getLabel());
953
+    }
954
+
955
+    public function testGetShareByTokenNotFound(): void {
956
+        $this->expectException(ShareNotFound::class);
957
+
958
+        $this->provider->getShareByToken('invalidtoken');
959
+    }
960
+
961
+    private function createTestStorageEntry($storageStringId) {
962
+        $qb = $this->dbConn->getQueryBuilder();
963
+        $qb->insert('storages')
964
+            ->values([
965
+                'id' => $qb->expr()->literal($storageStringId),
966
+            ]);
967
+        $this->assertEquals(1, $qb->executeStatement());
968
+        return $qb->getLastInsertId();
969
+    }
970
+
971
+    private function createTestFileEntry($path, $storage = 1) {
972
+        $qb = $this->dbConn->getQueryBuilder();
973
+        $qb->insert('filecache')
974
+            ->values([
975
+                'storage' => $qb->createNamedParameter($storage, IQueryBuilder::PARAM_INT),
976
+                'path' => $qb->createNamedParameter($path),
977
+                'path_hash' => $qb->createNamedParameter(md5($path)),
978
+                'name' => $qb->createNamedParameter(basename($path)),
979
+            ]);
980
+        $this->assertEquals(1, $qb->executeStatement());
981
+        return $qb->getLastInsertId();
982
+    }
983
+
984
+    public static function storageAndFileNameProvider(): array {
985
+        return [
986
+            // regular file on regular storage
987
+            ['home::shareOwner', 'files/test.txt', 'files/test2.txt'],
988
+            // regular file on external storage
989
+            ['smb::whatever', 'files/test.txt', 'files/test2.txt'],
990
+            // regular file on external storage in trashbin-like folder,
991
+            ['smb::whatever', 'files_trashbin/files/test.txt', 'files_trashbin/files/test2.txt'],
992
+        ];
993
+    }
994
+
995
+    #[\PHPUnit\Framework\Attributes\DataProvider('storageAndFileNameProvider')]
996
+    public function testGetSharedWithUser($storageStringId, $fileName1, $fileName2): void {
997
+        $storageId = $this->createTestStorageEntry($storageStringId);
998
+        $fileId = $this->createTestFileEntry($fileName1, $storageId);
999
+        $fileId2 = $this->createTestFileEntry($fileName2, $storageId);
1000
+        $qb = $this->dbConn->getQueryBuilder();
1001
+        $qb->insert('share')
1002
+            ->values([
1003
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1004
+                'share_with' => $qb->expr()->literal('sharedWith'),
1005
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
1006
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
1007
+                'item_type' => $qb->expr()->literal('file'),
1008
+                'file_source' => $qb->expr()->literal($fileId),
1009
+                'file_target' => $qb->expr()->literal('myTarget'),
1010
+                'permissions' => $qb->expr()->literal(13),
1011
+            ]);
1012
+        $this->assertEquals(1, $qb->executeStatement());
1013
+        $id = $qb->getLastInsertId();
1014
+
1015
+        $qb = $this->dbConn->getQueryBuilder();
1016
+        $qb->insert('share')
1017
+            ->values([
1018
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1019
+                'share_with' => $qb->expr()->literal('sharedWith2'),
1020
+                'uid_owner' => $qb->expr()->literal('shareOwner2'),
1021
+                'uid_initiator' => $qb->expr()->literal('sharedBy2'),
1022
+                'item_type' => $qb->expr()->literal('file2'),
1023
+                'file_source' => $qb->expr()->literal($fileId2),
1024
+                'file_target' => $qb->expr()->literal('myTarget2'),
1025
+                'permissions' => $qb->expr()->literal(14),
1026
+            ]);
1027
+        $this->assertEquals(1, $qb->executeStatement());
1028
+
1029
+        $file = $this->createMock(File::class);
1030
+        $this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
1031
+        $this->rootFolder->method('getFirstNodeById')->with($fileId)->willReturn($file);
1032
+
1033
+        $share = $this->provider->getSharedWith('sharedWith', IShare::TYPE_USER, null, 1, 0);
1034
+        $this->assertCount(1, $share);
1035
+
1036
+        $share = $share[0];
1037
+        $this->assertEquals($id, $share->getId());
1038
+        $this->assertEquals('sharedWith', $share->getSharedWith());
1039
+        $this->assertEquals('shareOwner', $share->getShareOwner());
1040
+        $this->assertEquals('sharedBy', $share->getSharedBy());
1041
+        $this->assertEquals(IShare::TYPE_USER, $share->getShareType());
1042
+    }
1043
+
1044
+    #[\PHPUnit\Framework\Attributes\DataProvider('storageAndFileNameProvider')]
1045
+    public function testGetSharedWithGroup($storageStringId, $fileName1, $fileName2): void {
1046
+        $storageId = $this->createTestStorageEntry($storageStringId);
1047
+        $fileId = $this->createTestFileEntry($fileName1, $storageId);
1048
+        $fileId2 = $this->createTestFileEntry($fileName2, $storageId);
1049
+        $qb = $this->dbConn->getQueryBuilder();
1050
+        $qb->insert('share')
1051
+            ->values([
1052
+                'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
1053
+                'share_with' => $qb->expr()->literal('sharedWith'),
1054
+                'uid_owner' => $qb->expr()->literal('shareOwner2'),
1055
+                'uid_initiator' => $qb->expr()->literal('sharedBy2'),
1056
+                'item_type' => $qb->expr()->literal('file'),
1057
+                'file_source' => $qb->expr()->literal($fileId2),
1058
+                'file_target' => $qb->expr()->literal('myTarget2'),
1059
+                'permissions' => $qb->expr()->literal(14),
1060
+            ]);
1061
+        $this->assertEquals(1, $qb->executeStatement());
1062
+
1063
+        $qb = $this->dbConn->getQueryBuilder();
1064
+        $qb->insert('share')
1065
+            ->values([
1066
+                'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
1067
+                'share_with' => $qb->expr()->literal('sharedWith'),
1068
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
1069
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
1070
+                'item_type' => $qb->expr()->literal('file'),
1071
+                'file_source' => $qb->expr()->literal($fileId),
1072
+                'file_target' => $qb->expr()->literal('myTarget'),
1073
+                'permissions' => $qb->expr()->literal(13),
1074
+            ]);
1075
+        $this->assertEquals(1, $qb->executeStatement());
1076
+        $id = $qb->getLastInsertId();
1077
+
1078
+        $groups = [];
1079
+        foreach (range(0, 100) as $i) {
1080
+            $groups[] = 'group' . $i;
1081
+        }
1082
+
1083
+        $groups[] = 'sharedWith';
1084
+
1085
+        $user = $this->createMock(IUser::class);
1086
+        $user->method('getUID')->willReturn('sharedWith');
1087
+        $owner = $this->createMock(IUser::class);
1088
+        $owner->method('getUID')->willReturn('shareOwner');
1089
+        $initiator = $this->createMock(IUser::class);
1090
+        $initiator->method('getUID')->willReturn('sharedBy');
1091
+
1092
+        $this->userManager->method('get')->willReturnMap([
1093
+            ['sharedWith', $user],
1094
+            ['shareOwner', $owner],
1095
+            ['sharedBy', $initiator],
1096
+        ]);
1097
+        $this->groupManager
1098
+            ->method('getUserGroupIds')
1099
+            ->willReturnCallback(fn (IUser $user) => ($user->getUID() === 'sharedWith' ? $groups : []));
1100
+
1101
+        $file = $this->createMock(File::class);
1102
+        $this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
1103
+        $this->rootFolder->method('getFirstNodeById')->with($fileId)->willReturn($file);
1104
+
1105
+        $share = $this->provider->getSharedWith('sharedWith', IShare::TYPE_GROUP, null, 20, 1);
1106
+        $this->assertCount(1, $share);
1107
+
1108
+        $share = $share[0];
1109
+        $this->assertEquals($id, $share->getId());
1110
+        $this->assertEquals('sharedWith', $share->getSharedWith());
1111
+        $this->assertEquals('shareOwner', $share->getShareOwner());
1112
+        $this->assertEquals('sharedBy', $share->getSharedBy());
1113
+        $this->assertEquals(IShare::TYPE_GROUP, $share->getShareType());
1114
+    }
1115
+
1116
+    #[\PHPUnit\Framework\Attributes\DataProvider('storageAndFileNameProvider')]
1117
+    public function testGetSharedWithGroupUserModified($storageStringId, $fileName1, $fileName2): void {
1118
+        $storageId = $this->createTestStorageEntry($storageStringId);
1119
+        $fileId = $this->createTestFileEntry($fileName1, $storageId);
1120
+        $qb = $this->dbConn->getQueryBuilder();
1121
+        $qb->insert('share')
1122
+            ->values([
1123
+                'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
1124
+                'share_with' => $qb->expr()->literal('sharedWith'),
1125
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
1126
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
1127
+                'item_type' => $qb->expr()->literal('file'),
1128
+                'file_source' => $qb->expr()->literal($fileId),
1129
+                'file_target' => $qb->expr()->literal('myTarget'),
1130
+                'permissions' => $qb->expr()->literal(13),
1131
+            ]);
1132
+        $this->assertEquals(1, $qb->executeStatement());
1133
+        $id = $qb->getLastInsertId();
1134
+
1135
+        /*
1136 1136
 		 * Wrong share. Should not be taken by code.
1137 1137
 		 */
1138
-		$qb = $this->dbConn->getQueryBuilder();
1139
-		$qb->insert('share')
1140
-			->values([
1141
-				'share_type' => $qb->expr()->literal(2),
1142
-				'share_with' => $qb->expr()->literal('user2'),
1143
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
1144
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
1145
-				'item_type' => $qb->expr()->literal('file'),
1146
-				'file_source' => $qb->expr()->literal($fileId),
1147
-				'file_target' => $qb->expr()->literal('wrongTarget'),
1148
-				'permissions' => $qb->expr()->literal(31),
1149
-				'parent' => $qb->expr()->literal($id),
1150
-			]);
1151
-		$this->assertEquals(1, $qb->executeStatement());
1152
-
1153
-		/*
1138
+        $qb = $this->dbConn->getQueryBuilder();
1139
+        $qb->insert('share')
1140
+            ->values([
1141
+                'share_type' => $qb->expr()->literal(2),
1142
+                'share_with' => $qb->expr()->literal('user2'),
1143
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
1144
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
1145
+                'item_type' => $qb->expr()->literal('file'),
1146
+                'file_source' => $qb->expr()->literal($fileId),
1147
+                'file_target' => $qb->expr()->literal('wrongTarget'),
1148
+                'permissions' => $qb->expr()->literal(31),
1149
+                'parent' => $qb->expr()->literal($id),
1150
+            ]);
1151
+        $this->assertEquals(1, $qb->executeStatement());
1152
+
1153
+        /*
1154 1154
 		 * Correct share. should be taken by code path.
1155 1155
 		 */
1156
-		$qb = $this->dbConn->getQueryBuilder();
1157
-		$qb->insert('share')
1158
-			->values([
1159
-				'share_type' => $qb->expr()->literal(2),
1160
-				'share_with' => $qb->expr()->literal('user'),
1161
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
1162
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
1163
-				'item_type' => $qb->expr()->literal('file'),
1164
-				'file_source' => $qb->expr()->literal($fileId),
1165
-				'file_target' => $qb->expr()->literal('userTarget'),
1166
-				'permissions' => $qb->expr()->literal(0),
1167
-				'parent' => $qb->expr()->literal($id),
1168
-			]);
1169
-		$this->assertEquals(1, $qb->executeStatement());
1170
-
1171
-		$groups = ['sharedWith'];
1172
-
1173
-		$user = $this->createMock(IUser::class);
1174
-		$user->method('getUID')->willReturn('user');
1175
-		$owner = $this->createMock(IUser::class);
1176
-		$owner->method('getUID')->willReturn('shareOwner');
1177
-		$initiator = $this->createMock(IUser::class);
1178
-		$initiator->method('getUID')->willReturn('sharedBy');
1179
-
1180
-		$this->userManager->method('get')->willReturnMap([
1181
-			['user', $user],
1182
-			['shareOwner', $owner],
1183
-			['sharedBy', $initiator],
1184
-		]);
1185
-		$this->groupManager
1186
-			->method('getUserGroupIds')
1187
-			->willReturnCallback(fn (IUser $user) => ($user->getUID() === 'user' ? $groups : []));
1188
-
1189
-		$file = $this->createMock(File::class);
1190
-		$this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
1191
-		$this->rootFolder->method('getFirstNodeById')->with($fileId)->willReturn($file);
1192
-
1193
-		$share = $this->provider->getSharedWith('user', IShare::TYPE_GROUP, null, -1, 0);
1194
-		$this->assertCount(1, $share);
1195
-
1196
-		$share = $share[0];
1197
-		$this->assertSame((string)$id, $share->getId());
1198
-		$this->assertSame('sharedWith', $share->getSharedWith());
1199
-		$this->assertSame('shareOwner', $share->getShareOwner());
1200
-		$this->assertSame('sharedBy', $share->getSharedBy());
1201
-		$this->assertSame(IShare::TYPE_GROUP, $share->getShareType());
1202
-		$this->assertSame(0, $share->getPermissions());
1203
-		$this->assertSame('userTarget', $share->getTarget());
1204
-	}
1205
-
1206
-	#[\PHPUnit\Framework\Attributes\DataProvider('storageAndFileNameProvider')]
1207
-	public function testGetSharedWithUserWithNode($storageStringId, $fileName1, $fileName2): void {
1208
-		$storageId = $this->createTestStorageEntry($storageStringId);
1209
-		$fileId = $this->createTestFileEntry($fileName1, $storageId);
1210
-		$fileId2 = $this->createTestFileEntry($fileName2, $storageId);
1211
-		$this->addShareToDB(IShare::TYPE_USER, 'user0', 'user1', 'user1',
1212
-			'file', $fileId, 'myTarget', 31, null, null, null);
1213
-		$id = $this->addShareToDB(IShare::TYPE_USER, 'user0', 'user1', 'user1',
1214
-			'file', $fileId2, 'myTarget', 31, null, null, null);
1215
-
1216
-		$user0 = $this->createMock(IUser::class);
1217
-		$user0->method('getUID')->willReturn('user0');
1218
-		$user0->method('getDisplayName')->willReturn('user0');
1219
-		$user1 = $this->createMock(IUser::class);
1220
-		$user1->method('getUID')->willReturn('user1');
1221
-		$user0->method('getDisplayName')->willReturn('user0');
1222
-
1223
-		$this->userManager->method('get')->willReturnMap([
1224
-			['user0', $user0],
1225
-			['user1', $user1],
1226
-		]);
1227
-
1228
-		$file = $this->createMock(File::class);
1229
-		$file->method('getId')->willReturn($fileId2);
1230
-
1231
-		$this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1232
-		$this->rootFolder->method('getFirstNodeById')->with($fileId2)->willReturn($file);
1233
-
1234
-		$share = $this->provider->getSharedWith('user0', IShare::TYPE_USER, $file, -1, 0);
1235
-		$this->assertCount(1, $share);
1236
-
1237
-		$share = $share[0];
1238
-		$this->assertEquals($id, $share->getId());
1239
-		$this->assertSame('user0', $share->getSharedWith());
1240
-		$this->assertSame('user1', $share->getShareOwner());
1241
-		$this->assertSame('user1', $share->getSharedBy());
1242
-		$this->assertSame($file, $share->getNode());
1243
-		$this->assertEquals(IShare::TYPE_USER, $share->getShareType());
1244
-	}
1245
-
1246
-	#[\PHPUnit\Framework\Attributes\DataProvider('storageAndFileNameProvider')]
1247
-	public function testGetSharedWithGroupWithNode($storageStringId, $fileName1, $fileName2): void {
1248
-		$storageId = $this->createTestStorageEntry($storageStringId);
1249
-		$fileId = $this->createTestFileEntry($fileName1, $storageId);
1250
-		$fileId2 = $this->createTestFileEntry($fileName2, $storageId);
1251
-		$this->addShareToDB(IShare::TYPE_GROUP, 'group0', 'user1', 'user1',
1252
-			'file', $fileId, 'myTarget', 31, null, null, null);
1253
-		$id = $this->addShareToDB(IShare::TYPE_GROUP, 'group0', 'user1', 'user1',
1254
-			'file', $fileId2, 'myTarget', 31, null, null, null);
1255
-
1256
-		$user0 = $this->createMock(IUser::class);
1257
-		$user0->method('getUID')->willReturn('user0');
1258
-		$user1 = $this->createMock(IUser::class);
1259
-		$user1->method('getUID')->willReturn('user1');
1260
-
1261
-		$this->userManager->method('get')->willReturnMap([
1262
-			['user0', $user0],
1263
-			['user1', $user1],
1264
-		]);
1265
-
1266
-		$this->groupManager
1267
-			->method('getUserGroupIds')
1268
-			->willReturnCallback(fn (IUser $user) => ($user->getUID() === 'user0' ? ['group0'] : []));
1269
-
1270
-		$node = $this->createMock(Folder::class);
1271
-		$node->method('getId')->willReturn($fileId2);
1272
-		$this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1273
-		$this->rootFolder->method('getFirstNodeById')->with($fileId2)->willReturn($node);
1274
-
1275
-		$share = $this->provider->getSharedWith('user0', IShare::TYPE_GROUP, $node, -1, 0);
1276
-		$this->assertCount(1, $share);
1277
-
1278
-		$share = $share[0];
1279
-		$this->assertEquals($id, $share->getId());
1280
-		$this->assertSame('group0', $share->getSharedWith());
1281
-		$this->assertSame('user1', $share->getShareOwner());
1282
-		$this->assertSame('user1', $share->getSharedBy());
1283
-		$this->assertSame($node, $share->getNode());
1284
-		$this->assertEquals(IShare::TYPE_GROUP, $share->getShareType());
1285
-	}
1286
-
1287
-	public static function shareTypesProvider(): array {
1288
-		return [
1289
-			[IShare::TYPE_USER, false],
1290
-			[IShare::TYPE_GROUP, false],
1291
-			[IShare::TYPE_USER, true],
1292
-			[IShare::TYPE_GROUP, true],
1293
-		];
1294
-	}
1295
-
1296
-	#[\PHPUnit\Framework\Attributes\DataProvider('shareTypesProvider')]
1297
-	public function testGetSharedWithWithDeletedFile($shareType, $trashed): void {
1298
-		if ($trashed) {
1299
-			// exists in database but is in trash
1300
-			$storageId = $this->createTestStorageEntry('home::shareOwner');
1301
-			$deletedFileId = $this->createTestFileEntry('files_trashbin/files/test.txt.d1465553223', $storageId);
1302
-		} else {
1303
-			// fileid that doesn't exist in the database
1304
-			$deletedFileId = 123;
1305
-		}
1306
-		$qb = $this->dbConn->getQueryBuilder();
1307
-		$qb->insert('share')
1308
-			->values([
1309
-				'share_type' => $qb->expr()->literal($shareType),
1310
-				'share_with' => $qb->expr()->literal('sharedWith'),
1311
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
1312
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
1313
-				'item_type' => $qb->expr()->literal('file'),
1314
-				'file_source' => $qb->expr()->literal($deletedFileId),
1315
-				'file_target' => $qb->expr()->literal('myTarget'),
1316
-				'permissions' => $qb->expr()->literal(13),
1317
-			]);
1318
-		$this->assertEquals(1, $qb->executeStatement());
1319
-
1320
-		$file = $this->createMock(File::class);
1321
-		$this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
1322
-		$this->rootFolder->method('getFirstNodeById')->with($deletedFileId)->willReturn($file);
1323
-
1324
-		$groups = [];
1325
-		foreach (range(0, 100) as $i) {
1326
-			$groups[] = 'group' . $i;
1327
-		}
1328
-
1329
-		$groups[] = 'sharedWith';
1330
-
1331
-		$user = $this->createMock(IUser::class);
1332
-		$user->method('getUID')->willReturn('sharedWith');
1333
-		$owner = $this->createMock(IUser::class);
1334
-		$owner->method('getUID')->willReturn('shareOwner');
1335
-		$initiator = $this->createMock(IUser::class);
1336
-		$initiator->method('getUID')->willReturn('sharedBy');
1337
-
1338
-		$this->userManager->method('get')->willReturnMap([
1339
-			['sharedWith', $user],
1340
-			['shareOwner', $owner],
1341
-			['sharedBy', $initiator],
1342
-		]);
1343
-		$this->groupManager
1344
-			->method('getUserGroupIds')
1345
-			->willReturnCallback(fn (IUser $user) => ($user->getUID() === 'sharedWith' ? $groups : []));
1346
-
1347
-		$share = $this->provider->getSharedWith('sharedWith', $shareType, null, 1, 0);
1348
-		$this->assertCount(0, $share);
1349
-	}
1350
-
1351
-	public function testGetSharesBy(): void {
1352
-		$qb = $this->dbConn->getQueryBuilder();
1353
-		$qb->insert('share')
1354
-			->values([
1355
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1356
-				'share_with' => $qb->expr()->literal('sharedWith'),
1357
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
1358
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
1359
-				'item_type' => $qb->expr()->literal('file'),
1360
-				'file_source' => $qb->expr()->literal(42),
1361
-				'file_target' => $qb->expr()->literal('myTarget'),
1362
-				'permissions' => $qb->expr()->literal(13),
1363
-			]);
1364
-		$this->assertEquals(1, $qb->executeStatement());
1365
-		$id = $qb->getLastInsertId();
1366
-
1367
-		$qb = $this->dbConn->getQueryBuilder();
1368
-		$qb->insert('share')
1369
-			->values([
1370
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1371
-				'share_with' => $qb->expr()->literal('sharedWith'),
1372
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
1373
-				'uid_initiator' => $qb->expr()->literal('sharedBy2'),
1374
-				'item_type' => $qb->expr()->literal('file'),
1375
-				'file_source' => $qb->expr()->literal(42),
1376
-				'file_target' => $qb->expr()->literal('userTarget'),
1377
-				'permissions' => $qb->expr()->literal(0),
1378
-				'parent' => $qb->expr()->literal($id),
1379
-			]);
1380
-		$this->assertEquals(1, $qb->executeStatement());
1381
-
1382
-		$file = $this->createMock(File::class);
1383
-		$this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
1384
-		$this->rootFolder->method('getFirstNodeById')->with(42)->willReturn($file);
1385
-
1386
-		$share = $this->provider->getSharesBy('sharedBy', IShare::TYPE_USER, null, false, 1, 0);
1387
-		$this->assertCount(1, $share);
1388
-
1389
-		/** @var IShare $share */
1390
-		$share = $share[0];
1391
-		$this->assertEquals($id, $share->getId());
1392
-		$this->assertEquals('sharedWith', $share->getSharedWith());
1393
-		$this->assertEquals('shareOwner', $share->getShareOwner());
1394
-		$this->assertEquals('sharedBy', $share->getSharedBy());
1395
-		$this->assertEquals(IShare::TYPE_USER, $share->getShareType());
1396
-		$this->assertEquals(13, $share->getPermissions());
1397
-		$this->assertEquals('myTarget', $share->getTarget());
1398
-	}
1399
-
1400
-	public function testGetSharesNode(): void {
1401
-		$qb = $this->dbConn->getQueryBuilder();
1402
-		$qb->insert('share')
1403
-			->values([
1404
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1405
-				'share_with' => $qb->expr()->literal('sharedWith'),
1406
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
1407
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
1408
-				'item_type' => $qb->expr()->literal('file'),
1409
-				'file_source' => $qb->expr()->literal(42),
1410
-				'file_target' => $qb->expr()->literal('myTarget'),
1411
-				'permissions' => $qb->expr()->literal(13),
1412
-			]);
1413
-		$this->assertEquals(1, $qb->executeStatement());
1414
-		$id = $qb->getLastInsertId();
1415
-
1416
-		$qb = $this->dbConn->getQueryBuilder();
1417
-		$qb->insert('share')
1418
-			->values([
1419
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1420
-				'share_with' => $qb->expr()->literal('sharedWith'),
1421
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
1422
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
1423
-				'item_type' => $qb->expr()->literal('file'),
1424
-				'file_source' => $qb->expr()->literal(43),
1425
-				'file_target' => $qb->expr()->literal('userTarget'),
1426
-				'permissions' => $qb->expr()->literal(0),
1427
-				'parent' => $qb->expr()->literal($id),
1428
-			]);
1429
-		$this->assertEquals(1, $qb->executeStatement());
1430
-
1431
-		$file = $this->createMock(File::class);
1432
-		$file->method('getId')->willReturn(42);
1433
-		$this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
1434
-		$this->rootFolder->method('getFirstNodeById')->with(42)->willReturn($file);
1435
-
1436
-		$share = $this->provider->getSharesBy('sharedBy', IShare::TYPE_USER, $file, false, 1, 0);
1437
-		$this->assertCount(1, $share);
1438
-
1439
-		/** @var IShare $share */
1440
-		$share = $share[0];
1441
-		$this->assertEquals($id, $share->getId());
1442
-		$this->assertEquals('sharedWith', $share->getSharedWith());
1443
-		$this->assertEquals('shareOwner', $share->getShareOwner());
1444
-		$this->assertEquals('sharedBy', $share->getSharedBy());
1445
-		$this->assertEquals(IShare::TYPE_USER, $share->getShareType());
1446
-		$this->assertEquals(13, $share->getPermissions());
1447
-		$this->assertEquals('myTarget', $share->getTarget());
1448
-	}
1449
-
1450
-	public function testGetSharesReshare(): void {
1451
-		$qb = $this->dbConn->getQueryBuilder();
1452
-		$qb->insert('share')
1453
-			->values([
1454
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1455
-				'share_with' => $qb->expr()->literal('sharedWith'),
1456
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
1457
-				'uid_initiator' => $qb->expr()->literal('shareOwner'),
1458
-				'item_type' => $qb->expr()->literal('file'),
1459
-				'file_source' => $qb->expr()->literal(42),
1460
-				'file_target' => $qb->expr()->literal('myTarget'),
1461
-				'permissions' => $qb->expr()->literal(13),
1462
-			]);
1463
-		$this->assertEquals(1, $qb->executeStatement());
1464
-		$id1 = $qb->getLastInsertId();
1465
-
1466
-		$qb = $this->dbConn->getQueryBuilder();
1467
-		$qb->insert('share')
1468
-			->values([
1469
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1470
-				'share_with' => $qb->expr()->literal('sharedWith'),
1471
-				'uid_owner' => $qb->expr()->literal('shareOwner'),
1472
-				'uid_initiator' => $qb->expr()->literal('sharedBy'),
1473
-				'item_type' => $qb->expr()->literal('file'),
1474
-				'file_source' => $qb->expr()->literal(42),
1475
-				'file_target' => $qb->expr()->literal('userTarget'),
1476
-				'permissions' => $qb->expr()->literal(0),
1477
-			]);
1478
-		$this->assertEquals(1, $qb->executeStatement());
1479
-		$id2 = $qb->getLastInsertId();
1480
-
1481
-		$file = $this->createMock(File::class);
1482
-		$file->method('getId')->willReturn(42);
1483
-		$this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
1484
-		$this->rootFolder->method('getFirstNodeById')->with(42)->willReturn($file);
1485
-
1486
-		$shares = $this->provider->getSharesBy('shareOwner', IShare::TYPE_USER, null, true, -1, 0);
1487
-		$this->assertCount(2, $shares);
1488
-
1489
-		/** @var IShare $share */
1490
-		$share = $shares[0];
1491
-		$this->assertEquals($id1, $share->getId());
1492
-		$this->assertSame('sharedWith', $share->getSharedWith());
1493
-		$this->assertSame('shareOwner', $share->getShareOwner());
1494
-		$this->assertSame('shareOwner', $share->getSharedBy());
1495
-		$this->assertEquals(IShare::TYPE_USER, $share->getShareType());
1496
-		$this->assertEquals(13, $share->getPermissions());
1497
-		$this->assertEquals('myTarget', $share->getTarget());
1498
-
1499
-		$share = $shares[1];
1500
-		$this->assertEquals($id2, $share->getId());
1501
-		$this->assertSame('sharedWith', $share->getSharedWith());
1502
-		$this->assertSame('shareOwner', $share->getShareOwner());
1503
-		$this->assertSame('sharedBy', $share->getSharedBy());
1504
-		$this->assertEquals(IShare::TYPE_USER, $share->getShareType());
1505
-		$this->assertEquals(0, $share->getPermissions());
1506
-		$this->assertEquals('userTarget', $share->getTarget());
1507
-	}
1508
-
1509
-	public function testDeleteFromSelfGroupNoCustomShare(): void {
1510
-		$qb = $this->dbConn->getQueryBuilder();
1511
-		$stmt = $qb->insert('share')
1512
-			->values([
1513
-				'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
1514
-				'share_with' => $qb->expr()->literal('group'),
1515
-				'uid_owner' => $qb->expr()->literal('user1'),
1516
-				'uid_initiator' => $qb->expr()->literal('user1'),
1517
-				'item_type' => $qb->expr()->literal('file'),
1518
-				'file_source' => $qb->expr()->literal(1),
1519
-				'file_target' => $qb->expr()->literal('myTarget1'),
1520
-				'permissions' => $qb->expr()->literal(2)
1521
-			])->executeStatement();
1522
-		$this->assertEquals(1, $stmt);
1523
-		$id = $qb->getLastInsertId();
1524
-
1525
-		$user1 = $this->createMock(IUser::class);
1526
-		$user1->method('getUID')->willReturn('user1');
1527
-		$user2 = $this->createMock(IUser::class);
1528
-		$user2->method('getUID')->willReturn('user2');
1529
-		$this->userManager->method('get')->willReturnMap([
1530
-			['user1', $user1],
1531
-			['user2', $user2],
1532
-		]);
1533
-
1534
-		$group = $this->createMock(IGroup::class);
1535
-		$group->method('getGID')->willReturn('group');
1536
-		$group->method('inGroup')->with($user2)->willReturn(true);
1537
-		$group->method('getDisplayName')->willReturn('group-displayname');
1538
-		$this->groupManager->method('get')->with('group')->willReturn($group);
1539
-
1540
-		$file = $this->createMock(File::class);
1541
-		$file->method('getId')->willReturn(1);
1542
-
1543
-		$this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1544
-		$this->rootFolder->method('getFirstNodeById')->with(1)->willReturn($file);
1545
-
1546
-		$share = $this->provider->getShareById($id);
1547
-
1548
-		$this->provider->deleteFromSelf($share, 'user2');
1549
-
1550
-		$qb = $this->dbConn->getQueryBuilder();
1551
-		$stmt = $qb->select('*')
1552
-			->from('share')
1553
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(2)))
1554
-			->executeQuery();
1555
-
1556
-		$shares = $stmt->fetchAllAssociative();
1557
-		$stmt->closeCursor();
1558
-
1559
-		$this->assertCount(1, $shares);
1560
-		$share2 = $shares[0];
1561
-		$this->assertEquals($id, $share2['parent']);
1562
-		$this->assertEquals(0, $share2['permissions']);
1563
-		$this->assertEquals('user2', $share2['share_with']);
1564
-	}
1565
-
1566
-	public function testDeleteFromSelfGroupAlreadyCustomShare(): void {
1567
-		$qb = $this->dbConn->getQueryBuilder();
1568
-		$stmt = $qb->insert('share')
1569
-			->values([
1570
-				'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
1571
-				'share_with' => $qb->expr()->literal('group'),
1572
-				'uid_owner' => $qb->expr()->literal('user1'),
1573
-				'uid_initiator' => $qb->expr()->literal('user1'),
1574
-				'item_type' => $qb->expr()->literal('file'),
1575
-				'file_source' => $qb->expr()->literal(1),
1576
-				'file_target' => $qb->expr()->literal('myTarget1'),
1577
-				'permissions' => $qb->expr()->literal(2)
1578
-			])->executeStatement();
1579
-		$this->assertEquals(1, $stmt);
1580
-		$id = $qb->getLastInsertId();
1581
-
1582
-		$qb = $this->dbConn->getQueryBuilder();
1583
-		$stmt = $qb->insert('share')
1584
-			->values([
1585
-				'share_type' => $qb->expr()->literal(2),
1586
-				'share_with' => $qb->expr()->literal('user2'),
1587
-				'uid_owner' => $qb->expr()->literal('user1'),
1588
-				'uid_initiator' => $qb->expr()->literal('user1'),
1589
-				'item_type' => $qb->expr()->literal('file'),
1590
-				'file_source' => $qb->expr()->literal(1),
1591
-				'file_target' => $qb->expr()->literal('myTarget1'),
1592
-				'permissions' => $qb->expr()->literal(2),
1593
-				'parent' => $qb->expr()->literal($id),
1594
-			])->executeStatement();
1595
-		$this->assertEquals(1, $stmt);
1596
-
1597
-		$user1 = $this->createMock(IUser::class);
1598
-		$user1->method('getUID')->willReturn('user1');
1599
-		$user2 = $this->createMock(IUser::class);
1600
-		$user2->method('getUID')->willReturn('user2');
1601
-		$this->userManager->method('get')->willReturnMap([
1602
-			['user1', $user1],
1603
-			['user2', $user2],
1604
-		]);
1605
-
1606
-		$group = $this->createMock(IGroup::class);
1607
-		$group->method('getGID')->willReturn('group');
1608
-		$group->method('inGroup')->with($user2)->willReturn(true);
1609
-		$group->method('getDisplayName')->willReturn('group-displayname');
1610
-		$this->groupManager->method('get')->with('group')->willReturn($group);
1611
-
1612
-		$file = $this->createMock(File::class);
1613
-		$file->method('getId')->willReturn(1);
1614
-
1615
-		$this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1616
-		$this->rootFolder->method('getFirstNodeById')->with(1)->willReturn($file);
1617
-
1618
-		$share = $this->provider->getShareById($id);
1619
-
1620
-		$this->provider->deleteFromSelf($share, 'user2');
1621
-
1622
-		$qb = $this->dbConn->getQueryBuilder();
1623
-		$stmt = $qb->select('*')
1624
-			->from('share')
1625
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(2)))
1626
-			->executeQuery();
1627
-
1628
-		$shares = $stmt->fetchAllAssociative();
1629
-		$stmt->closeCursor();
1630
-
1631
-		$this->assertCount(1, $shares);
1632
-		$share2 = $shares[0];
1633
-		$this->assertEquals($id, $share2['parent']);
1634
-		$this->assertEquals(0, $share2['permissions']);
1635
-		$this->assertEquals('user2', $share2['share_with']);
1636
-	}
1637
-
1638
-
1639
-	public function testDeleteFromSelfGroupUserNotInGroup(): void {
1640
-		$qb = $this->dbConn->getQueryBuilder();
1641
-		$stmt = $qb->insert('share')
1642
-			->values([
1643
-				'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
1644
-				'share_with' => $qb->expr()->literal('group'),
1645
-				'uid_owner' => $qb->expr()->literal('user1'),
1646
-				'uid_initiator' => $qb->expr()->literal('user1'),
1647
-				'item_type' => $qb->expr()->literal('file'),
1648
-				'file_source' => $qb->expr()->literal(1),
1649
-				'file_target' => $qb->expr()->literal('myTarget1'),
1650
-				'permissions' => $qb->expr()->literal(2)
1651
-			])->executeStatement();
1652
-		$this->assertEquals(1, $stmt);
1653
-		$id = $qb->getLastInsertId();
1654
-
1655
-		$user1 = $this->createMock(IUser::class);
1656
-		$user1->method('getUID')->willReturn('user1');
1657
-		$user2 = $this->createMock(IUser::class);
1658
-		$user2->method('getUID')->willReturn('user2');
1659
-		$this->userManager->method('get')->willReturnMap([
1660
-			['user1', $user1],
1661
-			['user2', $user2],
1662
-		]);
1663
-
1664
-		$group = $this->createMock(IGroup::class);
1665
-		$group->method('getGID')->willReturn('group');
1666
-		$group->method('inGroup')->with($user2)->willReturn(false);
1667
-		$group->method('getDisplayName')->willReturn('group-displayname');
1668
-		$this->groupManager->method('get')->with('group')->willReturn($group);
1669
-
1670
-		$file = $this->createMock(File::class);
1671
-		$file->method('getId')->willReturn(1);
1672
-
1673
-		$this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1674
-		$this->rootFolder->method('getFirstNodeById')->with(1)->willReturn($file);
1675
-
1676
-		$share = $this->provider->getShareById($id);
1677
-
1678
-		$this->provider->deleteFromSelf($share, 'user2');
1679
-	}
1680
-
1681
-
1682
-	public function testDeleteFromSelfGroupDoesNotExist(): void {
1683
-		$this->expectException(ProviderException::class);
1684
-		$this->expectExceptionMessage('Group "group" does not exist');
1685
-
1686
-		$qb = $this->dbConn->getQueryBuilder();
1687
-		$stmt = $qb->insert('share')
1688
-			->values([
1689
-				'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
1690
-				'share_with' => $qb->expr()->literal('group'),
1691
-				'uid_owner' => $qb->expr()->literal('user1'),
1692
-				'uid_initiator' => $qb->expr()->literal('user1'),
1693
-				'item_type' => $qb->expr()->literal('file'),
1694
-				'file_source' => $qb->expr()->literal(1),
1695
-				'file_target' => $qb->expr()->literal('myTarget1'),
1696
-				'permissions' => $qb->expr()->literal(2)
1697
-			])->executeStatement();
1698
-		$this->assertEquals(1, $stmt);
1699
-		$id = $qb->getLastInsertId();
1700
-
1701
-		$user1 = $this->createMock(IUser::class);
1702
-		$user1->method('getUID')->willReturn('user1');
1703
-		$user2 = $this->createMock(IUser::class);
1704
-		$user2->method('getUID')->willReturn('user2');
1705
-		$this->userManager->method('get')->willReturnMap([
1706
-			['user1', $user1],
1707
-			['user2', $user2],
1708
-		]);
1709
-
1710
-		$this->groupManager->method('get')->with('group')->willReturn(null);
1711
-
1712
-		$file = $this->createMock(File::class);
1713
-		$file->method('getId')->willReturn(1);
1714
-
1715
-		$this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1716
-		$this->rootFolder->method('getFirstNodeById')->with(1)->willReturn($file);
1717
-
1718
-		$share = $this->provider->getShareById($id);
1719
-
1720
-		$this->provider->deleteFromSelf($share, 'user2');
1721
-	}
1722
-
1723
-	public function testDeleteFromSelfUser(): void {
1724
-		$qb = $this->dbConn->getQueryBuilder();
1725
-		$stmt = $qb->insert('share')
1726
-			->values([
1727
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1728
-				'share_with' => $qb->expr()->literal('user2'),
1729
-				'uid_owner' => $qb->expr()->literal('user1'),
1730
-				'uid_initiator' => $qb->expr()->literal('user1'),
1731
-				'item_type' => $qb->expr()->literal('file'),
1732
-				'file_source' => $qb->expr()->literal(1),
1733
-				'file_target' => $qb->expr()->literal('myTarget1'),
1734
-				'permissions' => $qb->expr()->literal(2)
1735
-			])->executeStatement();
1736
-		$this->assertEquals(1, $stmt);
1737
-		$id = $qb->getLastInsertId();
1738
-
1739
-		$user1 = $this->createMock(IUser::class);
1740
-		$user1->method('getUID')->willReturn('user1');
1741
-		$user1->method('getDisplayName')->willReturn('user1');
1742
-		$user2 = $this->createMock(IUser::class);
1743
-		$user2->method('getUID')->willReturn('user2');
1744
-		$user2->method('getDisplayName')->willReturn('user2');
1745
-		$this->userManager->method('get')->willReturnMap([
1746
-			['user1', $user1],
1747
-			['user2', $user2],
1748
-		]);
1749
-
1750
-		$file = $this->createMock(File::class);
1751
-		$file->method('getId')->willReturn(1);
1752
-
1753
-		$this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1754
-		$this->rootFolder->method('getFirstNodeById')->with(1)->willReturn($file);
1755
-
1756
-		$share = $this->provider->getShareById($id);
1757
-
1758
-		$this->provider->deleteFromSelf($share, 'user2');
1759
-
1760
-		$qb = $this->dbConn->getQueryBuilder();
1761
-		$stmt = $qb->select('*')
1762
-			->from('share')
1763
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
1764
-			->executeQuery();
1765
-
1766
-		$shares = $stmt->fetchAllAssociative();
1767
-		$stmt->closeCursor();
1768
-
1769
-		$this->assertCount(0, $shares);
1770
-	}
1771
-
1772
-
1773
-	public function testDeleteFromSelfUserNotRecipient(): void {
1774
-		$this->expectException(ProviderException::class);
1775
-		$this->expectExceptionMessage('Recipient does not match');
1776
-
1777
-		$qb = $this->dbConn->getQueryBuilder();
1778
-		$stmt = $qb->insert('share')
1779
-			->values([
1780
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1781
-				'share_with' => $qb->expr()->literal('user2'),
1782
-				'uid_owner' => $qb->expr()->literal('user1'),
1783
-				'uid_initiator' => $qb->expr()->literal('user1'),
1784
-				'item_type' => $qb->expr()->literal('file'),
1785
-				'file_source' => $qb->expr()->literal(1),
1786
-				'file_target' => $qb->expr()->literal('myTarget1'),
1787
-				'permissions' => $qb->expr()->literal(2)
1788
-			])->executeStatement();
1789
-		$this->assertEquals(1, $stmt);
1790
-		$id = $qb->getLastInsertId();
1791
-
1792
-		$user1 = $this->createMock(IUser::class);
1793
-		$user1->method('getUID')->willReturn('user1');
1794
-		$user1->method('getDisplayName')->willReturn('user1');
1795
-		$user2 = $this->createMock(IUser::class);
1796
-		$user2->method('getUID')->willReturn('user2');
1797
-		$user2->method('getDisplayName')->willReturn('user2');
1798
-		$user3 = $this->createMock(IUser::class);
1799
-		$this->userManager->method('get')->willReturnMap([
1800
-			['user1', $user1],
1801
-			['user2', $user2],
1802
-		]);
1803
-
1804
-		$file = $this->createMock(File::class);
1805
-		$file->method('getId')->willReturn(1);
1806
-
1807
-		$this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1808
-		$this->rootFolder->method('getFirstNodeById')->with(1)->willReturn($file);
1809
-
1810
-		$share = $this->provider->getShareById($id);
1811
-
1812
-		$this->provider->deleteFromSelf($share, $user3);
1813
-	}
1814
-
1815
-
1816
-	public function testDeleteFromSelfLink(): void {
1817
-		$this->expectException(ProviderException::class);
1818
-		$this->expectExceptionMessage('Invalid shareType');
1819
-
1820
-		$qb = $this->dbConn->getQueryBuilder();
1821
-		$stmt = $qb->insert('share')
1822
-			->values([
1823
-				'share_type' => $qb->expr()->literal(IShare::TYPE_LINK),
1824
-				'uid_owner' => $qb->expr()->literal('user1'),
1825
-				'uid_initiator' => $qb->expr()->literal('user1'),
1826
-				'item_type' => $qb->expr()->literal('file'),
1827
-				'file_source' => $qb->expr()->literal(1),
1828
-				'file_target' => $qb->expr()->literal('myTarget1'),
1829
-				'permissions' => $qb->expr()->literal(2),
1830
-				'token' => $qb->expr()->literal('token'),
1831
-			])->executeStatement();
1832
-		$this->assertEquals(1, $stmt);
1833
-		$id = $qb->getLastInsertId();
1834
-
1835
-		$user1 = $this->createMock(IUser::class);
1836
-		$user1->method('getUID')->willReturn('user1');
1837
-		$this->userManager->method('get')->willReturnMap([
1838
-			['user1', $user1],
1839
-		]);
1840
-
1841
-		$file = $this->createMock(File::class);
1842
-		$file->method('getId')->willReturn(1);
1843
-
1844
-		$this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1845
-		$this->rootFolder->method('getFirstNodeById')->with(1)->willReturn($file);
1846
-
1847
-		$share = $this->provider->getShareById($id);
1848
-
1849
-		$this->provider->deleteFromSelf($share, $user1);
1850
-	}
1851
-
1852
-	public function testUpdateUser(): void {
1853
-		$id = $this->addShareToDB(IShare::TYPE_USER, 'user0', 'user1', 'user2',
1854
-			'file', 42, 'target', 31, null, null);
1855
-
1856
-		$users = [];
1857
-		for ($i = 0; $i < 6; $i++) {
1858
-			$user = $this->createMock(IUser::class);
1859
-			$user->method('getUID')->willReturn('user' . $i);
1860
-			$user->method('getDisplayName')->willReturn('user' . $i);
1861
-			$users['user' . $i] = $user;
1862
-		}
1863
-
1864
-		$this->userManager->method('get')->willReturnCallback(
1865
-			function ($userId) use ($users) {
1866
-				return $users[$userId];
1867
-			}
1868
-		);
1869
-
1870
-		$file1 = $this->createMock(File::class);
1871
-		$file1->method('getId')->willReturn(42);
1872
-		$file2 = $this->createMock(File::class);
1873
-		$file2->method('getId')->willReturn(43);
1874
-
1875
-		$folder1 = $this->createMock(Folder::class);
1876
-		$folder1->method('getFirstNodeById')->with(42)->willReturn($file1);
1877
-		$folder2 = $this->createMock(Folder::class);
1878
-		$folder2->method('getFirstNodeById')->with(43)->willReturn($file2);
1879
-
1880
-		$this->rootFolder->method('getUserFolder')->willReturnMap([
1881
-			['user2', $folder1],
1882
-			['user5', $folder2],
1883
-		]);
1884
-
1885
-		$share = $this->provider->getShareById($id);
1886
-
1887
-		$share->setSharedWith('user3');
1888
-		$share->setSharedBy('user4');
1889
-		$share->setShareOwner('user5');
1890
-		$share->setNode($file2);
1891
-		$share->setPermissions(1);
1892
-
1893
-		$share2 = $this->provider->update($share);
1894
-
1895
-		$this->assertEquals($id, $share2->getId());
1896
-		$this->assertSame('user3', $share2->getSharedWith());
1897
-		$this->assertSame('user4', $share2->getSharedBy());
1898
-		$this->assertSame('user5', $share2->getShareOwner());
1899
-		$this->assertSame(1, $share2->getPermissions());
1900
-
1901
-		$share2 = $this->provider->getShareById($id);
1902
-
1903
-		$this->assertEquals($id, $share2->getId());
1904
-		$this->assertSame('user3', $share2->getSharedWith());
1905
-		$this->assertSame('user4', $share2->getSharedBy());
1906
-		$this->assertSame('user5', $share2->getShareOwner());
1907
-		$this->assertSame(1, $share2->getPermissions());
1908
-	}
1909
-
1910
-	public function testUpdateLink(): void {
1911
-		$id = $this->addShareToDB(IShare::TYPE_LINK, null, 'user1', 'user2',
1912
-			'file', 42, 'target', 31, null, null);
1913
-
1914
-		$users = [];
1915
-		for ($i = 0; $i < 6; $i++) {
1916
-			$user = $this->createMock(IUser::class);
1917
-			$user->method('getUID')->willReturn('user' . $i);
1918
-			$users['user' . $i] = $user;
1919
-		}
1920
-
1921
-		$this->userManager->method('get')->willReturnCallback(
1922
-			function ($userId) use ($users) {
1923
-				return $users[$userId];
1924
-			}
1925
-		);
1926
-
1927
-		$file1 = $this->createMock(File::class);
1928
-		$file1->method('getId')->willReturn(42);
1929
-		$file2 = $this->createMock(File::class);
1930
-		$file2->method('getId')->willReturn(43);
1931
-
1932
-		$folder1 = $this->createMock(Folder::class);
1933
-		$folder1->method('getFirstNodeById')->with(42)->willReturn($file1);
1934
-		$folder2 = $this->createMock(Folder::class);
1935
-		$folder2->method('getFirstNodeById')->with(43)->willReturn($file2);
1936
-
1937
-		$this->rootFolder->method('getUserFolder')->willReturnMap([
1938
-			['user2', $folder1],
1939
-			['user5', $folder2],
1940
-		]);
1941
-
1942
-		$share = $this->provider->getShareById($id);
1943
-
1944
-		$share->setPassword('password');
1945
-		$share->setSendPasswordByTalk(true);
1946
-		$share->setSharedBy('user4');
1947
-		$share->setShareOwner('user5');
1948
-		$share->setNode($file2);
1949
-		$share->setPermissions(1);
1950
-
1951
-		$share2 = $this->provider->update($share);
1952
-
1953
-		$this->assertEquals($id, $share2->getId());
1954
-		$this->assertEquals('password', $share2->getPassword());
1955
-		$this->assertSame(true, $share2->getSendPasswordByTalk());
1956
-		$this->assertSame('user4', $share2->getSharedBy());
1957
-		$this->assertSame('user5', $share2->getShareOwner());
1958
-		$this->assertSame(1, $share2->getPermissions());
1959
-
1960
-		$share2 = $this->provider->getShareById($id);
1961
-
1962
-		$this->assertEquals($id, $share2->getId());
1963
-		$this->assertEquals('password', $share2->getPassword());
1964
-		$this->assertSame(true, $share2->getSendPasswordByTalk());
1965
-		$this->assertSame('user4', $share2->getSharedBy());
1966
-		$this->assertSame('user5', $share2->getShareOwner());
1967
-		$this->assertSame(1, $share2->getPermissions());
1968
-	}
1969
-
1970
-	public function testUpdateLinkRemovePassword(): void {
1971
-		$id = $this->addShareToDB(IShare::TYPE_LINK, 'foo', 'user1', 'user2',
1972
-			'file', 42, 'target', 31, null, null);
1973
-
1974
-		$qb = $this->dbConn->getQueryBuilder();
1975
-		$qb->update('share');
1976
-		$qb->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
1977
-		$qb->set('password', $qb->createNamedParameter('password'));
1978
-		$this->assertEquals(1, $qb->executeStatement());
1979
-
1980
-		$users = [];
1981
-		for ($i = 0; $i < 6; $i++) {
1982
-			$user = $this->createMock(IUser::class);
1983
-			$user->method('getUID')->willReturn('user' . $i);
1984
-			$users['user' . $i] = $user;
1985
-		}
1986
-
1987
-		$this->userManager->method('get')->willReturnCallback(
1988
-			function ($userId) use ($users) {
1989
-				return $users[$userId];
1990
-			}
1991
-		);
1992
-
1993
-		$file1 = $this->createMock(File::class);
1994
-		$file1->method('getId')->willReturn(42);
1995
-		$file2 = $this->createMock(File::class);
1996
-		$file2->method('getId')->willReturn(43);
1997
-
1998
-		$folder1 = $this->createMock(Folder::class);
1999
-		$folder1->method('getFirstNodeById')->with(42)->willReturn($file1);
2000
-		$folder2 = $this->createMock(Folder::class);
2001
-		$folder2->method('getFirstNodeById')->with(43)->willReturn($file2);
2002
-
2003
-		$this->rootFolder->method('getUserFolder')->willReturnMap([
2004
-			['user2', $folder1],
2005
-			['user5', $folder2],
2006
-		]);
2007
-
2008
-		$share = $this->provider->getShareById($id);
2009
-
2010
-		$share->setPassword(null);
2011
-		$share->setSharedBy('user4');
2012
-		$share->setShareOwner('user5');
2013
-		$share->setNode($file2);
2014
-		$share->setPermissions(1);
2015
-
2016
-		$share2 = $this->provider->update($share);
2017
-
2018
-		$this->assertEquals($id, $share2->getId());
2019
-		$this->assertEquals(null, $share2->getPassword());
2020
-		$this->assertSame('user4', $share2->getSharedBy());
2021
-		$this->assertSame('user5', $share2->getShareOwner());
2022
-		$this->assertSame(1, $share2->getPermissions());
2023
-
2024
-		$share2 = $this->provider->getShareById($id);
2025
-
2026
-		$this->assertEquals($id, $share2->getId());
2027
-		$this->assertEquals(null, $share2->getPassword());
2028
-		$this->assertSame('user4', $share2->getSharedBy());
2029
-		$this->assertSame('user5', $share2->getShareOwner());
2030
-		$this->assertSame(1, $share2->getPermissions());
2031
-	}
2032
-
2033
-	public function testUpdateGroupNoSub(): void {
2034
-		$id = $this->addShareToDB(IShare::TYPE_GROUP, 'group0', 'user1', 'user2',
2035
-			'file', 42, 'target', 31, null, null);
2036
-
2037
-		$users = [];
2038
-		for ($i = 0; $i < 6; $i++) {
2039
-			$user = $this->createMock(IUser::class);
2040
-			$user->method('getUID')->willReturn('user' . $i);
2041
-			$users['user' . $i] = $user;
2042
-		}
2043
-
2044
-		$this->userManager->method('get')->willReturnCallback(
2045
-			function ($userId) use ($users) {
2046
-				return $users[$userId];
2047
-			}
2048
-		);
2049
-
2050
-		$groups = [];
2051
-		for ($i = 0; $i < 2; $i++) {
2052
-			$group = $this->createMock(IGroup::class);
2053
-			$group->method('getGID')->willReturn('group' . $i);
2054
-			$group->method('getDisplayName')->willReturn('group-displayname' . $i);
2055
-			$groups['group' . $i] = $group;
2056
-		}
2057
-
2058
-		$this->groupManager->method('get')->willReturnCallback(
2059
-			function ($groupId) use ($groups) {
2060
-				return $groups[$groupId];
2061
-			}
2062
-		);
2063
-
2064
-		$file1 = $this->createMock(File::class);
2065
-		$file1->method('getId')->willReturn(42);
2066
-		$file2 = $this->createMock(File::class);
2067
-		$file2->method('getId')->willReturn(43);
2068
-
2069
-		$folder1 = $this->createMock(Folder::class);
2070
-		$folder1->method('getFirstNodeById')->with(42)->willReturn($file1);
2071
-		$folder2 = $this->createMock(Folder::class);
2072
-		$folder2->method('getFirstNodeById')->with(43)->willReturn($file2);
2073
-
2074
-		$this->rootFolder->method('getUserFolder')->willReturnMap([
2075
-			['user2', $folder1],
2076
-			['user5', $folder2],
2077
-		]);
2078
-
2079
-		$share = $this->provider->getShareById($id);
2080
-
2081
-		$share->setSharedWith('group0');
2082
-		$share->setSharedBy('user4');
2083
-		$share->setShareOwner('user5');
2084
-		$share->setNode($file2);
2085
-		$share->setPermissions(1);
2086
-
2087
-		$share2 = $this->provider->update($share);
2088
-
2089
-		$this->assertEquals($id, $share2->getId());
2090
-		// Group shares do not allow updating the recipient
2091
-		$this->assertSame('group0', $share2->getSharedWith());
2092
-		$this->assertSame('user4', $share2->getSharedBy());
2093
-		$this->assertSame('user5', $share2->getShareOwner());
2094
-		$this->assertSame(1, $share2->getPermissions());
2095
-
2096
-		$share2 = $this->provider->getShareById($id);
2097
-
2098
-		$this->assertEquals($id, $share2->getId());
2099
-		// Group shares do not allow updating the recipient
2100
-		$this->assertSame('group0', $share2->getSharedWith());
2101
-		$this->assertSame('user4', $share2->getSharedBy());
2102
-		$this->assertSame('user5', $share2->getShareOwner());
2103
-		$this->assertSame(1, $share2->getPermissions());
2104
-	}
2105
-
2106
-	public function testUpdateGroupSubShares(): void {
2107
-		$id = $this->addShareToDB(IShare::TYPE_GROUP, 'group0', 'user1', 'user2',
2108
-			'file', 42, 'target', 31, null, null);
2109
-
2110
-		$id2 = $this->addShareToDB(2, 'user0', 'user1', 'user2',
2111
-			'file', 42, 'mytarget', 31, null, null, $id);
2112
-
2113
-		$id3 = $this->addShareToDB(2, 'user3', 'user1', 'user2',
2114
-			'file', 42, 'mytarget2', 0, null, null, $id);
2115
-
2116
-		$users = [];
2117
-		for ($i = 0; $i < 6; $i++) {
2118
-			$user = $this->createMock(IUser::class);
2119
-			$user->method('getUID')->willReturn('user' . $i);
2120
-			$users['user' . $i] = $user;
2121
-		}
2122
-
2123
-		$this->userManager->method('get')->willReturnCallback(
2124
-			function ($userId) use ($users) {
2125
-				return $users[$userId];
2126
-			}
2127
-		);
2128
-
2129
-		$groups = [];
2130
-		for ($i = 0; $i < 2; $i++) {
2131
-			$group = $this->createMock(IGroup::class);
2132
-			$group->method('getGID')->willReturn('group' . $i);
2133
-			$group->method('getDisplayName')->willReturn('group-displayname' . $i);
2134
-			$groups['group' . $i] = $group;
2135
-		}
2136
-
2137
-		$this->groupManager->method('get')->willReturnCallback(
2138
-			function ($groupId) use ($groups) {
2139
-				return $groups[$groupId];
2140
-			}
2141
-		);
2142
-
2143
-		$file1 = $this->createMock(File::class);
2144
-		$file1->method('getId')->willReturn(42);
2145
-		$file2 = $this->createMock(File::class);
2146
-		$file2->method('getId')->willReturn(43);
2147
-
2148
-		$folder1 = $this->createMock(Folder::class);
2149
-		$folder1->method('getFirstNodeById')->with(42)->willReturn($file1);
2150
-		$folder2 = $this->createMock(Folder::class);
2151
-		$folder2->method('getFirstNodeById')->with(43)->willReturn($file2);
2152
-
2153
-		$this->rootFolder->method('getUserFolder')->willReturnMap([
2154
-			['user2', $folder1],
2155
-			['user5', $folder2],
2156
-		]);
2157
-
2158
-		$share = $this->provider->getShareById($id);
2159
-
2160
-		$share->setSharedWith('group0');
2161
-		$share->setSharedBy('user4');
2162
-		$share->setShareOwner('user5');
2163
-		$share->setNode($file2);
2164
-		$share->setPermissions(1);
2165
-
2166
-		$share2 = $this->provider->update($share);
2167
-
2168
-		$this->assertEquals($id, $share2->getId());
2169
-		// Group shares do not allow updating the recipient
2170
-		$this->assertSame('group0', $share2->getSharedWith());
2171
-		$this->assertSame('user4', $share2->getSharedBy());
2172
-		$this->assertSame('user5', $share2->getShareOwner());
2173
-		$this->assertSame(1, $share2->getPermissions());
2174
-
2175
-		$share2 = $this->provider->getShareById($id);
2176
-
2177
-		$this->assertEquals($id, $share2->getId());
2178
-		// Group shares do not allow updating the recipient
2179
-		$this->assertSame('group0', $share2->getSharedWith());
2180
-		$this->assertSame('user4', $share2->getSharedBy());
2181
-		$this->assertSame('user5', $share2->getShareOwner());
2182
-		$this->assertSame(1, $share2->getPermissions());
2183
-
2184
-		$qb = $this->dbConn->getQueryBuilder();
2185
-		$stmt = $qb->select('*')
2186
-			->from('share')
2187
-			->where($qb->expr()->eq('parent', $qb->createNamedParameter($id)))
2188
-			->orderBy('id')
2189
-			->executeQuery();
2190
-
2191
-		$shares = $stmt->fetchAllAssociative();
2192
-
2193
-		$this->assertSame('user0', $shares[0]['share_with']);
2194
-		$this->assertSame('user4', $shares[0]['uid_initiator']);
2195
-		$this->assertSame('user5', $shares[0]['uid_owner']);
2196
-		$this->assertSame(1, (int)$shares[0]['permissions']);
2197
-
2198
-		$this->assertSame('user3', $shares[1]['share_with']);
2199
-		$this->assertSame('user4', $shares[1]['uid_initiator']);
2200
-		$this->assertSame('user5', $shares[1]['uid_owner']);
2201
-		$this->assertSame(0, (int)$shares[1]['permissions']);
2202
-
2203
-
2204
-		$stmt->closeCursor();
2205
-	}
2206
-
2207
-	public function testMoveUserShare(): void {
2208
-		$id = $this->addShareToDB(IShare::TYPE_USER, 'user0', 'user1', 'user1', 'file',
2209
-			42, 'mytaret', 31, null, null);
2210
-
2211
-		$user0 = $this->createMock(IUser::class);
2212
-		$user0->method('getUID')->willReturn('user0');
2213
-		$user0->method('getDisplayName')->willReturn('user0');
2214
-		$user1 = $this->createMock(IUser::class);
2215
-		$user1->method('getUID')->willReturn('user1');
2216
-		$user1->method('getDisplayName')->willReturn('user1');
2217
-
2218
-		$this->userManager->method('get')->willReturnMap([
2219
-			['user0', $user0],
2220
-			['user1', $user1],
2221
-		]);
2222
-
2223
-		$file = $this->createMock(File::class);
2224
-		$file->method('getId')->willReturn(42);
2225
-
2226
-		$this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
2227
-		$this->rootFolder->method('getFirstNodeById')->willReturn($file);
2228
-
2229
-		$share = $this->provider->getShareById($id, null);
2230
-
2231
-		$share->setTarget('/newTarget');
2232
-		$this->provider->move($share, $user0);
2233
-
2234
-		$share = $this->provider->getShareById($id, null);
2235
-		$this->assertSame('/newTarget', $share->getTarget());
2236
-	}
2237
-
2238
-	public function testMoveGroupShare(): void {
2239
-		$id = $this->addShareToDB(IShare::TYPE_GROUP, 'group0', 'user1', 'user1', 'file',
2240
-			42, 'mytaret', 31, null, null);
2241
-
2242
-		$user0 = $this->createMock(IUser::class);
2243
-		$user0->method('getUID')->willReturn('user0');
2244
-		$user1 = $this->createMock(IUser::class);
2245
-		$user1->method('getUID')->willReturn('user1');
2246
-
2247
-		$group0 = $this->createMock(IGroup::class);
2248
-		$group0->method('getGID')->willReturn('group0');
2249
-		$group0->method('inGroup')->with($user0)->willReturn(true);
2250
-		$group0->method('getDisplayName')->willReturn('group0-displayname');
2251
-
2252
-		$this->groupManager->method('get')->with('group0')->willReturn($group0);
2253
-
2254
-		$this->userManager->method('get')->willReturnMap([
2255
-			['user0', $user0],
2256
-			['user1', $user1],
2257
-		]);
2258
-
2259
-		$folder = $this->createMock(Folder::class);
2260
-		$folder->method('getId')->willReturn(42);
2261
-
2262
-		$this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
2263
-		$this->rootFolder->method('getFirstNodeById')->willReturn($folder);
2264
-
2265
-		$share = $this->provider->getShareById($id, 'user0');
2266
-
2267
-		$share->setTarget('/newTarget');
2268
-		$this->provider->move($share, 'user0');
2269
-
2270
-		$share = $this->provider->getShareById($id, 'user0');
2271
-		$this->assertSame('/newTarget', $share->getTarget());
2272
-
2273
-		$share->setTarget('/ultraNewTarget');
2274
-		$this->provider->move($share, 'user0');
2275
-
2276
-		$share = $this->provider->getShareById($id, 'user0');
2277
-		$this->assertSame('/ultraNewTarget', $share->getTarget());
2278
-	}
2279
-
2280
-	public static function dataDeleteUser(): array {
2281
-		return [
2282
-			[IShare::TYPE_USER, 'a', 'b', 'c', 'a', true],
2283
-			[IShare::TYPE_USER, 'a', 'b', 'c', 'b', false],
2284
-			[IShare::TYPE_USER, 'a', 'b', 'c', 'c', true],
2285
-			[IShare::TYPE_USER, 'a', 'b', 'c', 'd', false],
2286
-			[IShare::TYPE_GROUP, 'a', 'b', 'c', 'a', true],
2287
-			[IShare::TYPE_GROUP, 'a', 'b', 'c', 'b', false],
2288
-			// The group c is still valid but user c is deleted so group share stays
2289
-			[IShare::TYPE_GROUP, 'a', 'b', 'c', 'c', false],
2290
-			[IShare::TYPE_GROUP, 'a', 'b', 'c', 'd', false],
2291
-			[IShare::TYPE_LINK, 'a', 'b', 'c', 'a', true],
2292
-			// To avoid invisible link shares delete initiated link shares as well (see #22327)
2293
-			[IShare::TYPE_LINK, 'a', 'b', 'c', 'b', true],
2294
-			[IShare::TYPE_LINK, 'a', 'b', 'c', 'c', false],
2295
-			[IShare::TYPE_LINK, 'a', 'b', 'c', 'd', false],
2296
-		];
2297
-	}
2298
-
2299
-	/**
2300
-	 *
2301
-	 * @param int $type The shareType (user/group/link)
2302
-	 * @param string $owner The owner of the share (uid)
2303
-	 * @param string $initiator The initiator of the share (uid)
2304
-	 * @param string $recipient The recipient of the share (uid/gid/pass)
2305
-	 * @param string $deletedUser The user that is deleted
2306
-	 * @param bool $rowDeleted Is the row deleted in this setup
2307
-	 */
2308
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataDeleteUser')]
2309
-	public function testDeleteUser($type, $owner, $initiator, $recipient, $deletedUser, $rowDeleted): void {
2310
-		$qb = $this->dbConn->getQueryBuilder();
2311
-		$qb->insert('share')
2312
-			->setValue('share_type', $qb->createNamedParameter($type))
2313
-			->setValue('uid_owner', $qb->createNamedParameter($owner))
2314
-			->setValue('uid_initiator', $qb->createNamedParameter($initiator))
2315
-			->setValue('share_with', $qb->createNamedParameter($recipient))
2316
-			->setValue('item_type', $qb->createNamedParameter('file'))
2317
-			->setValue('item_source', $qb->createNamedParameter(42))
2318
-			->setValue('file_source', $qb->createNamedParameter(42))
2319
-			->executeStatement();
2320
-
2321
-		$id = $qb->getLastInsertId();
2322
-
2323
-		$this->provider->userDeleted($deletedUser, $type);
2324
-
2325
-		$qb = $this->dbConn->getQueryBuilder();
2326
-		$qb->select('*')
2327
-			->from('share')
2328
-			->where(
2329
-				$qb->expr()->eq('id', $qb->createNamedParameter($id))
2330
-			);
2331
-		$cursor = $qb->executeQuery();
2332
-		$data = $cursor->fetchAllAssociative();
2333
-		$cursor->closeCursor();
2334
-
2335
-		$this->assertCount($rowDeleted ? 0 : 1, $data);
2336
-	}
2337
-
2338
-	public static function dataDeleteUserGroup(): array {
2339
-		return [
2340
-			['a', 'b', 'c', 'a', true, true],
2341
-			['a', 'b', 'c', 'b', false, false],
2342
-			['a', 'b', 'c', 'c', false, true],
2343
-			['a', 'b', 'c', 'd', false, false],
2344
-		];
2345
-	}
2346
-
2347
-	/**
2348
-	 *
2349
-	 * @param string $owner The owner of the share (uid)
2350
-	 * @param string $initiator The initiator of the share (uid)
2351
-	 * @param string $recipient The recipient of the usergroup share (uid)
2352
-	 * @param string $deletedUser The user that is deleted
2353
-	 * @param bool $groupShareDeleted
2354
-	 * @param bool $userGroupShareDeleted
2355
-	 */
2356
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataDeleteUserGroup')]
2357
-	public function testDeleteUserGroup($owner, $initiator, $recipient, $deletedUser, $groupShareDeleted, $userGroupShareDeleted): void {
2358
-		$qb = $this->dbConn->getQueryBuilder();
2359
-		$qb->insert('share')
2360
-			->setValue('share_type', $qb->createNamedParameter(IShare::TYPE_GROUP))
2361
-			->setValue('uid_owner', $qb->createNamedParameter($owner))
2362
-			->setValue('uid_initiator', $qb->createNamedParameter($initiator))
2363
-			->setValue('share_with', $qb->createNamedParameter('group'))
2364
-			->setValue('item_type', $qb->createNamedParameter('file'))
2365
-			->setValue('item_source', $qb->createNamedParameter(42))
2366
-			->setValue('file_source', $qb->createNamedParameter(42))
2367
-			->executeStatement();
2368
-		$groupId = $qb->getLastInsertId();
2369
-
2370
-		$qb = $this->dbConn->getQueryBuilder();
2371
-		$qb->insert('share')
2372
-			->setValue('share_type', $qb->createNamedParameter(2))
2373
-			->setValue('uid_owner', $qb->createNamedParameter($owner))
2374
-			->setValue('uid_initiator', $qb->createNamedParameter($initiator))
2375
-			->setValue('share_with', $qb->createNamedParameter($recipient))
2376
-			->setValue('item_type', $qb->createNamedParameter('file'))
2377
-			->setValue('item_source', $qb->createNamedParameter(42))
2378
-			->setValue('file_source', $qb->createNamedParameter(42))
2379
-			->executeStatement();
2380
-		$userGroupId = $qb->getLastInsertId();
2381
-
2382
-		$this->provider->userDeleted($deletedUser, IShare::TYPE_GROUP);
2383
-
2384
-		$qb = $this->dbConn->getQueryBuilder();
2385
-		$qb->select('*')
2386
-			->from('share')
2387
-			->where(
2388
-				$qb->expr()->eq('id', $qb->createNamedParameter($userGroupId))
2389
-			);
2390
-		$cursor = $qb->executeQuery();
2391
-		$data = $cursor->fetchAllAssociative();
2392
-		$cursor->closeCursor();
2393
-		$this->assertCount($userGroupShareDeleted ? 0 : 1, $data);
2394
-
2395
-		$qb = $this->dbConn->getQueryBuilder();
2396
-		$qb->select('*')
2397
-			->from('share')
2398
-			->where(
2399
-				$qb->expr()->eq('id', $qb->createNamedParameter($groupId))
2400
-			);
2401
-		$cursor = $qb->executeQuery();
2402
-		$data = $cursor->fetchAllAssociative();
2403
-		$cursor->closeCursor();
2404
-		$this->assertCount($groupShareDeleted ? 0 : 1, $data);
2405
-	}
2406
-
2407
-	public static function dataGroupDeleted(): array {
2408
-		return [
2409
-			[
2410
-				[
2411
-					'type' => IShare::TYPE_USER,
2412
-					'recipient' => 'user',
2413
-					'children' => []
2414
-				], 'group', false
2415
-			],
2416
-			[
2417
-				[
2418
-					'type' => IShare::TYPE_USER,
2419
-					'recipient' => 'user',
2420
-					'children' => []
2421
-				], 'user', false
2422
-			],
2423
-			[
2424
-				[
2425
-					'type' => IShare::TYPE_LINK,
2426
-					'recipient' => 'user',
2427
-					'children' => []
2428
-				], 'group', false
2429
-			],
2430
-			[
2431
-				[
2432
-					'type' => IShare::TYPE_GROUP,
2433
-					'recipient' => 'group1',
2434
-					'children' => [
2435
-						'foo',
2436
-						'bar'
2437
-					]
2438
-				], 'group2', false
2439
-			],
2440
-			[
2441
-				[
2442
-					'type' => IShare::TYPE_GROUP,
2443
-					'recipient' => 'group1',
2444
-					'children' => [
2445
-						'foo',
2446
-						'bar'
2447
-					]
2448
-				], 'group1', true
2449
-			],
2450
-		];
2451
-	}
2452
-
2453
-	/**
2454
-	 *
2455
-	 * @param $shares
2456
-	 * @param $groupToDelete
2457
-	 * @param $shouldBeDeleted
2458
-	 */
2459
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataGroupDeleted')]
2460
-	public function testGroupDeleted($shares, $groupToDelete, $shouldBeDeleted): void {
2461
-		$qb = $this->dbConn->getQueryBuilder();
2462
-		$qb->insert('share')
2463
-			->setValue('share_type', $qb->createNamedParameter($shares['type']))
2464
-			->setValue('uid_owner', $qb->createNamedParameter('owner'))
2465
-			->setValue('uid_initiator', $qb->createNamedParameter('initiator'))
2466
-			->setValue('share_with', $qb->createNamedParameter($shares['recipient']))
2467
-			->setValue('item_type', $qb->createNamedParameter('file'))
2468
-			->setValue('item_source', $qb->createNamedParameter(42))
2469
-			->setValue('file_source', $qb->createNamedParameter(42))
2470
-			->executeStatement();
2471
-		$ids = [$qb->getLastInsertId()];
2472
-
2473
-		foreach ($shares['children'] as $child) {
2474
-			$qb = $this->dbConn->getQueryBuilder();
2475
-			$qb->insert('share')
2476
-				->setValue('share_type', $qb->createNamedParameter(2))
2477
-				->setValue('uid_owner', $qb->createNamedParameter('owner'))
2478
-				->setValue('uid_initiator', $qb->createNamedParameter('initiator'))
2479
-				->setValue('share_with', $qb->createNamedParameter($child))
2480
-				->setValue('item_type', $qb->createNamedParameter('file'))
2481
-				->setValue('item_source', $qb->createNamedParameter(42))
2482
-				->setValue('file_source', $qb->createNamedParameter(42))
2483
-				->setValue('parent', $qb->createNamedParameter($ids[0]))
2484
-				->executeStatement();
2485
-			$ids[] = $qb->getLastInsertId();
2486
-		}
2487
-
2488
-		$this->provider->groupDeleted($groupToDelete);
2489
-
2490
-		$qb = $this->dbConn->getQueryBuilder();
2491
-		$cursor = $qb->select('*')
2492
-			->from('share')
2493
-			->where($qb->expr()->in('id', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
2494
-			->executeQuery();
2495
-		$data = $cursor->fetchAllAssociative();
2496
-		$cursor->closeCursor();
2497
-
2498
-		$this->assertCount($shouldBeDeleted ? 0 : count($ids), $data);
2499
-	}
2500
-
2501
-	public static function dataUserDeletedFromGroup(): array {
2502
-		return [
2503
-			['group1', 'user1', true],
2504
-			['group1', 'user2', false],
2505
-			['group2', 'user1', false],
2506
-		];
2507
-	}
2508
-
2509
-	/**
2510
-	 * Given a group share with 'group1'
2511
-	 * And a user specific group share with 'user1'.
2512
-	 * User $user is deleted from group $gid.
2513
-	 *
2514
-	 *
2515
-	 * @param string $group
2516
-	 * @param string $user
2517
-	 * @param bool $toDelete
2518
-	 */
2519
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataUserDeletedFromGroup')]
2520
-	public function testUserDeletedFromGroup($group, $user, $toDelete): void {
2521
-		$qb = $this->dbConn->getQueryBuilder();
2522
-		$qb->insert('share')
2523
-			->setValue('share_type', $qb->createNamedParameter(IShare::TYPE_GROUP))
2524
-			->setValue('uid_owner', $qb->createNamedParameter('owner'))
2525
-			->setValue('uid_initiator', $qb->createNamedParameter('initiator'))
2526
-			->setValue('share_with', $qb->createNamedParameter('group1'))
2527
-			->setValue('item_type', $qb->createNamedParameter('file'))
2528
-			->setValue('item_source', $qb->createNamedParameter(42))
2529
-			->setValue('file_source', $qb->createNamedParameter(42));
2530
-		$qb->executeStatement();
2531
-		$id1 = $qb->getLastInsertId();
2532
-
2533
-		$qb = $this->dbConn->getQueryBuilder();
2534
-		$qb->insert('share')
2535
-			->setValue('share_type', $qb->createNamedParameter(2))
2536
-			->setValue('uid_owner', $qb->createNamedParameter('owner'))
2537
-			->setValue('uid_initiator', $qb->createNamedParameter('initiator'))
2538
-			->setValue('share_with', $qb->createNamedParameter('user1'))
2539
-			->setValue('item_type', $qb->createNamedParameter('file'))
2540
-			->setValue('item_source', $qb->createNamedParameter(42))
2541
-			->setValue('file_source', $qb->createNamedParameter(42))
2542
-			->setValue('parent', $qb->createNamedParameter($id1));
2543
-		$qb->executeStatement();
2544
-		$id2 = $qb->getLastInsertId();
2545
-
2546
-		$this->provider->userDeletedFromGroup($user, $group);
2547
-
2548
-		$qb = $this->dbConn->getQueryBuilder();
2549
-		$qb->select('*')
2550
-			->from('share')
2551
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id2)));
2552
-		$cursor = $qb->executeQuery();
2553
-		$data = $cursor->fetchAllAssociative();
2554
-		$cursor->closeCursor();
2555
-
2556
-		$this->assertCount($toDelete ? 0 : 1, $data);
2557
-	}
2558
-
2559
-	public function testGetSharesInFolder(): void {
2560
-		$userManager = Server::get(IUserManager::class);
2561
-		$groupManager = Server::get(IGroupManager::class);
2562
-		$rootFolder = Server::get(IRootFolder::class);
2563
-
2564
-		$provider = new DefaultShareProvider(
2565
-			$this->dbConn,
2566
-			$userManager,
2567
-			$groupManager,
2568
-			$rootFolder,
2569
-			$this->mailer,
2570
-			$this->defaults,
2571
-			$this->l10nFactory,
2572
-			$this->urlGenerator,
2573
-			$this->timeFactory,
2574
-			$this->logger,
2575
-			$this->shareManager,
2576
-			$this->config,
2577
-		);
2578
-
2579
-		$password = md5(time());
2580
-
2581
-		$u1 = $userManager->createUser('testShare1', $password);
2582
-		$u2 = $userManager->createUser('testShare2', $password);
2583
-		$u3 = $userManager->createUser('testShare3', $password);
2584
-
2585
-		$g1 = $groupManager->createGroup('group1');
2586
-
2587
-		$u1Folder = $rootFolder->getUserFolder($u1->getUID());
2588
-		$folder1 = $u1Folder->newFolder('foo');
2589
-		$file1 = $folder1->newFile('bar');
2590
-		$folder2 = $folder1->newFolder('baz');
2591
-
2592
-		$shareManager = Server::get(IShareManager::class);
2593
-		$share1 = $shareManager->newShare();
2594
-		$share1->setNode($folder1)
2595
-			->setSharedBy($u1->getUID())
2596
-			->setSharedWith($u2->getUID())
2597
-			->setShareOwner($u1->getUID())
2598
-			->setShareType(IShare::TYPE_USER)
2599
-			->setPermissions(Constants::PERMISSION_ALL);
2600
-		$share1 = $this->provider->create($share1);
2601
-
2602
-		$share2 = $shareManager->newShare();
2603
-		$share2->setNode($file1)
2604
-			->setSharedBy($u2->getUID())
2605
-			->setSharedWith($u3->getUID())
2606
-			->setShareOwner($u1->getUID())
2607
-			->setShareType(IShare::TYPE_USER)
2608
-			->setPermissions(Constants::PERMISSION_READ);
2609
-		$share2 = $this->provider->create($share2);
2610
-
2611
-		$share3 = $shareManager->newShare();
2612
-		$share3->setNode($folder2)
2613
-			->setSharedBy($u2->getUID())
2614
-			->setShareOwner($u1->getUID())
2615
-			->setShareType(IShare::TYPE_LINK)
2616
-			->setPermissions(Constants::PERMISSION_READ);
2617
-		$share3 = $this->provider->create($share3);
2618
-
2619
-		$share4 = $shareManager->newShare();
2620
-		$share4->setNode($folder2)
2621
-			->setSharedBy($u1->getUID())
2622
-			->setSharedWith($g1->getGID())
2623
-			->setShareOwner($u1->getUID())
2624
-			->setShareType(IShare::TYPE_GROUP)
2625
-			->setPermissions(Constants::PERMISSION_READ);
2626
-		$share4 = $this->provider->create($share4);
2627
-
2628
-		$result = $provider->getSharesInFolder($u1->getUID(), $folder1, false);
2629
-		$this->assertCount(1, $result);
2630
-		$shares = array_pop($result);
2631
-		$this->assertCount(1, $shares);
2632
-		$this->assertSame($folder2->getId(), $shares[0]->getNodeId());
2633
-
2634
-		$result = $provider->getSharesInFolder($u1->getUID(), $folder1, true);
2635
-		$this->assertCount(2, $result);
2636
-
2637
-		$file_shares = $result[$file1->getId()];
2638
-		$this->assertCount(1, $file_shares);
2639
-		$this->assertSame($file1->getId(), $file_shares[0]->getNodeId());
2640
-		$this->assertSame(IShare::TYPE_USER, $file_shares[0]->getShareType());
2641
-
2642
-		$folder_shares = $result[$folder2->getId()];
2643
-		$this->assertCount(2, $folder_shares);
2644
-		$this->assertSame($folder2->getId(), $folder_shares[0]->getNodeId());
2645
-		$this->assertSame($folder2->getId(), $folder_shares[1]->getNodeId());
2646
-		$this->assertSame(IShare::TYPE_LINK, $folder_shares[0]->getShareType());
2647
-		$this->assertSame(IShare::TYPE_GROUP, $folder_shares[1]->getShareType());
2648
-
2649
-		$provider->delete($share1);
2650
-		$provider->delete($share2);
2651
-		$provider->delete($share3);
2652
-		$provider->delete($share4);
2653
-
2654
-		$u1->delete();
2655
-		$u2->delete();
2656
-		$u3->delete();
2657
-		$g1->delete();
2658
-	}
2659
-
2660
-	public function testGetAccessListNoCurrentAccessRequired(): void {
2661
-		$userManager = Server::get(IUserManager::class);
2662
-		$groupManager = Server::get(IGroupManager::class);
2663
-		$rootFolder = Server::get(IRootFolder::class);
2664
-
2665
-		$provider = new DefaultShareProvider(
2666
-			$this->dbConn,
2667
-			$userManager,
2668
-			$groupManager,
2669
-			$rootFolder,
2670
-			$this->mailer,
2671
-			$this->defaults,
2672
-			$this->l10nFactory,
2673
-			$this->urlGenerator,
2674
-			$this->timeFactory,
2675
-			$this->logger,
2676
-			$this->shareManager,
2677
-			$this->config,
2678
-		);
2679
-
2680
-		$u1 = $userManager->createUser('testShare1', 'test');
2681
-		$u2 = $userManager->createUser('testShare2', 'test');
2682
-		$u3 = $userManager->createUser('testShare3', 'test');
2683
-		$u4 = $userManager->createUser('testShare4', 'test');
2684
-		$u5 = $userManager->createUser('testShare5', 'test');
2685
-
2686
-		$g1 = $groupManager->createGroup('group1');
2687
-		$g1->addUser($u3);
2688
-		$g1->addUser($u4);
2689
-
2690
-		$u1Folder = $rootFolder->getUserFolder($u1->getUID());
2691
-		$folder1 = $u1Folder->newFolder('foo');
2692
-		$folder2 = $folder1->newFolder('baz');
2693
-		$file1 = $folder2->newFile('bar');
2694
-
2695
-		$result = $provider->getAccessList([$folder1, $folder2, $file1], false);
2696
-		$this->assertCount(0, $result['users']);
2697
-		$this->assertFalse($result['public']);
2698
-
2699
-		$shareManager = Server::get(IShareManager::class);
2700
-		$share1 = $shareManager->newShare();
2701
-		$share1->setNode($folder1)
2702
-			->setSharedBy($u1->getUID())
2703
-			->setSharedWith($u2->getUID())
2704
-			->setShareOwner($u1->getUID())
2705
-			->setShareType(IShare::TYPE_USER)
2706
-			->setPermissions(Constants::PERMISSION_ALL);
2707
-		$share1 = $this->provider->create($share1);
2708
-		$share1 = $provider->acceptShare($share1, $u2->getUid());
2709
-
2710
-		$share2 = $shareManager->newShare();
2711
-		$share2->setNode($folder2)
2712
-			->setSharedBy($u2->getUID())
2713
-			->setSharedWith($g1->getGID())
2714
-			->setShareOwner($u1->getUID())
2715
-			->setShareType(IShare::TYPE_GROUP)
2716
-			->setPermissions(Constants::PERMISSION_ALL);
2717
-		$share2 = $this->provider->create($share2);
2718
-
2719
-		$shareManager->deleteFromSelf($share2, $u4->getUID());
2720
-
2721
-		$share2 = $provider->acceptShare($share2, $u3->getUid());
2722
-		$share2 = $provider->acceptShare($share2, $u4->getUid());
2723
-
2724
-		$share3 = $shareManager->newShare();
2725
-		$share3->setNode($file1)
2726
-			->setSharedBy($u3->getUID())
2727
-			->setShareOwner($u1->getUID())
2728
-			->setShareType(IShare::TYPE_LINK)
2729
-			->setPermissions(Constants::PERMISSION_READ);
2730
-		$share3 = $this->provider->create($share3);
2731
-
2732
-		$share4 = $shareManager->newShare();
2733
-		$share4->setNode($file1)
2734
-			->setSharedBy($u3->getUID())
2735
-			->setSharedWith($u5->getUID())
2736
-			->setShareOwner($u1->getUID())
2737
-			->setShareType(IShare::TYPE_USER)
2738
-			->setPermissions(Constants::PERMISSION_READ);
2739
-		$share4 = $this->provider->create($share4);
2740
-		$share4 = $provider->acceptShare($share4, $u5->getUid());
2741
-
2742
-		$result = $provider->getAccessList([$folder1, $folder2, $file1], false);
2743
-
2744
-		$this->assertCount(4, $result['users']);
2745
-		$this->assertContains('testShare2', $result['users']);
2746
-		$this->assertContains('testShare3', $result['users']);
2747
-		$this->assertContains('testShare4', $result['users']);
2748
-		$this->assertContains('testShare5', $result['users']);
2749
-		$this->assertTrue($result['public']);
2750
-
2751
-		$provider->delete($share1);
2752
-		$provider->delete($share2);
2753
-		$provider->delete($share3);
2754
-		$provider->delete($share4);
2755
-
2756
-		$u1->delete();
2757
-		$u2->delete();
2758
-		$u3->delete();
2759
-		$u4->delete();
2760
-		$u5->delete();
2761
-		$g1->delete();
2762
-	}
2763
-
2764
-	public function testGetAccessListCurrentAccessRequired(): void {
2765
-		$userManager = Server::get(IUserManager::class);
2766
-		$groupManager = Server::get(IGroupManager::class);
2767
-		$rootFolder = Server::get(IRootFolder::class);
2768
-
2769
-		$provider = new DefaultShareProvider(
2770
-			$this->dbConn,
2771
-			$userManager,
2772
-			$groupManager,
2773
-			$rootFolder,
2774
-			$this->mailer,
2775
-			$this->defaults,
2776
-			$this->l10nFactory,
2777
-			$this->urlGenerator,
2778
-			$this->timeFactory,
2779
-			$this->logger,
2780
-			$this->shareManager,
2781
-			$this->config,
2782
-		);
2783
-
2784
-		$u1 = $userManager->createUser('testShare1', 'test');
2785
-		$u2 = $userManager->createUser('testShare2', 'test');
2786
-		$u3 = $userManager->createUser('testShare3', 'test');
2787
-		$u4 = $userManager->createUser('testShare4', 'test');
2788
-		$u5 = $userManager->createUser('testShare5', 'test');
2789
-
2790
-		$g1 = $groupManager->createGroup('group1');
2791
-		$g1->addUser($u3);
2792
-		$g1->addUser($u4);
2793
-
2794
-		$u1Folder = $rootFolder->getUserFolder($u1->getUID());
2795
-		$folder1 = $u1Folder->newFolder('foo');
2796
-		$folder2 = $folder1->newFolder('baz');
2797
-		$file1 = $folder2->newFile('bar');
2798
-
2799
-		$result = $provider->getAccessList([$folder1, $folder2, $file1], false);
2800
-		$this->assertCount(0, $result['users']);
2801
-		$this->assertFalse($result['public']);
2802
-
2803
-		$shareManager = Server::get(IShareManager::class);
2804
-		$share1 = $shareManager->newShare();
2805
-		$share1->setNode($folder1)
2806
-			->setSharedBy($u1->getUID())
2807
-			->setSharedWith($u2->getUID())
2808
-			->setShareOwner($u1->getUID())
2809
-			->setShareType(IShare::TYPE_USER)
2810
-			->setPermissions(Constants::PERMISSION_ALL);
2811
-		$share1 = $this->provider->create($share1);
2812
-		$share1 = $provider->acceptShare($share1, $u2->getUid());
2813
-
2814
-		$share2 = $shareManager->newShare();
2815
-		$share2->setNode($folder2)
2816
-			->setSharedBy($u2->getUID())
2817
-			->setSharedWith($g1->getGID())
2818
-			->setShareOwner($u1->getUID())
2819
-			->setShareType(IShare::TYPE_GROUP)
2820
-			->setPermissions(Constants::PERMISSION_ALL);
2821
-		$share2 = $this->provider->create($share2);
2822
-		$share2 = $provider->acceptShare($share2, $u3->getUid());
2823
-		$share2 = $provider->acceptShare($share2, $u4->getUid());
2824
-
2825
-		$shareManager->deleteFromSelf($share2, $u4->getUID());
2826
-
2827
-		$share3 = $shareManager->newShare();
2828
-		$share3->setNode($file1)
2829
-			->setSharedBy($u3->getUID())
2830
-			->setShareOwner($u1->getUID())
2831
-			->setShareType(IShare::TYPE_LINK)
2832
-			->setPermissions(Constants::PERMISSION_READ);
2833
-		$share3 = $this->provider->create($share3);
2834
-
2835
-		$share4 = $shareManager->newShare();
2836
-		$share4->setNode($file1)
2837
-			->setSharedBy($u3->getUID())
2838
-			->setSharedWith($u5->getUID())
2839
-			->setShareOwner($u1->getUID())
2840
-			->setShareType(IShare::TYPE_USER)
2841
-			->setPermissions(Constants::PERMISSION_READ);
2842
-		$share4 = $this->provider->create($share4);
2843
-		$share4 = $provider->acceptShare($share4, $u5->getUid());
2844
-
2845
-		$result = $provider->getAccessList([$folder1, $folder2, $file1], true);
2846
-
2847
-		$this->assertCount(3, $result['users']);
2848
-		$this->assertArrayHasKey('testShare2', $result['users']);
2849
-		$this->assertArrayHasKey('testShare3', $result['users']);
2850
-		$this->assertArrayHasKey('testShare5', $result['users']);
2851
-		$this->assertTrue($result['public']);
2852
-
2853
-		$provider->delete($share1);
2854
-		$provider->delete($share2);
2855
-		$provider->delete($share3);
2856
-		$provider->delete($share4);
2857
-
2858
-		$u1->delete();
2859
-		$u2->delete();
2860
-		$u3->delete();
2861
-		$u4->delete();
2862
-		$u5->delete();
2863
-		$g1->delete();
2864
-	}
2865
-
2866
-	public function testGetAllShares(): void {
2867
-		$qb = $this->dbConn->getQueryBuilder();
2868
-
2869
-		$qb->insert('share')
2870
-			->values([
2871
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
2872
-				'share_with' => $qb->expr()->literal('sharedWith1'),
2873
-				'uid_owner' => $qb->expr()->literal('shareOwner1'),
2874
-				'uid_initiator' => $qb->expr()->literal('sharedBy1'),
2875
-				'item_type' => $qb->expr()->literal('file'),
2876
-				'file_source' => $qb->expr()->literal(42),
2877
-				'file_target' => $qb->expr()->literal('myTarget1'),
2878
-				'permissions' => $qb->expr()->literal(13),
2879
-			]);
2880
-		$qb->executeStatement();
2881
-
2882
-		$id1 = $qb->getLastInsertId();
2883
-
2884
-		$qb->insert('share')
2885
-			->values([
2886
-				'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
2887
-				'share_with' => $qb->expr()->literal('sharedWith2'),
2888
-				'uid_owner' => $qb->expr()->literal('shareOwner2'),
2889
-				'uid_initiator' => $qb->expr()->literal('sharedBy2'),
2890
-				'item_type' => $qb->expr()->literal('file'),
2891
-				'file_source' => $qb->expr()->literal(43),
2892
-				'file_target' => $qb->expr()->literal('myTarget2'),
2893
-				'permissions' => $qb->expr()->literal(14),
2894
-			]);
2895
-		$qb->executeStatement();
2896
-
2897
-		$id2 = $qb->getLastInsertId();
2898
-
2899
-		$qb->insert('share')
2900
-			->values([
2901
-				'share_type' => $qb->expr()->literal(IShare::TYPE_LINK),
2902
-				'token' => $qb->expr()->literal('token3'),
2903
-				'uid_owner' => $qb->expr()->literal('shareOwner3'),
2904
-				'uid_initiator' => $qb->expr()->literal('sharedBy3'),
2905
-				'item_type' => $qb->expr()->literal('file'),
2906
-				'file_source' => $qb->expr()->literal(44),
2907
-				'file_target' => $qb->expr()->literal('myTarget3'),
2908
-				'permissions' => $qb->expr()->literal(15),
2909
-			]);
2910
-		$qb->executeStatement();
2911
-
2912
-		$id3 = $qb->getLastInsertId();
2913
-
2914
-		$qb->insert('share')
2915
-			->values([
2916
-				'share_type' => $qb->expr()->literal(IShare::TYPE_EMAIL),
2917
-				'share_with' => $qb->expr()->literal('shareOwner4'),
2918
-				'token' => $qb->expr()->literal('token4'),
2919
-				'uid_owner' => $qb->expr()->literal('shareOwner4'),
2920
-				'uid_initiator' => $qb->expr()->literal('sharedBy4'),
2921
-				'item_type' => $qb->expr()->literal('file'),
2922
-				'file_source' => $qb->expr()->literal(45),
2923
-				'file_target' => $qb->expr()->literal('myTarget4'),
2924
-				'permissions' => $qb->expr()->literal(16),
2925
-			]);
2926
-		$qb->executeStatement();
2927
-
2928
-		$id4 = $qb->getLastInsertId();
2929
-
2930
-		$qb->insert('share')
2931
-			->values([
2932
-				'share_type' => $qb->expr()->literal(IShare::TYPE_LINK),
2933
-				'token' => $qb->expr()->literal('token5'),
2934
-				'uid_owner' => $qb->expr()->literal('shareOwner5'),
2935
-				'uid_initiator' => $qb->expr()->literal('sharedBy5'),
2936
-				'item_type' => $qb->expr()->literal('file'),
2937
-				'file_source' => $qb->expr()->literal(46),
2938
-				'file_target' => $qb->expr()->literal('myTarget5'),
2939
-				'permissions' => $qb->expr()->literal(17),
2940
-			]);
2941
-		$qb->executeStatement();
2942
-
2943
-		$id5 = $qb->getLastInsertId();
2944
-
2945
-		$ownerPath1 = $this->createMock(File::class);
2946
-		$shareOwner1Folder = $this->createMock(Folder::class);
2947
-		$shareOwner1Folder->method('getFirstNodeById')->willReturn($ownerPath1);
2948
-
2949
-		$ownerPath2 = $this->createMock(File::class);
2950
-		$shareOwner2Folder = $this->createMock(Folder::class);
2951
-		$shareOwner2Folder->method('getFirstNodeById')->willReturn($ownerPath2);
2952
-
2953
-		$ownerPath3 = $this->createMock(File::class);
2954
-		$shareOwner3Folder = $this->createMock(Folder::class);
2955
-		$shareOwner3Folder->method('getFirstNodeById')->willReturn($ownerPath3);
2956
-
2957
-		$ownerPath4 = $this->createMock(File::class);
2958
-		$shareOwner4Folder = $this->createMock(Folder::class);
2959
-		$shareOwner4Folder->method('getFirstNodeById')->willReturn($ownerPath4);
2960
-
2961
-		$ownerPath5 = $this->createMock(File::class);
2962
-		$shareOwner5Folder = $this->createMock(Folder::class);
2963
-		$shareOwner5Folder->method('getFirstNodeById')->willReturn($ownerPath5);
2964
-
2965
-		$this->rootFolder
2966
-			->method('getUserFolder')
2967
-			->willReturnMap(
2968
-				[
2969
-					['shareOwner1', $shareOwner1Folder],
2970
-					['shareOwner2', $shareOwner2Folder],
2971
-					['shareOwner3', $shareOwner3Folder],
2972
-					['shareOwner4', $shareOwner4Folder],
2973
-					['shareOwner5', $shareOwner5Folder],
2974
-				]
2975
-			);
2976
-
2977
-		$shares = iterator_to_array($this->provider->getAllShares());
2978
-		$this->assertEquals(4, count($shares));
2979
-
2980
-		$share = $shares[0];
2981
-
2982
-		// We fetch the node so the root folder is eventually called
2983
-
2984
-		$this->assertEquals($id1, $share->getId());
2985
-		$this->assertEquals(IShare::TYPE_USER, $share->getShareType());
2986
-		$this->assertEquals('sharedWith1', $share->getSharedWith());
2987
-		$this->assertEquals('sharedBy1', $share->getSharedBy());
2988
-		$this->assertEquals('shareOwner1', $share->getShareOwner());
2989
-		$this->assertEquals($ownerPath1, $share->getNode());
2990
-		$this->assertEquals(13, $share->getPermissions());
2991
-		$this->assertEquals(null, $share->getToken());
2992
-		$this->assertEquals('myTarget1', $share->getTarget());
2993
-
2994
-		$share = $shares[1];
2995
-
2996
-		$this->assertEquals($id2, $share->getId());
2997
-		$this->assertEquals(IShare::TYPE_GROUP, $share->getShareType());
2998
-		$this->assertEquals('sharedWith2', $share->getSharedWith());
2999
-		$this->assertEquals('sharedBy2', $share->getSharedBy());
3000
-		$this->assertEquals('shareOwner2', $share->getShareOwner());
3001
-		$this->assertEquals($ownerPath2, $share->getNode());
3002
-		$this->assertEquals(14, $share->getPermissions());
3003
-		$this->assertEquals(null, $share->getToken());
3004
-		$this->assertEquals('myTarget2', $share->getTarget());
3005
-
3006
-		$share = $shares[2];
3007
-
3008
-		$this->assertEquals($id3, $share->getId());
3009
-		$this->assertEquals(IShare::TYPE_LINK, $share->getShareType());
3010
-		$this->assertEquals(null, $share->getSharedWith());
3011
-		$this->assertEquals('sharedBy3', $share->getSharedBy());
3012
-		$this->assertEquals('shareOwner3', $share->getShareOwner());
3013
-		$this->assertEquals($ownerPath3, $share->getNode());
3014
-		$this->assertEquals(15, $share->getPermissions());
3015
-		$this->assertEquals('token3', $share->getToken());
3016
-		$this->assertEquals('myTarget3', $share->getTarget());
3017
-
3018
-		$share = $shares[3];
3019
-
3020
-		$this->assertEquals($id5, $share->getId());
3021
-		$this->assertEquals(IShare::TYPE_LINK, $share->getShareType());
3022
-		$this->assertEquals(null, $share->getSharedWith());
3023
-		$this->assertEquals('sharedBy5', $share->getSharedBy());
3024
-		$this->assertEquals('shareOwner5', $share->getShareOwner());
3025
-		$this->assertEquals($ownerPath5, $share->getNode());
3026
-		$this->assertEquals(17, $share->getPermissions());
3027
-		$this->assertEquals('token5', $share->getToken());
3028
-		$this->assertEquals('myTarget5', $share->getTarget());
3029
-	}
3030
-
3031
-
3032
-	public function testGetSharesByPath(): void {
3033
-		$qb = $this->dbConn->getQueryBuilder();
3034
-
3035
-		$qb->insert('share')
3036
-			->values([
3037
-				'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
3038
-				'uid_owner' => $qb->expr()->literal('user1'),
3039
-				'uid_initiator' => $qb->expr()->literal('user1'),
3040
-				'share_with' => $qb->expr()->literal('user2'),
3041
-				'item_type' => $qb->expr()->literal('file'),
3042
-				'file_source' => $qb->expr()->literal(1),
3043
-			]);
3044
-		$qb->executeStatement();
3045
-
3046
-		$id1 = $qb->getLastInsertId();
3047
-
3048
-		$qb->insert('share')
3049
-			->values([
3050
-				'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
3051
-				'uid_owner' => $qb->expr()->literal('user1'),
3052
-				'uid_initiator' => $qb->expr()->literal('user1'),
3053
-				'share_with' => $qb->expr()->literal('user2'),
3054
-				'item_type' => $qb->expr()->literal('file'),
3055
-				'file_source' => $qb->expr()->literal(1),
3056
-			]);
3057
-		$qb->executeStatement();
3058
-
3059
-		$id2 = $qb->getLastInsertId();
3060
-
3061
-		$qb->insert('share')
3062
-			->values([
3063
-				'share_type' => $qb->expr()->literal(IShare::TYPE_LINK),
3064
-				'uid_owner' => $qb->expr()->literal('user1'),
3065
-				'uid_initiator' => $qb->expr()->literal('user1'),
3066
-				'share_with' => $qb->expr()->literal('user2'),
3067
-				'item_type' => $qb->expr()->literal('file'),
3068
-				'file_source' => $qb->expr()->literal(1),
3069
-			]);
3070
-		$qb->executeStatement();
3071
-
3072
-		$id3 = $qb->getLastInsertId();
3073
-
3074
-		$ownerPath1 = $this->createMock(File::class);
3075
-		$shareOwner1Folder = $this->createMock(Folder::class);
3076
-		$shareOwner1Folder->method('getFirstNodeById')->willReturn($ownerPath1);
3077
-
3078
-		$ownerPath2 = $this->createMock(File::class);
3079
-		$shareOwner2Folder = $this->createMock(Folder::class);
3080
-		$shareOwner2Folder->method('getFirstNodeById')->willReturn($ownerPath2);
3081
-
3082
-		$ownerPath3 = $this->createMock(File::class);
3083
-		$shareOwner3Folder = $this->createMock(Folder::class);
3084
-		$shareOwner3Folder->method('getFirstNodeById')->willReturn($ownerPath3);
3085
-
3086
-		$this->rootFolder
3087
-			->method('getUserFolder')
3088
-			->willReturnMap(
3089
-				[
3090
-					['shareOwner1', $shareOwner1Folder],
3091
-					['shareOwner2', $shareOwner2Folder],
3092
-					['shareOwner3', $shareOwner3Folder],
3093
-				]
3094
-			);
3095
-
3096
-		$node = $this->createMock(Node::class);
3097
-		$node
3098
-			->expects($this->once())
3099
-			->method('getId')
3100
-			->willReturn(1);
3101
-
3102
-		$shares = $this->provider->getSharesByPath($node);
3103
-		$this->assertCount(3, $shares);
3104
-
3105
-		$this->assertEquals($id1, $shares[0]->getId());
3106
-		$this->assertEquals(IShare::TYPE_USER, $shares[0]->getShareType());
3107
-
3108
-		$this->assertEquals($id2, $shares[1]->getId());
3109
-		$this->assertEquals(IShare::TYPE_GROUP, $shares[1]->getShareType());
3110
-
3111
-		$this->assertEquals($id3, $shares[2]->getId());
3112
-		$this->assertEquals(IShare::TYPE_LINK, $shares[2]->getShareType());
3113
-	}
1156
+        $qb = $this->dbConn->getQueryBuilder();
1157
+        $qb->insert('share')
1158
+            ->values([
1159
+                'share_type' => $qb->expr()->literal(2),
1160
+                'share_with' => $qb->expr()->literal('user'),
1161
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
1162
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
1163
+                'item_type' => $qb->expr()->literal('file'),
1164
+                'file_source' => $qb->expr()->literal($fileId),
1165
+                'file_target' => $qb->expr()->literal('userTarget'),
1166
+                'permissions' => $qb->expr()->literal(0),
1167
+                'parent' => $qb->expr()->literal($id),
1168
+            ]);
1169
+        $this->assertEquals(1, $qb->executeStatement());
1170
+
1171
+        $groups = ['sharedWith'];
1172
+
1173
+        $user = $this->createMock(IUser::class);
1174
+        $user->method('getUID')->willReturn('user');
1175
+        $owner = $this->createMock(IUser::class);
1176
+        $owner->method('getUID')->willReturn('shareOwner');
1177
+        $initiator = $this->createMock(IUser::class);
1178
+        $initiator->method('getUID')->willReturn('sharedBy');
1179
+
1180
+        $this->userManager->method('get')->willReturnMap([
1181
+            ['user', $user],
1182
+            ['shareOwner', $owner],
1183
+            ['sharedBy', $initiator],
1184
+        ]);
1185
+        $this->groupManager
1186
+            ->method('getUserGroupIds')
1187
+            ->willReturnCallback(fn (IUser $user) => ($user->getUID() === 'user' ? $groups : []));
1188
+
1189
+        $file = $this->createMock(File::class);
1190
+        $this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
1191
+        $this->rootFolder->method('getFirstNodeById')->with($fileId)->willReturn($file);
1192
+
1193
+        $share = $this->provider->getSharedWith('user', IShare::TYPE_GROUP, null, -1, 0);
1194
+        $this->assertCount(1, $share);
1195
+
1196
+        $share = $share[0];
1197
+        $this->assertSame((string)$id, $share->getId());
1198
+        $this->assertSame('sharedWith', $share->getSharedWith());
1199
+        $this->assertSame('shareOwner', $share->getShareOwner());
1200
+        $this->assertSame('sharedBy', $share->getSharedBy());
1201
+        $this->assertSame(IShare::TYPE_GROUP, $share->getShareType());
1202
+        $this->assertSame(0, $share->getPermissions());
1203
+        $this->assertSame('userTarget', $share->getTarget());
1204
+    }
1205
+
1206
+    #[\PHPUnit\Framework\Attributes\DataProvider('storageAndFileNameProvider')]
1207
+    public function testGetSharedWithUserWithNode($storageStringId, $fileName1, $fileName2): void {
1208
+        $storageId = $this->createTestStorageEntry($storageStringId);
1209
+        $fileId = $this->createTestFileEntry($fileName1, $storageId);
1210
+        $fileId2 = $this->createTestFileEntry($fileName2, $storageId);
1211
+        $this->addShareToDB(IShare::TYPE_USER, 'user0', 'user1', 'user1',
1212
+            'file', $fileId, 'myTarget', 31, null, null, null);
1213
+        $id = $this->addShareToDB(IShare::TYPE_USER, 'user0', 'user1', 'user1',
1214
+            'file', $fileId2, 'myTarget', 31, null, null, null);
1215
+
1216
+        $user0 = $this->createMock(IUser::class);
1217
+        $user0->method('getUID')->willReturn('user0');
1218
+        $user0->method('getDisplayName')->willReturn('user0');
1219
+        $user1 = $this->createMock(IUser::class);
1220
+        $user1->method('getUID')->willReturn('user1');
1221
+        $user0->method('getDisplayName')->willReturn('user0');
1222
+
1223
+        $this->userManager->method('get')->willReturnMap([
1224
+            ['user0', $user0],
1225
+            ['user1', $user1],
1226
+        ]);
1227
+
1228
+        $file = $this->createMock(File::class);
1229
+        $file->method('getId')->willReturn($fileId2);
1230
+
1231
+        $this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1232
+        $this->rootFolder->method('getFirstNodeById')->with($fileId2)->willReturn($file);
1233
+
1234
+        $share = $this->provider->getSharedWith('user0', IShare::TYPE_USER, $file, -1, 0);
1235
+        $this->assertCount(1, $share);
1236
+
1237
+        $share = $share[0];
1238
+        $this->assertEquals($id, $share->getId());
1239
+        $this->assertSame('user0', $share->getSharedWith());
1240
+        $this->assertSame('user1', $share->getShareOwner());
1241
+        $this->assertSame('user1', $share->getSharedBy());
1242
+        $this->assertSame($file, $share->getNode());
1243
+        $this->assertEquals(IShare::TYPE_USER, $share->getShareType());
1244
+    }
1245
+
1246
+    #[\PHPUnit\Framework\Attributes\DataProvider('storageAndFileNameProvider')]
1247
+    public function testGetSharedWithGroupWithNode($storageStringId, $fileName1, $fileName2): void {
1248
+        $storageId = $this->createTestStorageEntry($storageStringId);
1249
+        $fileId = $this->createTestFileEntry($fileName1, $storageId);
1250
+        $fileId2 = $this->createTestFileEntry($fileName2, $storageId);
1251
+        $this->addShareToDB(IShare::TYPE_GROUP, 'group0', 'user1', 'user1',
1252
+            'file', $fileId, 'myTarget', 31, null, null, null);
1253
+        $id = $this->addShareToDB(IShare::TYPE_GROUP, 'group0', 'user1', 'user1',
1254
+            'file', $fileId2, 'myTarget', 31, null, null, null);
1255
+
1256
+        $user0 = $this->createMock(IUser::class);
1257
+        $user0->method('getUID')->willReturn('user0');
1258
+        $user1 = $this->createMock(IUser::class);
1259
+        $user1->method('getUID')->willReturn('user1');
1260
+
1261
+        $this->userManager->method('get')->willReturnMap([
1262
+            ['user0', $user0],
1263
+            ['user1', $user1],
1264
+        ]);
1265
+
1266
+        $this->groupManager
1267
+            ->method('getUserGroupIds')
1268
+            ->willReturnCallback(fn (IUser $user) => ($user->getUID() === 'user0' ? ['group0'] : []));
1269
+
1270
+        $node = $this->createMock(Folder::class);
1271
+        $node->method('getId')->willReturn($fileId2);
1272
+        $this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1273
+        $this->rootFolder->method('getFirstNodeById')->with($fileId2)->willReturn($node);
1274
+
1275
+        $share = $this->provider->getSharedWith('user0', IShare::TYPE_GROUP, $node, -1, 0);
1276
+        $this->assertCount(1, $share);
1277
+
1278
+        $share = $share[0];
1279
+        $this->assertEquals($id, $share->getId());
1280
+        $this->assertSame('group0', $share->getSharedWith());
1281
+        $this->assertSame('user1', $share->getShareOwner());
1282
+        $this->assertSame('user1', $share->getSharedBy());
1283
+        $this->assertSame($node, $share->getNode());
1284
+        $this->assertEquals(IShare::TYPE_GROUP, $share->getShareType());
1285
+    }
1286
+
1287
+    public static function shareTypesProvider(): array {
1288
+        return [
1289
+            [IShare::TYPE_USER, false],
1290
+            [IShare::TYPE_GROUP, false],
1291
+            [IShare::TYPE_USER, true],
1292
+            [IShare::TYPE_GROUP, true],
1293
+        ];
1294
+    }
1295
+
1296
+    #[\PHPUnit\Framework\Attributes\DataProvider('shareTypesProvider')]
1297
+    public function testGetSharedWithWithDeletedFile($shareType, $trashed): void {
1298
+        if ($trashed) {
1299
+            // exists in database but is in trash
1300
+            $storageId = $this->createTestStorageEntry('home::shareOwner');
1301
+            $deletedFileId = $this->createTestFileEntry('files_trashbin/files/test.txt.d1465553223', $storageId);
1302
+        } else {
1303
+            // fileid that doesn't exist in the database
1304
+            $deletedFileId = 123;
1305
+        }
1306
+        $qb = $this->dbConn->getQueryBuilder();
1307
+        $qb->insert('share')
1308
+            ->values([
1309
+                'share_type' => $qb->expr()->literal($shareType),
1310
+                'share_with' => $qb->expr()->literal('sharedWith'),
1311
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
1312
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
1313
+                'item_type' => $qb->expr()->literal('file'),
1314
+                'file_source' => $qb->expr()->literal($deletedFileId),
1315
+                'file_target' => $qb->expr()->literal('myTarget'),
1316
+                'permissions' => $qb->expr()->literal(13),
1317
+            ]);
1318
+        $this->assertEquals(1, $qb->executeStatement());
1319
+
1320
+        $file = $this->createMock(File::class);
1321
+        $this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
1322
+        $this->rootFolder->method('getFirstNodeById')->with($deletedFileId)->willReturn($file);
1323
+
1324
+        $groups = [];
1325
+        foreach (range(0, 100) as $i) {
1326
+            $groups[] = 'group' . $i;
1327
+        }
1328
+
1329
+        $groups[] = 'sharedWith';
1330
+
1331
+        $user = $this->createMock(IUser::class);
1332
+        $user->method('getUID')->willReturn('sharedWith');
1333
+        $owner = $this->createMock(IUser::class);
1334
+        $owner->method('getUID')->willReturn('shareOwner');
1335
+        $initiator = $this->createMock(IUser::class);
1336
+        $initiator->method('getUID')->willReturn('sharedBy');
1337
+
1338
+        $this->userManager->method('get')->willReturnMap([
1339
+            ['sharedWith', $user],
1340
+            ['shareOwner', $owner],
1341
+            ['sharedBy', $initiator],
1342
+        ]);
1343
+        $this->groupManager
1344
+            ->method('getUserGroupIds')
1345
+            ->willReturnCallback(fn (IUser $user) => ($user->getUID() === 'sharedWith' ? $groups : []));
1346
+
1347
+        $share = $this->provider->getSharedWith('sharedWith', $shareType, null, 1, 0);
1348
+        $this->assertCount(0, $share);
1349
+    }
1350
+
1351
+    public function testGetSharesBy(): void {
1352
+        $qb = $this->dbConn->getQueryBuilder();
1353
+        $qb->insert('share')
1354
+            ->values([
1355
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1356
+                'share_with' => $qb->expr()->literal('sharedWith'),
1357
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
1358
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
1359
+                'item_type' => $qb->expr()->literal('file'),
1360
+                'file_source' => $qb->expr()->literal(42),
1361
+                'file_target' => $qb->expr()->literal('myTarget'),
1362
+                'permissions' => $qb->expr()->literal(13),
1363
+            ]);
1364
+        $this->assertEquals(1, $qb->executeStatement());
1365
+        $id = $qb->getLastInsertId();
1366
+
1367
+        $qb = $this->dbConn->getQueryBuilder();
1368
+        $qb->insert('share')
1369
+            ->values([
1370
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1371
+                'share_with' => $qb->expr()->literal('sharedWith'),
1372
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
1373
+                'uid_initiator' => $qb->expr()->literal('sharedBy2'),
1374
+                'item_type' => $qb->expr()->literal('file'),
1375
+                'file_source' => $qb->expr()->literal(42),
1376
+                'file_target' => $qb->expr()->literal('userTarget'),
1377
+                'permissions' => $qb->expr()->literal(0),
1378
+                'parent' => $qb->expr()->literal($id),
1379
+            ]);
1380
+        $this->assertEquals(1, $qb->executeStatement());
1381
+
1382
+        $file = $this->createMock(File::class);
1383
+        $this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
1384
+        $this->rootFolder->method('getFirstNodeById')->with(42)->willReturn($file);
1385
+
1386
+        $share = $this->provider->getSharesBy('sharedBy', IShare::TYPE_USER, null, false, 1, 0);
1387
+        $this->assertCount(1, $share);
1388
+
1389
+        /** @var IShare $share */
1390
+        $share = $share[0];
1391
+        $this->assertEquals($id, $share->getId());
1392
+        $this->assertEquals('sharedWith', $share->getSharedWith());
1393
+        $this->assertEquals('shareOwner', $share->getShareOwner());
1394
+        $this->assertEquals('sharedBy', $share->getSharedBy());
1395
+        $this->assertEquals(IShare::TYPE_USER, $share->getShareType());
1396
+        $this->assertEquals(13, $share->getPermissions());
1397
+        $this->assertEquals('myTarget', $share->getTarget());
1398
+    }
1399
+
1400
+    public function testGetSharesNode(): void {
1401
+        $qb = $this->dbConn->getQueryBuilder();
1402
+        $qb->insert('share')
1403
+            ->values([
1404
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1405
+                'share_with' => $qb->expr()->literal('sharedWith'),
1406
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
1407
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
1408
+                'item_type' => $qb->expr()->literal('file'),
1409
+                'file_source' => $qb->expr()->literal(42),
1410
+                'file_target' => $qb->expr()->literal('myTarget'),
1411
+                'permissions' => $qb->expr()->literal(13),
1412
+            ]);
1413
+        $this->assertEquals(1, $qb->executeStatement());
1414
+        $id = $qb->getLastInsertId();
1415
+
1416
+        $qb = $this->dbConn->getQueryBuilder();
1417
+        $qb->insert('share')
1418
+            ->values([
1419
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1420
+                'share_with' => $qb->expr()->literal('sharedWith'),
1421
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
1422
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
1423
+                'item_type' => $qb->expr()->literal('file'),
1424
+                'file_source' => $qb->expr()->literal(43),
1425
+                'file_target' => $qb->expr()->literal('userTarget'),
1426
+                'permissions' => $qb->expr()->literal(0),
1427
+                'parent' => $qb->expr()->literal($id),
1428
+            ]);
1429
+        $this->assertEquals(1, $qb->executeStatement());
1430
+
1431
+        $file = $this->createMock(File::class);
1432
+        $file->method('getId')->willReturn(42);
1433
+        $this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
1434
+        $this->rootFolder->method('getFirstNodeById')->with(42)->willReturn($file);
1435
+
1436
+        $share = $this->provider->getSharesBy('sharedBy', IShare::TYPE_USER, $file, false, 1, 0);
1437
+        $this->assertCount(1, $share);
1438
+
1439
+        /** @var IShare $share */
1440
+        $share = $share[0];
1441
+        $this->assertEquals($id, $share->getId());
1442
+        $this->assertEquals('sharedWith', $share->getSharedWith());
1443
+        $this->assertEquals('shareOwner', $share->getShareOwner());
1444
+        $this->assertEquals('sharedBy', $share->getSharedBy());
1445
+        $this->assertEquals(IShare::TYPE_USER, $share->getShareType());
1446
+        $this->assertEquals(13, $share->getPermissions());
1447
+        $this->assertEquals('myTarget', $share->getTarget());
1448
+    }
1449
+
1450
+    public function testGetSharesReshare(): void {
1451
+        $qb = $this->dbConn->getQueryBuilder();
1452
+        $qb->insert('share')
1453
+            ->values([
1454
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1455
+                'share_with' => $qb->expr()->literal('sharedWith'),
1456
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
1457
+                'uid_initiator' => $qb->expr()->literal('shareOwner'),
1458
+                'item_type' => $qb->expr()->literal('file'),
1459
+                'file_source' => $qb->expr()->literal(42),
1460
+                'file_target' => $qb->expr()->literal('myTarget'),
1461
+                'permissions' => $qb->expr()->literal(13),
1462
+            ]);
1463
+        $this->assertEquals(1, $qb->executeStatement());
1464
+        $id1 = $qb->getLastInsertId();
1465
+
1466
+        $qb = $this->dbConn->getQueryBuilder();
1467
+        $qb->insert('share')
1468
+            ->values([
1469
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1470
+                'share_with' => $qb->expr()->literal('sharedWith'),
1471
+                'uid_owner' => $qb->expr()->literal('shareOwner'),
1472
+                'uid_initiator' => $qb->expr()->literal('sharedBy'),
1473
+                'item_type' => $qb->expr()->literal('file'),
1474
+                'file_source' => $qb->expr()->literal(42),
1475
+                'file_target' => $qb->expr()->literal('userTarget'),
1476
+                'permissions' => $qb->expr()->literal(0),
1477
+            ]);
1478
+        $this->assertEquals(1, $qb->executeStatement());
1479
+        $id2 = $qb->getLastInsertId();
1480
+
1481
+        $file = $this->createMock(File::class);
1482
+        $file->method('getId')->willReturn(42);
1483
+        $this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
1484
+        $this->rootFolder->method('getFirstNodeById')->with(42)->willReturn($file);
1485
+
1486
+        $shares = $this->provider->getSharesBy('shareOwner', IShare::TYPE_USER, null, true, -1, 0);
1487
+        $this->assertCount(2, $shares);
1488
+
1489
+        /** @var IShare $share */
1490
+        $share = $shares[0];
1491
+        $this->assertEquals($id1, $share->getId());
1492
+        $this->assertSame('sharedWith', $share->getSharedWith());
1493
+        $this->assertSame('shareOwner', $share->getShareOwner());
1494
+        $this->assertSame('shareOwner', $share->getSharedBy());
1495
+        $this->assertEquals(IShare::TYPE_USER, $share->getShareType());
1496
+        $this->assertEquals(13, $share->getPermissions());
1497
+        $this->assertEquals('myTarget', $share->getTarget());
1498
+
1499
+        $share = $shares[1];
1500
+        $this->assertEquals($id2, $share->getId());
1501
+        $this->assertSame('sharedWith', $share->getSharedWith());
1502
+        $this->assertSame('shareOwner', $share->getShareOwner());
1503
+        $this->assertSame('sharedBy', $share->getSharedBy());
1504
+        $this->assertEquals(IShare::TYPE_USER, $share->getShareType());
1505
+        $this->assertEquals(0, $share->getPermissions());
1506
+        $this->assertEquals('userTarget', $share->getTarget());
1507
+    }
1508
+
1509
+    public function testDeleteFromSelfGroupNoCustomShare(): void {
1510
+        $qb = $this->dbConn->getQueryBuilder();
1511
+        $stmt = $qb->insert('share')
1512
+            ->values([
1513
+                'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
1514
+                'share_with' => $qb->expr()->literal('group'),
1515
+                'uid_owner' => $qb->expr()->literal('user1'),
1516
+                'uid_initiator' => $qb->expr()->literal('user1'),
1517
+                'item_type' => $qb->expr()->literal('file'),
1518
+                'file_source' => $qb->expr()->literal(1),
1519
+                'file_target' => $qb->expr()->literal('myTarget1'),
1520
+                'permissions' => $qb->expr()->literal(2)
1521
+            ])->executeStatement();
1522
+        $this->assertEquals(1, $stmt);
1523
+        $id = $qb->getLastInsertId();
1524
+
1525
+        $user1 = $this->createMock(IUser::class);
1526
+        $user1->method('getUID')->willReturn('user1');
1527
+        $user2 = $this->createMock(IUser::class);
1528
+        $user2->method('getUID')->willReturn('user2');
1529
+        $this->userManager->method('get')->willReturnMap([
1530
+            ['user1', $user1],
1531
+            ['user2', $user2],
1532
+        ]);
1533
+
1534
+        $group = $this->createMock(IGroup::class);
1535
+        $group->method('getGID')->willReturn('group');
1536
+        $group->method('inGroup')->with($user2)->willReturn(true);
1537
+        $group->method('getDisplayName')->willReturn('group-displayname');
1538
+        $this->groupManager->method('get')->with('group')->willReturn($group);
1539
+
1540
+        $file = $this->createMock(File::class);
1541
+        $file->method('getId')->willReturn(1);
1542
+
1543
+        $this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1544
+        $this->rootFolder->method('getFirstNodeById')->with(1)->willReturn($file);
1545
+
1546
+        $share = $this->provider->getShareById($id);
1547
+
1548
+        $this->provider->deleteFromSelf($share, 'user2');
1549
+
1550
+        $qb = $this->dbConn->getQueryBuilder();
1551
+        $stmt = $qb->select('*')
1552
+            ->from('share')
1553
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(2)))
1554
+            ->executeQuery();
1555
+
1556
+        $shares = $stmt->fetchAllAssociative();
1557
+        $stmt->closeCursor();
1558
+
1559
+        $this->assertCount(1, $shares);
1560
+        $share2 = $shares[0];
1561
+        $this->assertEquals($id, $share2['parent']);
1562
+        $this->assertEquals(0, $share2['permissions']);
1563
+        $this->assertEquals('user2', $share2['share_with']);
1564
+    }
1565
+
1566
+    public function testDeleteFromSelfGroupAlreadyCustomShare(): void {
1567
+        $qb = $this->dbConn->getQueryBuilder();
1568
+        $stmt = $qb->insert('share')
1569
+            ->values([
1570
+                'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
1571
+                'share_with' => $qb->expr()->literal('group'),
1572
+                'uid_owner' => $qb->expr()->literal('user1'),
1573
+                'uid_initiator' => $qb->expr()->literal('user1'),
1574
+                'item_type' => $qb->expr()->literal('file'),
1575
+                'file_source' => $qb->expr()->literal(1),
1576
+                'file_target' => $qb->expr()->literal('myTarget1'),
1577
+                'permissions' => $qb->expr()->literal(2)
1578
+            ])->executeStatement();
1579
+        $this->assertEquals(1, $stmt);
1580
+        $id = $qb->getLastInsertId();
1581
+
1582
+        $qb = $this->dbConn->getQueryBuilder();
1583
+        $stmt = $qb->insert('share')
1584
+            ->values([
1585
+                'share_type' => $qb->expr()->literal(2),
1586
+                'share_with' => $qb->expr()->literal('user2'),
1587
+                'uid_owner' => $qb->expr()->literal('user1'),
1588
+                'uid_initiator' => $qb->expr()->literal('user1'),
1589
+                'item_type' => $qb->expr()->literal('file'),
1590
+                'file_source' => $qb->expr()->literal(1),
1591
+                'file_target' => $qb->expr()->literal('myTarget1'),
1592
+                'permissions' => $qb->expr()->literal(2),
1593
+                'parent' => $qb->expr()->literal($id),
1594
+            ])->executeStatement();
1595
+        $this->assertEquals(1, $stmt);
1596
+
1597
+        $user1 = $this->createMock(IUser::class);
1598
+        $user1->method('getUID')->willReturn('user1');
1599
+        $user2 = $this->createMock(IUser::class);
1600
+        $user2->method('getUID')->willReturn('user2');
1601
+        $this->userManager->method('get')->willReturnMap([
1602
+            ['user1', $user1],
1603
+            ['user2', $user2],
1604
+        ]);
1605
+
1606
+        $group = $this->createMock(IGroup::class);
1607
+        $group->method('getGID')->willReturn('group');
1608
+        $group->method('inGroup')->with($user2)->willReturn(true);
1609
+        $group->method('getDisplayName')->willReturn('group-displayname');
1610
+        $this->groupManager->method('get')->with('group')->willReturn($group);
1611
+
1612
+        $file = $this->createMock(File::class);
1613
+        $file->method('getId')->willReturn(1);
1614
+
1615
+        $this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1616
+        $this->rootFolder->method('getFirstNodeById')->with(1)->willReturn($file);
1617
+
1618
+        $share = $this->provider->getShareById($id);
1619
+
1620
+        $this->provider->deleteFromSelf($share, 'user2');
1621
+
1622
+        $qb = $this->dbConn->getQueryBuilder();
1623
+        $stmt = $qb->select('*')
1624
+            ->from('share')
1625
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(2)))
1626
+            ->executeQuery();
1627
+
1628
+        $shares = $stmt->fetchAllAssociative();
1629
+        $stmt->closeCursor();
1630
+
1631
+        $this->assertCount(1, $shares);
1632
+        $share2 = $shares[0];
1633
+        $this->assertEquals($id, $share2['parent']);
1634
+        $this->assertEquals(0, $share2['permissions']);
1635
+        $this->assertEquals('user2', $share2['share_with']);
1636
+    }
1637
+
1638
+
1639
+    public function testDeleteFromSelfGroupUserNotInGroup(): void {
1640
+        $qb = $this->dbConn->getQueryBuilder();
1641
+        $stmt = $qb->insert('share')
1642
+            ->values([
1643
+                'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
1644
+                'share_with' => $qb->expr()->literal('group'),
1645
+                'uid_owner' => $qb->expr()->literal('user1'),
1646
+                'uid_initiator' => $qb->expr()->literal('user1'),
1647
+                'item_type' => $qb->expr()->literal('file'),
1648
+                'file_source' => $qb->expr()->literal(1),
1649
+                'file_target' => $qb->expr()->literal('myTarget1'),
1650
+                'permissions' => $qb->expr()->literal(2)
1651
+            ])->executeStatement();
1652
+        $this->assertEquals(1, $stmt);
1653
+        $id = $qb->getLastInsertId();
1654
+
1655
+        $user1 = $this->createMock(IUser::class);
1656
+        $user1->method('getUID')->willReturn('user1');
1657
+        $user2 = $this->createMock(IUser::class);
1658
+        $user2->method('getUID')->willReturn('user2');
1659
+        $this->userManager->method('get')->willReturnMap([
1660
+            ['user1', $user1],
1661
+            ['user2', $user2],
1662
+        ]);
1663
+
1664
+        $group = $this->createMock(IGroup::class);
1665
+        $group->method('getGID')->willReturn('group');
1666
+        $group->method('inGroup')->with($user2)->willReturn(false);
1667
+        $group->method('getDisplayName')->willReturn('group-displayname');
1668
+        $this->groupManager->method('get')->with('group')->willReturn($group);
1669
+
1670
+        $file = $this->createMock(File::class);
1671
+        $file->method('getId')->willReturn(1);
1672
+
1673
+        $this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1674
+        $this->rootFolder->method('getFirstNodeById')->with(1)->willReturn($file);
1675
+
1676
+        $share = $this->provider->getShareById($id);
1677
+
1678
+        $this->provider->deleteFromSelf($share, 'user2');
1679
+    }
1680
+
1681
+
1682
+    public function testDeleteFromSelfGroupDoesNotExist(): void {
1683
+        $this->expectException(ProviderException::class);
1684
+        $this->expectExceptionMessage('Group "group" does not exist');
1685
+
1686
+        $qb = $this->dbConn->getQueryBuilder();
1687
+        $stmt = $qb->insert('share')
1688
+            ->values([
1689
+                'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
1690
+                'share_with' => $qb->expr()->literal('group'),
1691
+                'uid_owner' => $qb->expr()->literal('user1'),
1692
+                'uid_initiator' => $qb->expr()->literal('user1'),
1693
+                'item_type' => $qb->expr()->literal('file'),
1694
+                'file_source' => $qb->expr()->literal(1),
1695
+                'file_target' => $qb->expr()->literal('myTarget1'),
1696
+                'permissions' => $qb->expr()->literal(2)
1697
+            ])->executeStatement();
1698
+        $this->assertEquals(1, $stmt);
1699
+        $id = $qb->getLastInsertId();
1700
+
1701
+        $user1 = $this->createMock(IUser::class);
1702
+        $user1->method('getUID')->willReturn('user1');
1703
+        $user2 = $this->createMock(IUser::class);
1704
+        $user2->method('getUID')->willReturn('user2');
1705
+        $this->userManager->method('get')->willReturnMap([
1706
+            ['user1', $user1],
1707
+            ['user2', $user2],
1708
+        ]);
1709
+
1710
+        $this->groupManager->method('get')->with('group')->willReturn(null);
1711
+
1712
+        $file = $this->createMock(File::class);
1713
+        $file->method('getId')->willReturn(1);
1714
+
1715
+        $this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1716
+        $this->rootFolder->method('getFirstNodeById')->with(1)->willReturn($file);
1717
+
1718
+        $share = $this->provider->getShareById($id);
1719
+
1720
+        $this->provider->deleteFromSelf($share, 'user2');
1721
+    }
1722
+
1723
+    public function testDeleteFromSelfUser(): void {
1724
+        $qb = $this->dbConn->getQueryBuilder();
1725
+        $stmt = $qb->insert('share')
1726
+            ->values([
1727
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1728
+                'share_with' => $qb->expr()->literal('user2'),
1729
+                'uid_owner' => $qb->expr()->literal('user1'),
1730
+                'uid_initiator' => $qb->expr()->literal('user1'),
1731
+                'item_type' => $qb->expr()->literal('file'),
1732
+                'file_source' => $qb->expr()->literal(1),
1733
+                'file_target' => $qb->expr()->literal('myTarget1'),
1734
+                'permissions' => $qb->expr()->literal(2)
1735
+            ])->executeStatement();
1736
+        $this->assertEquals(1, $stmt);
1737
+        $id = $qb->getLastInsertId();
1738
+
1739
+        $user1 = $this->createMock(IUser::class);
1740
+        $user1->method('getUID')->willReturn('user1');
1741
+        $user1->method('getDisplayName')->willReturn('user1');
1742
+        $user2 = $this->createMock(IUser::class);
1743
+        $user2->method('getUID')->willReturn('user2');
1744
+        $user2->method('getDisplayName')->willReturn('user2');
1745
+        $this->userManager->method('get')->willReturnMap([
1746
+            ['user1', $user1],
1747
+            ['user2', $user2],
1748
+        ]);
1749
+
1750
+        $file = $this->createMock(File::class);
1751
+        $file->method('getId')->willReturn(1);
1752
+
1753
+        $this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1754
+        $this->rootFolder->method('getFirstNodeById')->with(1)->willReturn($file);
1755
+
1756
+        $share = $this->provider->getShareById($id);
1757
+
1758
+        $this->provider->deleteFromSelf($share, 'user2');
1759
+
1760
+        $qb = $this->dbConn->getQueryBuilder();
1761
+        $stmt = $qb->select('*')
1762
+            ->from('share')
1763
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
1764
+            ->executeQuery();
1765
+
1766
+        $shares = $stmt->fetchAllAssociative();
1767
+        $stmt->closeCursor();
1768
+
1769
+        $this->assertCount(0, $shares);
1770
+    }
1771
+
1772
+
1773
+    public function testDeleteFromSelfUserNotRecipient(): void {
1774
+        $this->expectException(ProviderException::class);
1775
+        $this->expectExceptionMessage('Recipient does not match');
1776
+
1777
+        $qb = $this->dbConn->getQueryBuilder();
1778
+        $stmt = $qb->insert('share')
1779
+            ->values([
1780
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
1781
+                'share_with' => $qb->expr()->literal('user2'),
1782
+                'uid_owner' => $qb->expr()->literal('user1'),
1783
+                'uid_initiator' => $qb->expr()->literal('user1'),
1784
+                'item_type' => $qb->expr()->literal('file'),
1785
+                'file_source' => $qb->expr()->literal(1),
1786
+                'file_target' => $qb->expr()->literal('myTarget1'),
1787
+                'permissions' => $qb->expr()->literal(2)
1788
+            ])->executeStatement();
1789
+        $this->assertEquals(1, $stmt);
1790
+        $id = $qb->getLastInsertId();
1791
+
1792
+        $user1 = $this->createMock(IUser::class);
1793
+        $user1->method('getUID')->willReturn('user1');
1794
+        $user1->method('getDisplayName')->willReturn('user1');
1795
+        $user2 = $this->createMock(IUser::class);
1796
+        $user2->method('getUID')->willReturn('user2');
1797
+        $user2->method('getDisplayName')->willReturn('user2');
1798
+        $user3 = $this->createMock(IUser::class);
1799
+        $this->userManager->method('get')->willReturnMap([
1800
+            ['user1', $user1],
1801
+            ['user2', $user2],
1802
+        ]);
1803
+
1804
+        $file = $this->createMock(File::class);
1805
+        $file->method('getId')->willReturn(1);
1806
+
1807
+        $this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1808
+        $this->rootFolder->method('getFirstNodeById')->with(1)->willReturn($file);
1809
+
1810
+        $share = $this->provider->getShareById($id);
1811
+
1812
+        $this->provider->deleteFromSelf($share, $user3);
1813
+    }
1814
+
1815
+
1816
+    public function testDeleteFromSelfLink(): void {
1817
+        $this->expectException(ProviderException::class);
1818
+        $this->expectExceptionMessage('Invalid shareType');
1819
+
1820
+        $qb = $this->dbConn->getQueryBuilder();
1821
+        $stmt = $qb->insert('share')
1822
+            ->values([
1823
+                'share_type' => $qb->expr()->literal(IShare::TYPE_LINK),
1824
+                'uid_owner' => $qb->expr()->literal('user1'),
1825
+                'uid_initiator' => $qb->expr()->literal('user1'),
1826
+                'item_type' => $qb->expr()->literal('file'),
1827
+                'file_source' => $qb->expr()->literal(1),
1828
+                'file_target' => $qb->expr()->literal('myTarget1'),
1829
+                'permissions' => $qb->expr()->literal(2),
1830
+                'token' => $qb->expr()->literal('token'),
1831
+            ])->executeStatement();
1832
+        $this->assertEquals(1, $stmt);
1833
+        $id = $qb->getLastInsertId();
1834
+
1835
+        $user1 = $this->createMock(IUser::class);
1836
+        $user1->method('getUID')->willReturn('user1');
1837
+        $this->userManager->method('get')->willReturnMap([
1838
+            ['user1', $user1],
1839
+        ]);
1840
+
1841
+        $file = $this->createMock(File::class);
1842
+        $file->method('getId')->willReturn(1);
1843
+
1844
+        $this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
1845
+        $this->rootFolder->method('getFirstNodeById')->with(1)->willReturn($file);
1846
+
1847
+        $share = $this->provider->getShareById($id);
1848
+
1849
+        $this->provider->deleteFromSelf($share, $user1);
1850
+    }
1851
+
1852
+    public function testUpdateUser(): void {
1853
+        $id = $this->addShareToDB(IShare::TYPE_USER, 'user0', 'user1', 'user2',
1854
+            'file', 42, 'target', 31, null, null);
1855
+
1856
+        $users = [];
1857
+        for ($i = 0; $i < 6; $i++) {
1858
+            $user = $this->createMock(IUser::class);
1859
+            $user->method('getUID')->willReturn('user' . $i);
1860
+            $user->method('getDisplayName')->willReturn('user' . $i);
1861
+            $users['user' . $i] = $user;
1862
+        }
1863
+
1864
+        $this->userManager->method('get')->willReturnCallback(
1865
+            function ($userId) use ($users) {
1866
+                return $users[$userId];
1867
+            }
1868
+        );
1869
+
1870
+        $file1 = $this->createMock(File::class);
1871
+        $file1->method('getId')->willReturn(42);
1872
+        $file2 = $this->createMock(File::class);
1873
+        $file2->method('getId')->willReturn(43);
1874
+
1875
+        $folder1 = $this->createMock(Folder::class);
1876
+        $folder1->method('getFirstNodeById')->with(42)->willReturn($file1);
1877
+        $folder2 = $this->createMock(Folder::class);
1878
+        $folder2->method('getFirstNodeById')->with(43)->willReturn($file2);
1879
+
1880
+        $this->rootFolder->method('getUserFolder')->willReturnMap([
1881
+            ['user2', $folder1],
1882
+            ['user5', $folder2],
1883
+        ]);
1884
+
1885
+        $share = $this->provider->getShareById($id);
1886
+
1887
+        $share->setSharedWith('user3');
1888
+        $share->setSharedBy('user4');
1889
+        $share->setShareOwner('user5');
1890
+        $share->setNode($file2);
1891
+        $share->setPermissions(1);
1892
+
1893
+        $share2 = $this->provider->update($share);
1894
+
1895
+        $this->assertEquals($id, $share2->getId());
1896
+        $this->assertSame('user3', $share2->getSharedWith());
1897
+        $this->assertSame('user4', $share2->getSharedBy());
1898
+        $this->assertSame('user5', $share2->getShareOwner());
1899
+        $this->assertSame(1, $share2->getPermissions());
1900
+
1901
+        $share2 = $this->provider->getShareById($id);
1902
+
1903
+        $this->assertEquals($id, $share2->getId());
1904
+        $this->assertSame('user3', $share2->getSharedWith());
1905
+        $this->assertSame('user4', $share2->getSharedBy());
1906
+        $this->assertSame('user5', $share2->getShareOwner());
1907
+        $this->assertSame(1, $share2->getPermissions());
1908
+    }
1909
+
1910
+    public function testUpdateLink(): void {
1911
+        $id = $this->addShareToDB(IShare::TYPE_LINK, null, 'user1', 'user2',
1912
+            'file', 42, 'target', 31, null, null);
1913
+
1914
+        $users = [];
1915
+        for ($i = 0; $i < 6; $i++) {
1916
+            $user = $this->createMock(IUser::class);
1917
+            $user->method('getUID')->willReturn('user' . $i);
1918
+            $users['user' . $i] = $user;
1919
+        }
1920
+
1921
+        $this->userManager->method('get')->willReturnCallback(
1922
+            function ($userId) use ($users) {
1923
+                return $users[$userId];
1924
+            }
1925
+        );
1926
+
1927
+        $file1 = $this->createMock(File::class);
1928
+        $file1->method('getId')->willReturn(42);
1929
+        $file2 = $this->createMock(File::class);
1930
+        $file2->method('getId')->willReturn(43);
1931
+
1932
+        $folder1 = $this->createMock(Folder::class);
1933
+        $folder1->method('getFirstNodeById')->with(42)->willReturn($file1);
1934
+        $folder2 = $this->createMock(Folder::class);
1935
+        $folder2->method('getFirstNodeById')->with(43)->willReturn($file2);
1936
+
1937
+        $this->rootFolder->method('getUserFolder')->willReturnMap([
1938
+            ['user2', $folder1],
1939
+            ['user5', $folder2],
1940
+        ]);
1941
+
1942
+        $share = $this->provider->getShareById($id);
1943
+
1944
+        $share->setPassword('password');
1945
+        $share->setSendPasswordByTalk(true);
1946
+        $share->setSharedBy('user4');
1947
+        $share->setShareOwner('user5');
1948
+        $share->setNode($file2);
1949
+        $share->setPermissions(1);
1950
+
1951
+        $share2 = $this->provider->update($share);
1952
+
1953
+        $this->assertEquals($id, $share2->getId());
1954
+        $this->assertEquals('password', $share2->getPassword());
1955
+        $this->assertSame(true, $share2->getSendPasswordByTalk());
1956
+        $this->assertSame('user4', $share2->getSharedBy());
1957
+        $this->assertSame('user5', $share2->getShareOwner());
1958
+        $this->assertSame(1, $share2->getPermissions());
1959
+
1960
+        $share2 = $this->provider->getShareById($id);
1961
+
1962
+        $this->assertEquals($id, $share2->getId());
1963
+        $this->assertEquals('password', $share2->getPassword());
1964
+        $this->assertSame(true, $share2->getSendPasswordByTalk());
1965
+        $this->assertSame('user4', $share2->getSharedBy());
1966
+        $this->assertSame('user5', $share2->getShareOwner());
1967
+        $this->assertSame(1, $share2->getPermissions());
1968
+    }
1969
+
1970
+    public function testUpdateLinkRemovePassword(): void {
1971
+        $id = $this->addShareToDB(IShare::TYPE_LINK, 'foo', 'user1', 'user2',
1972
+            'file', 42, 'target', 31, null, null);
1973
+
1974
+        $qb = $this->dbConn->getQueryBuilder();
1975
+        $qb->update('share');
1976
+        $qb->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
1977
+        $qb->set('password', $qb->createNamedParameter('password'));
1978
+        $this->assertEquals(1, $qb->executeStatement());
1979
+
1980
+        $users = [];
1981
+        for ($i = 0; $i < 6; $i++) {
1982
+            $user = $this->createMock(IUser::class);
1983
+            $user->method('getUID')->willReturn('user' . $i);
1984
+            $users['user' . $i] = $user;
1985
+        }
1986
+
1987
+        $this->userManager->method('get')->willReturnCallback(
1988
+            function ($userId) use ($users) {
1989
+                return $users[$userId];
1990
+            }
1991
+        );
1992
+
1993
+        $file1 = $this->createMock(File::class);
1994
+        $file1->method('getId')->willReturn(42);
1995
+        $file2 = $this->createMock(File::class);
1996
+        $file2->method('getId')->willReturn(43);
1997
+
1998
+        $folder1 = $this->createMock(Folder::class);
1999
+        $folder1->method('getFirstNodeById')->with(42)->willReturn($file1);
2000
+        $folder2 = $this->createMock(Folder::class);
2001
+        $folder2->method('getFirstNodeById')->with(43)->willReturn($file2);
2002
+
2003
+        $this->rootFolder->method('getUserFolder')->willReturnMap([
2004
+            ['user2', $folder1],
2005
+            ['user5', $folder2],
2006
+        ]);
2007
+
2008
+        $share = $this->provider->getShareById($id);
2009
+
2010
+        $share->setPassword(null);
2011
+        $share->setSharedBy('user4');
2012
+        $share->setShareOwner('user5');
2013
+        $share->setNode($file2);
2014
+        $share->setPermissions(1);
2015
+
2016
+        $share2 = $this->provider->update($share);
2017
+
2018
+        $this->assertEquals($id, $share2->getId());
2019
+        $this->assertEquals(null, $share2->getPassword());
2020
+        $this->assertSame('user4', $share2->getSharedBy());
2021
+        $this->assertSame('user5', $share2->getShareOwner());
2022
+        $this->assertSame(1, $share2->getPermissions());
2023
+
2024
+        $share2 = $this->provider->getShareById($id);
2025
+
2026
+        $this->assertEquals($id, $share2->getId());
2027
+        $this->assertEquals(null, $share2->getPassword());
2028
+        $this->assertSame('user4', $share2->getSharedBy());
2029
+        $this->assertSame('user5', $share2->getShareOwner());
2030
+        $this->assertSame(1, $share2->getPermissions());
2031
+    }
2032
+
2033
+    public function testUpdateGroupNoSub(): void {
2034
+        $id = $this->addShareToDB(IShare::TYPE_GROUP, 'group0', 'user1', 'user2',
2035
+            'file', 42, 'target', 31, null, null);
2036
+
2037
+        $users = [];
2038
+        for ($i = 0; $i < 6; $i++) {
2039
+            $user = $this->createMock(IUser::class);
2040
+            $user->method('getUID')->willReturn('user' . $i);
2041
+            $users['user' . $i] = $user;
2042
+        }
2043
+
2044
+        $this->userManager->method('get')->willReturnCallback(
2045
+            function ($userId) use ($users) {
2046
+                return $users[$userId];
2047
+            }
2048
+        );
2049
+
2050
+        $groups = [];
2051
+        for ($i = 0; $i < 2; $i++) {
2052
+            $group = $this->createMock(IGroup::class);
2053
+            $group->method('getGID')->willReturn('group' . $i);
2054
+            $group->method('getDisplayName')->willReturn('group-displayname' . $i);
2055
+            $groups['group' . $i] = $group;
2056
+        }
2057
+
2058
+        $this->groupManager->method('get')->willReturnCallback(
2059
+            function ($groupId) use ($groups) {
2060
+                return $groups[$groupId];
2061
+            }
2062
+        );
2063
+
2064
+        $file1 = $this->createMock(File::class);
2065
+        $file1->method('getId')->willReturn(42);
2066
+        $file2 = $this->createMock(File::class);
2067
+        $file2->method('getId')->willReturn(43);
2068
+
2069
+        $folder1 = $this->createMock(Folder::class);
2070
+        $folder1->method('getFirstNodeById')->with(42)->willReturn($file1);
2071
+        $folder2 = $this->createMock(Folder::class);
2072
+        $folder2->method('getFirstNodeById')->with(43)->willReturn($file2);
2073
+
2074
+        $this->rootFolder->method('getUserFolder')->willReturnMap([
2075
+            ['user2', $folder1],
2076
+            ['user5', $folder2],
2077
+        ]);
2078
+
2079
+        $share = $this->provider->getShareById($id);
2080
+
2081
+        $share->setSharedWith('group0');
2082
+        $share->setSharedBy('user4');
2083
+        $share->setShareOwner('user5');
2084
+        $share->setNode($file2);
2085
+        $share->setPermissions(1);
2086
+
2087
+        $share2 = $this->provider->update($share);
2088
+
2089
+        $this->assertEquals($id, $share2->getId());
2090
+        // Group shares do not allow updating the recipient
2091
+        $this->assertSame('group0', $share2->getSharedWith());
2092
+        $this->assertSame('user4', $share2->getSharedBy());
2093
+        $this->assertSame('user5', $share2->getShareOwner());
2094
+        $this->assertSame(1, $share2->getPermissions());
2095
+
2096
+        $share2 = $this->provider->getShareById($id);
2097
+
2098
+        $this->assertEquals($id, $share2->getId());
2099
+        // Group shares do not allow updating the recipient
2100
+        $this->assertSame('group0', $share2->getSharedWith());
2101
+        $this->assertSame('user4', $share2->getSharedBy());
2102
+        $this->assertSame('user5', $share2->getShareOwner());
2103
+        $this->assertSame(1, $share2->getPermissions());
2104
+    }
2105
+
2106
+    public function testUpdateGroupSubShares(): void {
2107
+        $id = $this->addShareToDB(IShare::TYPE_GROUP, 'group0', 'user1', 'user2',
2108
+            'file', 42, 'target', 31, null, null);
2109
+
2110
+        $id2 = $this->addShareToDB(2, 'user0', 'user1', 'user2',
2111
+            'file', 42, 'mytarget', 31, null, null, $id);
2112
+
2113
+        $id3 = $this->addShareToDB(2, 'user3', 'user1', 'user2',
2114
+            'file', 42, 'mytarget2', 0, null, null, $id);
2115
+
2116
+        $users = [];
2117
+        for ($i = 0; $i < 6; $i++) {
2118
+            $user = $this->createMock(IUser::class);
2119
+            $user->method('getUID')->willReturn('user' . $i);
2120
+            $users['user' . $i] = $user;
2121
+        }
2122
+
2123
+        $this->userManager->method('get')->willReturnCallback(
2124
+            function ($userId) use ($users) {
2125
+                return $users[$userId];
2126
+            }
2127
+        );
2128
+
2129
+        $groups = [];
2130
+        for ($i = 0; $i < 2; $i++) {
2131
+            $group = $this->createMock(IGroup::class);
2132
+            $group->method('getGID')->willReturn('group' . $i);
2133
+            $group->method('getDisplayName')->willReturn('group-displayname' . $i);
2134
+            $groups['group' . $i] = $group;
2135
+        }
2136
+
2137
+        $this->groupManager->method('get')->willReturnCallback(
2138
+            function ($groupId) use ($groups) {
2139
+                return $groups[$groupId];
2140
+            }
2141
+        );
2142
+
2143
+        $file1 = $this->createMock(File::class);
2144
+        $file1->method('getId')->willReturn(42);
2145
+        $file2 = $this->createMock(File::class);
2146
+        $file2->method('getId')->willReturn(43);
2147
+
2148
+        $folder1 = $this->createMock(Folder::class);
2149
+        $folder1->method('getFirstNodeById')->with(42)->willReturn($file1);
2150
+        $folder2 = $this->createMock(Folder::class);
2151
+        $folder2->method('getFirstNodeById')->with(43)->willReturn($file2);
2152
+
2153
+        $this->rootFolder->method('getUserFolder')->willReturnMap([
2154
+            ['user2', $folder1],
2155
+            ['user5', $folder2],
2156
+        ]);
2157
+
2158
+        $share = $this->provider->getShareById($id);
2159
+
2160
+        $share->setSharedWith('group0');
2161
+        $share->setSharedBy('user4');
2162
+        $share->setShareOwner('user5');
2163
+        $share->setNode($file2);
2164
+        $share->setPermissions(1);
2165
+
2166
+        $share2 = $this->provider->update($share);
2167
+
2168
+        $this->assertEquals($id, $share2->getId());
2169
+        // Group shares do not allow updating the recipient
2170
+        $this->assertSame('group0', $share2->getSharedWith());
2171
+        $this->assertSame('user4', $share2->getSharedBy());
2172
+        $this->assertSame('user5', $share2->getShareOwner());
2173
+        $this->assertSame(1, $share2->getPermissions());
2174
+
2175
+        $share2 = $this->provider->getShareById($id);
2176
+
2177
+        $this->assertEquals($id, $share2->getId());
2178
+        // Group shares do not allow updating the recipient
2179
+        $this->assertSame('group0', $share2->getSharedWith());
2180
+        $this->assertSame('user4', $share2->getSharedBy());
2181
+        $this->assertSame('user5', $share2->getShareOwner());
2182
+        $this->assertSame(1, $share2->getPermissions());
2183
+
2184
+        $qb = $this->dbConn->getQueryBuilder();
2185
+        $stmt = $qb->select('*')
2186
+            ->from('share')
2187
+            ->where($qb->expr()->eq('parent', $qb->createNamedParameter($id)))
2188
+            ->orderBy('id')
2189
+            ->executeQuery();
2190
+
2191
+        $shares = $stmt->fetchAllAssociative();
2192
+
2193
+        $this->assertSame('user0', $shares[0]['share_with']);
2194
+        $this->assertSame('user4', $shares[0]['uid_initiator']);
2195
+        $this->assertSame('user5', $shares[0]['uid_owner']);
2196
+        $this->assertSame(1, (int)$shares[0]['permissions']);
2197
+
2198
+        $this->assertSame('user3', $shares[1]['share_with']);
2199
+        $this->assertSame('user4', $shares[1]['uid_initiator']);
2200
+        $this->assertSame('user5', $shares[1]['uid_owner']);
2201
+        $this->assertSame(0, (int)$shares[1]['permissions']);
2202
+
2203
+
2204
+        $stmt->closeCursor();
2205
+    }
2206
+
2207
+    public function testMoveUserShare(): void {
2208
+        $id = $this->addShareToDB(IShare::TYPE_USER, 'user0', 'user1', 'user1', 'file',
2209
+            42, 'mytaret', 31, null, null);
2210
+
2211
+        $user0 = $this->createMock(IUser::class);
2212
+        $user0->method('getUID')->willReturn('user0');
2213
+        $user0->method('getDisplayName')->willReturn('user0');
2214
+        $user1 = $this->createMock(IUser::class);
2215
+        $user1->method('getUID')->willReturn('user1');
2216
+        $user1->method('getDisplayName')->willReturn('user1');
2217
+
2218
+        $this->userManager->method('get')->willReturnMap([
2219
+            ['user0', $user0],
2220
+            ['user1', $user1],
2221
+        ]);
2222
+
2223
+        $file = $this->createMock(File::class);
2224
+        $file->method('getId')->willReturn(42);
2225
+
2226
+        $this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
2227
+        $this->rootFolder->method('getFirstNodeById')->willReturn($file);
2228
+
2229
+        $share = $this->provider->getShareById($id, null);
2230
+
2231
+        $share->setTarget('/newTarget');
2232
+        $this->provider->move($share, $user0);
2233
+
2234
+        $share = $this->provider->getShareById($id, null);
2235
+        $this->assertSame('/newTarget', $share->getTarget());
2236
+    }
2237
+
2238
+    public function testMoveGroupShare(): void {
2239
+        $id = $this->addShareToDB(IShare::TYPE_GROUP, 'group0', 'user1', 'user1', 'file',
2240
+            42, 'mytaret', 31, null, null);
2241
+
2242
+        $user0 = $this->createMock(IUser::class);
2243
+        $user0->method('getUID')->willReturn('user0');
2244
+        $user1 = $this->createMock(IUser::class);
2245
+        $user1->method('getUID')->willReturn('user1');
2246
+
2247
+        $group0 = $this->createMock(IGroup::class);
2248
+        $group0->method('getGID')->willReturn('group0');
2249
+        $group0->method('inGroup')->with($user0)->willReturn(true);
2250
+        $group0->method('getDisplayName')->willReturn('group0-displayname');
2251
+
2252
+        $this->groupManager->method('get')->with('group0')->willReturn($group0);
2253
+
2254
+        $this->userManager->method('get')->willReturnMap([
2255
+            ['user0', $user0],
2256
+            ['user1', $user1],
2257
+        ]);
2258
+
2259
+        $folder = $this->createMock(Folder::class);
2260
+        $folder->method('getId')->willReturn(42);
2261
+
2262
+        $this->rootFolder->method('getUserFolder')->with('user1')->willReturnSelf();
2263
+        $this->rootFolder->method('getFirstNodeById')->willReturn($folder);
2264
+
2265
+        $share = $this->provider->getShareById($id, 'user0');
2266
+
2267
+        $share->setTarget('/newTarget');
2268
+        $this->provider->move($share, 'user0');
2269
+
2270
+        $share = $this->provider->getShareById($id, 'user0');
2271
+        $this->assertSame('/newTarget', $share->getTarget());
2272
+
2273
+        $share->setTarget('/ultraNewTarget');
2274
+        $this->provider->move($share, 'user0');
2275
+
2276
+        $share = $this->provider->getShareById($id, 'user0');
2277
+        $this->assertSame('/ultraNewTarget', $share->getTarget());
2278
+    }
2279
+
2280
+    public static function dataDeleteUser(): array {
2281
+        return [
2282
+            [IShare::TYPE_USER, 'a', 'b', 'c', 'a', true],
2283
+            [IShare::TYPE_USER, 'a', 'b', 'c', 'b', false],
2284
+            [IShare::TYPE_USER, 'a', 'b', 'c', 'c', true],
2285
+            [IShare::TYPE_USER, 'a', 'b', 'c', 'd', false],
2286
+            [IShare::TYPE_GROUP, 'a', 'b', 'c', 'a', true],
2287
+            [IShare::TYPE_GROUP, 'a', 'b', 'c', 'b', false],
2288
+            // The group c is still valid but user c is deleted so group share stays
2289
+            [IShare::TYPE_GROUP, 'a', 'b', 'c', 'c', false],
2290
+            [IShare::TYPE_GROUP, 'a', 'b', 'c', 'd', false],
2291
+            [IShare::TYPE_LINK, 'a', 'b', 'c', 'a', true],
2292
+            // To avoid invisible link shares delete initiated link shares as well (see #22327)
2293
+            [IShare::TYPE_LINK, 'a', 'b', 'c', 'b', true],
2294
+            [IShare::TYPE_LINK, 'a', 'b', 'c', 'c', false],
2295
+            [IShare::TYPE_LINK, 'a', 'b', 'c', 'd', false],
2296
+        ];
2297
+    }
2298
+
2299
+    /**
2300
+     *
2301
+     * @param int $type The shareType (user/group/link)
2302
+     * @param string $owner The owner of the share (uid)
2303
+     * @param string $initiator The initiator of the share (uid)
2304
+     * @param string $recipient The recipient of the share (uid/gid/pass)
2305
+     * @param string $deletedUser The user that is deleted
2306
+     * @param bool $rowDeleted Is the row deleted in this setup
2307
+     */
2308
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataDeleteUser')]
2309
+    public function testDeleteUser($type, $owner, $initiator, $recipient, $deletedUser, $rowDeleted): void {
2310
+        $qb = $this->dbConn->getQueryBuilder();
2311
+        $qb->insert('share')
2312
+            ->setValue('share_type', $qb->createNamedParameter($type))
2313
+            ->setValue('uid_owner', $qb->createNamedParameter($owner))
2314
+            ->setValue('uid_initiator', $qb->createNamedParameter($initiator))
2315
+            ->setValue('share_with', $qb->createNamedParameter($recipient))
2316
+            ->setValue('item_type', $qb->createNamedParameter('file'))
2317
+            ->setValue('item_source', $qb->createNamedParameter(42))
2318
+            ->setValue('file_source', $qb->createNamedParameter(42))
2319
+            ->executeStatement();
2320
+
2321
+        $id = $qb->getLastInsertId();
2322
+
2323
+        $this->provider->userDeleted($deletedUser, $type);
2324
+
2325
+        $qb = $this->dbConn->getQueryBuilder();
2326
+        $qb->select('*')
2327
+            ->from('share')
2328
+            ->where(
2329
+                $qb->expr()->eq('id', $qb->createNamedParameter($id))
2330
+            );
2331
+        $cursor = $qb->executeQuery();
2332
+        $data = $cursor->fetchAllAssociative();
2333
+        $cursor->closeCursor();
2334
+
2335
+        $this->assertCount($rowDeleted ? 0 : 1, $data);
2336
+    }
2337
+
2338
+    public static function dataDeleteUserGroup(): array {
2339
+        return [
2340
+            ['a', 'b', 'c', 'a', true, true],
2341
+            ['a', 'b', 'c', 'b', false, false],
2342
+            ['a', 'b', 'c', 'c', false, true],
2343
+            ['a', 'b', 'c', 'd', false, false],
2344
+        ];
2345
+    }
2346
+
2347
+    /**
2348
+     *
2349
+     * @param string $owner The owner of the share (uid)
2350
+     * @param string $initiator The initiator of the share (uid)
2351
+     * @param string $recipient The recipient of the usergroup share (uid)
2352
+     * @param string $deletedUser The user that is deleted
2353
+     * @param bool $groupShareDeleted
2354
+     * @param bool $userGroupShareDeleted
2355
+     */
2356
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataDeleteUserGroup')]
2357
+    public function testDeleteUserGroup($owner, $initiator, $recipient, $deletedUser, $groupShareDeleted, $userGroupShareDeleted): void {
2358
+        $qb = $this->dbConn->getQueryBuilder();
2359
+        $qb->insert('share')
2360
+            ->setValue('share_type', $qb->createNamedParameter(IShare::TYPE_GROUP))
2361
+            ->setValue('uid_owner', $qb->createNamedParameter($owner))
2362
+            ->setValue('uid_initiator', $qb->createNamedParameter($initiator))
2363
+            ->setValue('share_with', $qb->createNamedParameter('group'))
2364
+            ->setValue('item_type', $qb->createNamedParameter('file'))
2365
+            ->setValue('item_source', $qb->createNamedParameter(42))
2366
+            ->setValue('file_source', $qb->createNamedParameter(42))
2367
+            ->executeStatement();
2368
+        $groupId = $qb->getLastInsertId();
2369
+
2370
+        $qb = $this->dbConn->getQueryBuilder();
2371
+        $qb->insert('share')
2372
+            ->setValue('share_type', $qb->createNamedParameter(2))
2373
+            ->setValue('uid_owner', $qb->createNamedParameter($owner))
2374
+            ->setValue('uid_initiator', $qb->createNamedParameter($initiator))
2375
+            ->setValue('share_with', $qb->createNamedParameter($recipient))
2376
+            ->setValue('item_type', $qb->createNamedParameter('file'))
2377
+            ->setValue('item_source', $qb->createNamedParameter(42))
2378
+            ->setValue('file_source', $qb->createNamedParameter(42))
2379
+            ->executeStatement();
2380
+        $userGroupId = $qb->getLastInsertId();
2381
+
2382
+        $this->provider->userDeleted($deletedUser, IShare::TYPE_GROUP);
2383
+
2384
+        $qb = $this->dbConn->getQueryBuilder();
2385
+        $qb->select('*')
2386
+            ->from('share')
2387
+            ->where(
2388
+                $qb->expr()->eq('id', $qb->createNamedParameter($userGroupId))
2389
+            );
2390
+        $cursor = $qb->executeQuery();
2391
+        $data = $cursor->fetchAllAssociative();
2392
+        $cursor->closeCursor();
2393
+        $this->assertCount($userGroupShareDeleted ? 0 : 1, $data);
2394
+
2395
+        $qb = $this->dbConn->getQueryBuilder();
2396
+        $qb->select('*')
2397
+            ->from('share')
2398
+            ->where(
2399
+                $qb->expr()->eq('id', $qb->createNamedParameter($groupId))
2400
+            );
2401
+        $cursor = $qb->executeQuery();
2402
+        $data = $cursor->fetchAllAssociative();
2403
+        $cursor->closeCursor();
2404
+        $this->assertCount($groupShareDeleted ? 0 : 1, $data);
2405
+    }
2406
+
2407
+    public static function dataGroupDeleted(): array {
2408
+        return [
2409
+            [
2410
+                [
2411
+                    'type' => IShare::TYPE_USER,
2412
+                    'recipient' => 'user',
2413
+                    'children' => []
2414
+                ], 'group', false
2415
+            ],
2416
+            [
2417
+                [
2418
+                    'type' => IShare::TYPE_USER,
2419
+                    'recipient' => 'user',
2420
+                    'children' => []
2421
+                ], 'user', false
2422
+            ],
2423
+            [
2424
+                [
2425
+                    'type' => IShare::TYPE_LINK,
2426
+                    'recipient' => 'user',
2427
+                    'children' => []
2428
+                ], 'group', false
2429
+            ],
2430
+            [
2431
+                [
2432
+                    'type' => IShare::TYPE_GROUP,
2433
+                    'recipient' => 'group1',
2434
+                    'children' => [
2435
+                        'foo',
2436
+                        'bar'
2437
+                    ]
2438
+                ], 'group2', false
2439
+            ],
2440
+            [
2441
+                [
2442
+                    'type' => IShare::TYPE_GROUP,
2443
+                    'recipient' => 'group1',
2444
+                    'children' => [
2445
+                        'foo',
2446
+                        'bar'
2447
+                    ]
2448
+                ], 'group1', true
2449
+            ],
2450
+        ];
2451
+    }
2452
+
2453
+    /**
2454
+     *
2455
+     * @param $shares
2456
+     * @param $groupToDelete
2457
+     * @param $shouldBeDeleted
2458
+     */
2459
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataGroupDeleted')]
2460
+    public function testGroupDeleted($shares, $groupToDelete, $shouldBeDeleted): void {
2461
+        $qb = $this->dbConn->getQueryBuilder();
2462
+        $qb->insert('share')
2463
+            ->setValue('share_type', $qb->createNamedParameter($shares['type']))
2464
+            ->setValue('uid_owner', $qb->createNamedParameter('owner'))
2465
+            ->setValue('uid_initiator', $qb->createNamedParameter('initiator'))
2466
+            ->setValue('share_with', $qb->createNamedParameter($shares['recipient']))
2467
+            ->setValue('item_type', $qb->createNamedParameter('file'))
2468
+            ->setValue('item_source', $qb->createNamedParameter(42))
2469
+            ->setValue('file_source', $qb->createNamedParameter(42))
2470
+            ->executeStatement();
2471
+        $ids = [$qb->getLastInsertId()];
2472
+
2473
+        foreach ($shares['children'] as $child) {
2474
+            $qb = $this->dbConn->getQueryBuilder();
2475
+            $qb->insert('share')
2476
+                ->setValue('share_type', $qb->createNamedParameter(2))
2477
+                ->setValue('uid_owner', $qb->createNamedParameter('owner'))
2478
+                ->setValue('uid_initiator', $qb->createNamedParameter('initiator'))
2479
+                ->setValue('share_with', $qb->createNamedParameter($child))
2480
+                ->setValue('item_type', $qb->createNamedParameter('file'))
2481
+                ->setValue('item_source', $qb->createNamedParameter(42))
2482
+                ->setValue('file_source', $qb->createNamedParameter(42))
2483
+                ->setValue('parent', $qb->createNamedParameter($ids[0]))
2484
+                ->executeStatement();
2485
+            $ids[] = $qb->getLastInsertId();
2486
+        }
2487
+
2488
+        $this->provider->groupDeleted($groupToDelete);
2489
+
2490
+        $qb = $this->dbConn->getQueryBuilder();
2491
+        $cursor = $qb->select('*')
2492
+            ->from('share')
2493
+            ->where($qb->expr()->in('id', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
2494
+            ->executeQuery();
2495
+        $data = $cursor->fetchAllAssociative();
2496
+        $cursor->closeCursor();
2497
+
2498
+        $this->assertCount($shouldBeDeleted ? 0 : count($ids), $data);
2499
+    }
2500
+
2501
+    public static function dataUserDeletedFromGroup(): array {
2502
+        return [
2503
+            ['group1', 'user1', true],
2504
+            ['group1', 'user2', false],
2505
+            ['group2', 'user1', false],
2506
+        ];
2507
+    }
2508
+
2509
+    /**
2510
+     * Given a group share with 'group1'
2511
+     * And a user specific group share with 'user1'.
2512
+     * User $user is deleted from group $gid.
2513
+     *
2514
+     *
2515
+     * @param string $group
2516
+     * @param string $user
2517
+     * @param bool $toDelete
2518
+     */
2519
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataUserDeletedFromGroup')]
2520
+    public function testUserDeletedFromGroup($group, $user, $toDelete): void {
2521
+        $qb = $this->dbConn->getQueryBuilder();
2522
+        $qb->insert('share')
2523
+            ->setValue('share_type', $qb->createNamedParameter(IShare::TYPE_GROUP))
2524
+            ->setValue('uid_owner', $qb->createNamedParameter('owner'))
2525
+            ->setValue('uid_initiator', $qb->createNamedParameter('initiator'))
2526
+            ->setValue('share_with', $qb->createNamedParameter('group1'))
2527
+            ->setValue('item_type', $qb->createNamedParameter('file'))
2528
+            ->setValue('item_source', $qb->createNamedParameter(42))
2529
+            ->setValue('file_source', $qb->createNamedParameter(42));
2530
+        $qb->executeStatement();
2531
+        $id1 = $qb->getLastInsertId();
2532
+
2533
+        $qb = $this->dbConn->getQueryBuilder();
2534
+        $qb->insert('share')
2535
+            ->setValue('share_type', $qb->createNamedParameter(2))
2536
+            ->setValue('uid_owner', $qb->createNamedParameter('owner'))
2537
+            ->setValue('uid_initiator', $qb->createNamedParameter('initiator'))
2538
+            ->setValue('share_with', $qb->createNamedParameter('user1'))
2539
+            ->setValue('item_type', $qb->createNamedParameter('file'))
2540
+            ->setValue('item_source', $qb->createNamedParameter(42))
2541
+            ->setValue('file_source', $qb->createNamedParameter(42))
2542
+            ->setValue('parent', $qb->createNamedParameter($id1));
2543
+        $qb->executeStatement();
2544
+        $id2 = $qb->getLastInsertId();
2545
+
2546
+        $this->provider->userDeletedFromGroup($user, $group);
2547
+
2548
+        $qb = $this->dbConn->getQueryBuilder();
2549
+        $qb->select('*')
2550
+            ->from('share')
2551
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id2)));
2552
+        $cursor = $qb->executeQuery();
2553
+        $data = $cursor->fetchAllAssociative();
2554
+        $cursor->closeCursor();
2555
+
2556
+        $this->assertCount($toDelete ? 0 : 1, $data);
2557
+    }
2558
+
2559
+    public function testGetSharesInFolder(): void {
2560
+        $userManager = Server::get(IUserManager::class);
2561
+        $groupManager = Server::get(IGroupManager::class);
2562
+        $rootFolder = Server::get(IRootFolder::class);
2563
+
2564
+        $provider = new DefaultShareProvider(
2565
+            $this->dbConn,
2566
+            $userManager,
2567
+            $groupManager,
2568
+            $rootFolder,
2569
+            $this->mailer,
2570
+            $this->defaults,
2571
+            $this->l10nFactory,
2572
+            $this->urlGenerator,
2573
+            $this->timeFactory,
2574
+            $this->logger,
2575
+            $this->shareManager,
2576
+            $this->config,
2577
+        );
2578
+
2579
+        $password = md5(time());
2580
+
2581
+        $u1 = $userManager->createUser('testShare1', $password);
2582
+        $u2 = $userManager->createUser('testShare2', $password);
2583
+        $u3 = $userManager->createUser('testShare3', $password);
2584
+
2585
+        $g1 = $groupManager->createGroup('group1');
2586
+
2587
+        $u1Folder = $rootFolder->getUserFolder($u1->getUID());
2588
+        $folder1 = $u1Folder->newFolder('foo');
2589
+        $file1 = $folder1->newFile('bar');
2590
+        $folder2 = $folder1->newFolder('baz');
2591
+
2592
+        $shareManager = Server::get(IShareManager::class);
2593
+        $share1 = $shareManager->newShare();
2594
+        $share1->setNode($folder1)
2595
+            ->setSharedBy($u1->getUID())
2596
+            ->setSharedWith($u2->getUID())
2597
+            ->setShareOwner($u1->getUID())
2598
+            ->setShareType(IShare::TYPE_USER)
2599
+            ->setPermissions(Constants::PERMISSION_ALL);
2600
+        $share1 = $this->provider->create($share1);
2601
+
2602
+        $share2 = $shareManager->newShare();
2603
+        $share2->setNode($file1)
2604
+            ->setSharedBy($u2->getUID())
2605
+            ->setSharedWith($u3->getUID())
2606
+            ->setShareOwner($u1->getUID())
2607
+            ->setShareType(IShare::TYPE_USER)
2608
+            ->setPermissions(Constants::PERMISSION_READ);
2609
+        $share2 = $this->provider->create($share2);
2610
+
2611
+        $share3 = $shareManager->newShare();
2612
+        $share3->setNode($folder2)
2613
+            ->setSharedBy($u2->getUID())
2614
+            ->setShareOwner($u1->getUID())
2615
+            ->setShareType(IShare::TYPE_LINK)
2616
+            ->setPermissions(Constants::PERMISSION_READ);
2617
+        $share3 = $this->provider->create($share3);
2618
+
2619
+        $share4 = $shareManager->newShare();
2620
+        $share4->setNode($folder2)
2621
+            ->setSharedBy($u1->getUID())
2622
+            ->setSharedWith($g1->getGID())
2623
+            ->setShareOwner($u1->getUID())
2624
+            ->setShareType(IShare::TYPE_GROUP)
2625
+            ->setPermissions(Constants::PERMISSION_READ);
2626
+        $share4 = $this->provider->create($share4);
2627
+
2628
+        $result = $provider->getSharesInFolder($u1->getUID(), $folder1, false);
2629
+        $this->assertCount(1, $result);
2630
+        $shares = array_pop($result);
2631
+        $this->assertCount(1, $shares);
2632
+        $this->assertSame($folder2->getId(), $shares[0]->getNodeId());
2633
+
2634
+        $result = $provider->getSharesInFolder($u1->getUID(), $folder1, true);
2635
+        $this->assertCount(2, $result);
2636
+
2637
+        $file_shares = $result[$file1->getId()];
2638
+        $this->assertCount(1, $file_shares);
2639
+        $this->assertSame($file1->getId(), $file_shares[0]->getNodeId());
2640
+        $this->assertSame(IShare::TYPE_USER, $file_shares[0]->getShareType());
2641
+
2642
+        $folder_shares = $result[$folder2->getId()];
2643
+        $this->assertCount(2, $folder_shares);
2644
+        $this->assertSame($folder2->getId(), $folder_shares[0]->getNodeId());
2645
+        $this->assertSame($folder2->getId(), $folder_shares[1]->getNodeId());
2646
+        $this->assertSame(IShare::TYPE_LINK, $folder_shares[0]->getShareType());
2647
+        $this->assertSame(IShare::TYPE_GROUP, $folder_shares[1]->getShareType());
2648
+
2649
+        $provider->delete($share1);
2650
+        $provider->delete($share2);
2651
+        $provider->delete($share3);
2652
+        $provider->delete($share4);
2653
+
2654
+        $u1->delete();
2655
+        $u2->delete();
2656
+        $u3->delete();
2657
+        $g1->delete();
2658
+    }
2659
+
2660
+    public function testGetAccessListNoCurrentAccessRequired(): void {
2661
+        $userManager = Server::get(IUserManager::class);
2662
+        $groupManager = Server::get(IGroupManager::class);
2663
+        $rootFolder = Server::get(IRootFolder::class);
2664
+
2665
+        $provider = new DefaultShareProvider(
2666
+            $this->dbConn,
2667
+            $userManager,
2668
+            $groupManager,
2669
+            $rootFolder,
2670
+            $this->mailer,
2671
+            $this->defaults,
2672
+            $this->l10nFactory,
2673
+            $this->urlGenerator,
2674
+            $this->timeFactory,
2675
+            $this->logger,
2676
+            $this->shareManager,
2677
+            $this->config,
2678
+        );
2679
+
2680
+        $u1 = $userManager->createUser('testShare1', 'test');
2681
+        $u2 = $userManager->createUser('testShare2', 'test');
2682
+        $u3 = $userManager->createUser('testShare3', 'test');
2683
+        $u4 = $userManager->createUser('testShare4', 'test');
2684
+        $u5 = $userManager->createUser('testShare5', 'test');
2685
+
2686
+        $g1 = $groupManager->createGroup('group1');
2687
+        $g1->addUser($u3);
2688
+        $g1->addUser($u4);
2689
+
2690
+        $u1Folder = $rootFolder->getUserFolder($u1->getUID());
2691
+        $folder1 = $u1Folder->newFolder('foo');
2692
+        $folder2 = $folder1->newFolder('baz');
2693
+        $file1 = $folder2->newFile('bar');
2694
+
2695
+        $result = $provider->getAccessList([$folder1, $folder2, $file1], false);
2696
+        $this->assertCount(0, $result['users']);
2697
+        $this->assertFalse($result['public']);
2698
+
2699
+        $shareManager = Server::get(IShareManager::class);
2700
+        $share1 = $shareManager->newShare();
2701
+        $share1->setNode($folder1)
2702
+            ->setSharedBy($u1->getUID())
2703
+            ->setSharedWith($u2->getUID())
2704
+            ->setShareOwner($u1->getUID())
2705
+            ->setShareType(IShare::TYPE_USER)
2706
+            ->setPermissions(Constants::PERMISSION_ALL);
2707
+        $share1 = $this->provider->create($share1);
2708
+        $share1 = $provider->acceptShare($share1, $u2->getUid());
2709
+
2710
+        $share2 = $shareManager->newShare();
2711
+        $share2->setNode($folder2)
2712
+            ->setSharedBy($u2->getUID())
2713
+            ->setSharedWith($g1->getGID())
2714
+            ->setShareOwner($u1->getUID())
2715
+            ->setShareType(IShare::TYPE_GROUP)
2716
+            ->setPermissions(Constants::PERMISSION_ALL);
2717
+        $share2 = $this->provider->create($share2);
2718
+
2719
+        $shareManager->deleteFromSelf($share2, $u4->getUID());
2720
+
2721
+        $share2 = $provider->acceptShare($share2, $u3->getUid());
2722
+        $share2 = $provider->acceptShare($share2, $u4->getUid());
2723
+
2724
+        $share3 = $shareManager->newShare();
2725
+        $share3->setNode($file1)
2726
+            ->setSharedBy($u3->getUID())
2727
+            ->setShareOwner($u1->getUID())
2728
+            ->setShareType(IShare::TYPE_LINK)
2729
+            ->setPermissions(Constants::PERMISSION_READ);
2730
+        $share3 = $this->provider->create($share3);
2731
+
2732
+        $share4 = $shareManager->newShare();
2733
+        $share4->setNode($file1)
2734
+            ->setSharedBy($u3->getUID())
2735
+            ->setSharedWith($u5->getUID())
2736
+            ->setShareOwner($u1->getUID())
2737
+            ->setShareType(IShare::TYPE_USER)
2738
+            ->setPermissions(Constants::PERMISSION_READ);
2739
+        $share4 = $this->provider->create($share4);
2740
+        $share4 = $provider->acceptShare($share4, $u5->getUid());
2741
+
2742
+        $result = $provider->getAccessList([$folder1, $folder2, $file1], false);
2743
+
2744
+        $this->assertCount(4, $result['users']);
2745
+        $this->assertContains('testShare2', $result['users']);
2746
+        $this->assertContains('testShare3', $result['users']);
2747
+        $this->assertContains('testShare4', $result['users']);
2748
+        $this->assertContains('testShare5', $result['users']);
2749
+        $this->assertTrue($result['public']);
2750
+
2751
+        $provider->delete($share1);
2752
+        $provider->delete($share2);
2753
+        $provider->delete($share3);
2754
+        $provider->delete($share4);
2755
+
2756
+        $u1->delete();
2757
+        $u2->delete();
2758
+        $u3->delete();
2759
+        $u4->delete();
2760
+        $u5->delete();
2761
+        $g1->delete();
2762
+    }
2763
+
2764
+    public function testGetAccessListCurrentAccessRequired(): void {
2765
+        $userManager = Server::get(IUserManager::class);
2766
+        $groupManager = Server::get(IGroupManager::class);
2767
+        $rootFolder = Server::get(IRootFolder::class);
2768
+
2769
+        $provider = new DefaultShareProvider(
2770
+            $this->dbConn,
2771
+            $userManager,
2772
+            $groupManager,
2773
+            $rootFolder,
2774
+            $this->mailer,
2775
+            $this->defaults,
2776
+            $this->l10nFactory,
2777
+            $this->urlGenerator,
2778
+            $this->timeFactory,
2779
+            $this->logger,
2780
+            $this->shareManager,
2781
+            $this->config,
2782
+        );
2783
+
2784
+        $u1 = $userManager->createUser('testShare1', 'test');
2785
+        $u2 = $userManager->createUser('testShare2', 'test');
2786
+        $u3 = $userManager->createUser('testShare3', 'test');
2787
+        $u4 = $userManager->createUser('testShare4', 'test');
2788
+        $u5 = $userManager->createUser('testShare5', 'test');
2789
+
2790
+        $g1 = $groupManager->createGroup('group1');
2791
+        $g1->addUser($u3);
2792
+        $g1->addUser($u4);
2793
+
2794
+        $u1Folder = $rootFolder->getUserFolder($u1->getUID());
2795
+        $folder1 = $u1Folder->newFolder('foo');
2796
+        $folder2 = $folder1->newFolder('baz');
2797
+        $file1 = $folder2->newFile('bar');
2798
+
2799
+        $result = $provider->getAccessList([$folder1, $folder2, $file1], false);
2800
+        $this->assertCount(0, $result['users']);
2801
+        $this->assertFalse($result['public']);
2802
+
2803
+        $shareManager = Server::get(IShareManager::class);
2804
+        $share1 = $shareManager->newShare();
2805
+        $share1->setNode($folder1)
2806
+            ->setSharedBy($u1->getUID())
2807
+            ->setSharedWith($u2->getUID())
2808
+            ->setShareOwner($u1->getUID())
2809
+            ->setShareType(IShare::TYPE_USER)
2810
+            ->setPermissions(Constants::PERMISSION_ALL);
2811
+        $share1 = $this->provider->create($share1);
2812
+        $share1 = $provider->acceptShare($share1, $u2->getUid());
2813
+
2814
+        $share2 = $shareManager->newShare();
2815
+        $share2->setNode($folder2)
2816
+            ->setSharedBy($u2->getUID())
2817
+            ->setSharedWith($g1->getGID())
2818
+            ->setShareOwner($u1->getUID())
2819
+            ->setShareType(IShare::TYPE_GROUP)
2820
+            ->setPermissions(Constants::PERMISSION_ALL);
2821
+        $share2 = $this->provider->create($share2);
2822
+        $share2 = $provider->acceptShare($share2, $u3->getUid());
2823
+        $share2 = $provider->acceptShare($share2, $u4->getUid());
2824
+
2825
+        $shareManager->deleteFromSelf($share2, $u4->getUID());
2826
+
2827
+        $share3 = $shareManager->newShare();
2828
+        $share3->setNode($file1)
2829
+            ->setSharedBy($u3->getUID())
2830
+            ->setShareOwner($u1->getUID())
2831
+            ->setShareType(IShare::TYPE_LINK)
2832
+            ->setPermissions(Constants::PERMISSION_READ);
2833
+        $share3 = $this->provider->create($share3);
2834
+
2835
+        $share4 = $shareManager->newShare();
2836
+        $share4->setNode($file1)
2837
+            ->setSharedBy($u3->getUID())
2838
+            ->setSharedWith($u5->getUID())
2839
+            ->setShareOwner($u1->getUID())
2840
+            ->setShareType(IShare::TYPE_USER)
2841
+            ->setPermissions(Constants::PERMISSION_READ);
2842
+        $share4 = $this->provider->create($share4);
2843
+        $share4 = $provider->acceptShare($share4, $u5->getUid());
2844
+
2845
+        $result = $provider->getAccessList([$folder1, $folder2, $file1], true);
2846
+
2847
+        $this->assertCount(3, $result['users']);
2848
+        $this->assertArrayHasKey('testShare2', $result['users']);
2849
+        $this->assertArrayHasKey('testShare3', $result['users']);
2850
+        $this->assertArrayHasKey('testShare5', $result['users']);
2851
+        $this->assertTrue($result['public']);
2852
+
2853
+        $provider->delete($share1);
2854
+        $provider->delete($share2);
2855
+        $provider->delete($share3);
2856
+        $provider->delete($share4);
2857
+
2858
+        $u1->delete();
2859
+        $u2->delete();
2860
+        $u3->delete();
2861
+        $u4->delete();
2862
+        $u5->delete();
2863
+        $g1->delete();
2864
+    }
2865
+
2866
+    public function testGetAllShares(): void {
2867
+        $qb = $this->dbConn->getQueryBuilder();
2868
+
2869
+        $qb->insert('share')
2870
+            ->values([
2871
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
2872
+                'share_with' => $qb->expr()->literal('sharedWith1'),
2873
+                'uid_owner' => $qb->expr()->literal('shareOwner1'),
2874
+                'uid_initiator' => $qb->expr()->literal('sharedBy1'),
2875
+                'item_type' => $qb->expr()->literal('file'),
2876
+                'file_source' => $qb->expr()->literal(42),
2877
+                'file_target' => $qb->expr()->literal('myTarget1'),
2878
+                'permissions' => $qb->expr()->literal(13),
2879
+            ]);
2880
+        $qb->executeStatement();
2881
+
2882
+        $id1 = $qb->getLastInsertId();
2883
+
2884
+        $qb->insert('share')
2885
+            ->values([
2886
+                'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
2887
+                'share_with' => $qb->expr()->literal('sharedWith2'),
2888
+                'uid_owner' => $qb->expr()->literal('shareOwner2'),
2889
+                'uid_initiator' => $qb->expr()->literal('sharedBy2'),
2890
+                'item_type' => $qb->expr()->literal('file'),
2891
+                'file_source' => $qb->expr()->literal(43),
2892
+                'file_target' => $qb->expr()->literal('myTarget2'),
2893
+                'permissions' => $qb->expr()->literal(14),
2894
+            ]);
2895
+        $qb->executeStatement();
2896
+
2897
+        $id2 = $qb->getLastInsertId();
2898
+
2899
+        $qb->insert('share')
2900
+            ->values([
2901
+                'share_type' => $qb->expr()->literal(IShare::TYPE_LINK),
2902
+                'token' => $qb->expr()->literal('token3'),
2903
+                'uid_owner' => $qb->expr()->literal('shareOwner3'),
2904
+                'uid_initiator' => $qb->expr()->literal('sharedBy3'),
2905
+                'item_type' => $qb->expr()->literal('file'),
2906
+                'file_source' => $qb->expr()->literal(44),
2907
+                'file_target' => $qb->expr()->literal('myTarget3'),
2908
+                'permissions' => $qb->expr()->literal(15),
2909
+            ]);
2910
+        $qb->executeStatement();
2911
+
2912
+        $id3 = $qb->getLastInsertId();
2913
+
2914
+        $qb->insert('share')
2915
+            ->values([
2916
+                'share_type' => $qb->expr()->literal(IShare::TYPE_EMAIL),
2917
+                'share_with' => $qb->expr()->literal('shareOwner4'),
2918
+                'token' => $qb->expr()->literal('token4'),
2919
+                'uid_owner' => $qb->expr()->literal('shareOwner4'),
2920
+                'uid_initiator' => $qb->expr()->literal('sharedBy4'),
2921
+                'item_type' => $qb->expr()->literal('file'),
2922
+                'file_source' => $qb->expr()->literal(45),
2923
+                'file_target' => $qb->expr()->literal('myTarget4'),
2924
+                'permissions' => $qb->expr()->literal(16),
2925
+            ]);
2926
+        $qb->executeStatement();
2927
+
2928
+        $id4 = $qb->getLastInsertId();
2929
+
2930
+        $qb->insert('share')
2931
+            ->values([
2932
+                'share_type' => $qb->expr()->literal(IShare::TYPE_LINK),
2933
+                'token' => $qb->expr()->literal('token5'),
2934
+                'uid_owner' => $qb->expr()->literal('shareOwner5'),
2935
+                'uid_initiator' => $qb->expr()->literal('sharedBy5'),
2936
+                'item_type' => $qb->expr()->literal('file'),
2937
+                'file_source' => $qb->expr()->literal(46),
2938
+                'file_target' => $qb->expr()->literal('myTarget5'),
2939
+                'permissions' => $qb->expr()->literal(17),
2940
+            ]);
2941
+        $qb->executeStatement();
2942
+
2943
+        $id5 = $qb->getLastInsertId();
2944
+
2945
+        $ownerPath1 = $this->createMock(File::class);
2946
+        $shareOwner1Folder = $this->createMock(Folder::class);
2947
+        $shareOwner1Folder->method('getFirstNodeById')->willReturn($ownerPath1);
2948
+
2949
+        $ownerPath2 = $this->createMock(File::class);
2950
+        $shareOwner2Folder = $this->createMock(Folder::class);
2951
+        $shareOwner2Folder->method('getFirstNodeById')->willReturn($ownerPath2);
2952
+
2953
+        $ownerPath3 = $this->createMock(File::class);
2954
+        $shareOwner3Folder = $this->createMock(Folder::class);
2955
+        $shareOwner3Folder->method('getFirstNodeById')->willReturn($ownerPath3);
2956
+
2957
+        $ownerPath4 = $this->createMock(File::class);
2958
+        $shareOwner4Folder = $this->createMock(Folder::class);
2959
+        $shareOwner4Folder->method('getFirstNodeById')->willReturn($ownerPath4);
2960
+
2961
+        $ownerPath5 = $this->createMock(File::class);
2962
+        $shareOwner5Folder = $this->createMock(Folder::class);
2963
+        $shareOwner5Folder->method('getFirstNodeById')->willReturn($ownerPath5);
2964
+
2965
+        $this->rootFolder
2966
+            ->method('getUserFolder')
2967
+            ->willReturnMap(
2968
+                [
2969
+                    ['shareOwner1', $shareOwner1Folder],
2970
+                    ['shareOwner2', $shareOwner2Folder],
2971
+                    ['shareOwner3', $shareOwner3Folder],
2972
+                    ['shareOwner4', $shareOwner4Folder],
2973
+                    ['shareOwner5', $shareOwner5Folder],
2974
+                ]
2975
+            );
2976
+
2977
+        $shares = iterator_to_array($this->provider->getAllShares());
2978
+        $this->assertEquals(4, count($shares));
2979
+
2980
+        $share = $shares[0];
2981
+
2982
+        // We fetch the node so the root folder is eventually called
2983
+
2984
+        $this->assertEquals($id1, $share->getId());
2985
+        $this->assertEquals(IShare::TYPE_USER, $share->getShareType());
2986
+        $this->assertEquals('sharedWith1', $share->getSharedWith());
2987
+        $this->assertEquals('sharedBy1', $share->getSharedBy());
2988
+        $this->assertEquals('shareOwner1', $share->getShareOwner());
2989
+        $this->assertEquals($ownerPath1, $share->getNode());
2990
+        $this->assertEquals(13, $share->getPermissions());
2991
+        $this->assertEquals(null, $share->getToken());
2992
+        $this->assertEquals('myTarget1', $share->getTarget());
2993
+
2994
+        $share = $shares[1];
2995
+
2996
+        $this->assertEquals($id2, $share->getId());
2997
+        $this->assertEquals(IShare::TYPE_GROUP, $share->getShareType());
2998
+        $this->assertEquals('sharedWith2', $share->getSharedWith());
2999
+        $this->assertEquals('sharedBy2', $share->getSharedBy());
3000
+        $this->assertEquals('shareOwner2', $share->getShareOwner());
3001
+        $this->assertEquals($ownerPath2, $share->getNode());
3002
+        $this->assertEquals(14, $share->getPermissions());
3003
+        $this->assertEquals(null, $share->getToken());
3004
+        $this->assertEquals('myTarget2', $share->getTarget());
3005
+
3006
+        $share = $shares[2];
3007
+
3008
+        $this->assertEquals($id3, $share->getId());
3009
+        $this->assertEquals(IShare::TYPE_LINK, $share->getShareType());
3010
+        $this->assertEquals(null, $share->getSharedWith());
3011
+        $this->assertEquals('sharedBy3', $share->getSharedBy());
3012
+        $this->assertEquals('shareOwner3', $share->getShareOwner());
3013
+        $this->assertEquals($ownerPath3, $share->getNode());
3014
+        $this->assertEquals(15, $share->getPermissions());
3015
+        $this->assertEquals('token3', $share->getToken());
3016
+        $this->assertEquals('myTarget3', $share->getTarget());
3017
+
3018
+        $share = $shares[3];
3019
+
3020
+        $this->assertEquals($id5, $share->getId());
3021
+        $this->assertEquals(IShare::TYPE_LINK, $share->getShareType());
3022
+        $this->assertEquals(null, $share->getSharedWith());
3023
+        $this->assertEquals('sharedBy5', $share->getSharedBy());
3024
+        $this->assertEquals('shareOwner5', $share->getShareOwner());
3025
+        $this->assertEquals($ownerPath5, $share->getNode());
3026
+        $this->assertEquals(17, $share->getPermissions());
3027
+        $this->assertEquals('token5', $share->getToken());
3028
+        $this->assertEquals('myTarget5', $share->getTarget());
3029
+    }
3030
+
3031
+
3032
+    public function testGetSharesByPath(): void {
3033
+        $qb = $this->dbConn->getQueryBuilder();
3034
+
3035
+        $qb->insert('share')
3036
+            ->values([
3037
+                'share_type' => $qb->expr()->literal(IShare::TYPE_USER),
3038
+                'uid_owner' => $qb->expr()->literal('user1'),
3039
+                'uid_initiator' => $qb->expr()->literal('user1'),
3040
+                'share_with' => $qb->expr()->literal('user2'),
3041
+                'item_type' => $qb->expr()->literal('file'),
3042
+                'file_source' => $qb->expr()->literal(1),
3043
+            ]);
3044
+        $qb->executeStatement();
3045
+
3046
+        $id1 = $qb->getLastInsertId();
3047
+
3048
+        $qb->insert('share')
3049
+            ->values([
3050
+                'share_type' => $qb->expr()->literal(IShare::TYPE_GROUP),
3051
+                'uid_owner' => $qb->expr()->literal('user1'),
3052
+                'uid_initiator' => $qb->expr()->literal('user1'),
3053
+                'share_with' => $qb->expr()->literal('user2'),
3054
+                'item_type' => $qb->expr()->literal('file'),
3055
+                'file_source' => $qb->expr()->literal(1),
3056
+            ]);
3057
+        $qb->executeStatement();
3058
+
3059
+        $id2 = $qb->getLastInsertId();
3060
+
3061
+        $qb->insert('share')
3062
+            ->values([
3063
+                'share_type' => $qb->expr()->literal(IShare::TYPE_LINK),
3064
+                'uid_owner' => $qb->expr()->literal('user1'),
3065
+                'uid_initiator' => $qb->expr()->literal('user1'),
3066
+                'share_with' => $qb->expr()->literal('user2'),
3067
+                'item_type' => $qb->expr()->literal('file'),
3068
+                'file_source' => $qb->expr()->literal(1),
3069
+            ]);
3070
+        $qb->executeStatement();
3071
+
3072
+        $id3 = $qb->getLastInsertId();
3073
+
3074
+        $ownerPath1 = $this->createMock(File::class);
3075
+        $shareOwner1Folder = $this->createMock(Folder::class);
3076
+        $shareOwner1Folder->method('getFirstNodeById')->willReturn($ownerPath1);
3077
+
3078
+        $ownerPath2 = $this->createMock(File::class);
3079
+        $shareOwner2Folder = $this->createMock(Folder::class);
3080
+        $shareOwner2Folder->method('getFirstNodeById')->willReturn($ownerPath2);
3081
+
3082
+        $ownerPath3 = $this->createMock(File::class);
3083
+        $shareOwner3Folder = $this->createMock(Folder::class);
3084
+        $shareOwner3Folder->method('getFirstNodeById')->willReturn($ownerPath3);
3085
+
3086
+        $this->rootFolder
3087
+            ->method('getUserFolder')
3088
+            ->willReturnMap(
3089
+                [
3090
+                    ['shareOwner1', $shareOwner1Folder],
3091
+                    ['shareOwner2', $shareOwner2Folder],
3092
+                    ['shareOwner3', $shareOwner3Folder],
3093
+                ]
3094
+            );
3095
+
3096
+        $node = $this->createMock(Node::class);
3097
+        $node
3098
+            ->expects($this->once())
3099
+            ->method('getId')
3100
+            ->willReturn(1);
3101
+
3102
+        $shares = $this->provider->getSharesByPath($node);
3103
+        $this->assertCount(3, $shares);
3104
+
3105
+        $this->assertEquals($id1, $shares[0]->getId());
3106
+        $this->assertEquals(IShare::TYPE_USER, $shares[0]->getShareType());
3107
+
3108
+        $this->assertEquals($id2, $shares[1]->getId());
3109
+        $this->assertEquals(IShare::TYPE_GROUP, $shares[1]->getShareType());
3110
+
3111
+        $this->assertEquals($id3, $shares[2]->getId());
3112
+        $this->assertEquals(IShare::TYPE_LINK, $shares[2]->getShareType());
3113
+    }
3114 3114
 }
Please login to merge, or discard this patch.
tests/lib/Authentication/TwoFactorAuth/Db/ProviderUserAssignmentDaoTest.php 1 patch
Indentation   +138 added lines, -138 removed lines patch added patch discarded remove patch
@@ -16,142 +16,142 @@
 block discarded – undo
16 16
 
17 17
 #[\PHPUnit\Framework\Attributes\Group('DB')]
18 18
 class ProviderUserAssignmentDaoTest extends TestCase {
19
-	/** @var IDBConnection */
20
-	private $dbConn;
21
-
22
-	/** @var ProviderUserAssignmentDao */
23
-	private $dao;
24
-
25
-	protected function setUp(): void {
26
-		parent::setUp();
27
-
28
-		$this->dbConn = Server::get(IDBConnection::class);
29
-		$qb = $this->dbConn->getQueryBuilder();
30
-		$q = $qb->delete(ProviderUserAssignmentDao::TABLE_NAME);
31
-		$q->executeStatement();
32
-
33
-		$this->dao = new ProviderUserAssignmentDao($this->dbConn);
34
-	}
35
-
36
-	public function testGetState(): void {
37
-		$qb = $this->dbConn->getQueryBuilder();
38
-		$q1 = $qb->insert(ProviderUserAssignmentDao::TABLE_NAME)->values([
39
-			'provider_id' => $qb->createNamedParameter('twofactor_u2f'),
40
-			'uid' => $qb->createNamedParameter('user123'),
41
-			'enabled' => $qb->createNamedParameter(1),
42
-		]);
43
-		$q1->executeStatement();
44
-		$q2 = $qb->insert(ProviderUserAssignmentDao::TABLE_NAME)->values([
45
-			'provider_id' => $qb->createNamedParameter('twofactor_totp'),
46
-			'uid' => $qb->createNamedParameter('user123'),
47
-			'enabled' => $qb->createNamedParameter(0),
48
-		]);
49
-		$q2->executeStatement();
50
-		$expected = [
51
-			'twofactor_u2f' => true,
52
-			'twofactor_totp' => false,
53
-		];
54
-
55
-		$state = $this->dao->getState('user123');
56
-
57
-		$this->assertEquals($expected, $state);
58
-	}
59
-
60
-	public function testPersist(): void {
61
-		$qb = $this->dbConn->getQueryBuilder();
62
-
63
-		$this->dao->persist('twofactor_totp', 'user123', 0);
64
-
65
-		$q = $qb
66
-			->select('*')
67
-			->from(ProviderUserAssignmentDao::TABLE_NAME)
68
-			->where($qb->expr()->eq('provider_id', $qb->createNamedParameter('twofactor_totp')))
69
-			->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter('user123')))
70
-			->andWhere($qb->expr()->eq('enabled', $qb->createNamedParameter(0)));
71
-		$res = $q->executeQuery();
72
-		$data = $res->fetchAllAssociative();
73
-		$res->closeCursor();
74
-		$this->assertCount(1, $data);
75
-	}
76
-
77
-	public function testPersistTwice(): void {
78
-		$qb = $this->dbConn->getQueryBuilder();
79
-
80
-		$this->dao->persist('twofactor_totp', 'user123', 0);
81
-		$this->dao->persist('twofactor_totp', 'user123', 1);
82
-
83
-		$q = $qb
84
-			->select('*')
85
-			->from(ProviderUserAssignmentDao::TABLE_NAME)
86
-			->where($qb->expr()->eq('provider_id', $qb->createNamedParameter('twofactor_totp')))
87
-			->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter('user123')))
88
-			->andWhere($qb->expr()->eq('enabled', $qb->createNamedParameter(1)));
89
-		$res = $q->executeQuery();
90
-		$data = $res->fetchAllAssociative();
91
-		$res->closeCursor();
92
-
93
-		$this->assertCount(1, $data);
94
-	}
95
-
96
-	public function testPersistSameStateTwice(): void {
97
-		$qb = $this->dbConn->getQueryBuilder();
98
-
99
-		$this->dao->persist('twofactor_totp', 'user123', 1);
100
-		$this->dao->persist('twofactor_totp', 'user123', 1);
101
-
102
-		$q = $qb
103
-			->select('*')
104
-			->from(ProviderUserAssignmentDao::TABLE_NAME)
105
-			->where($qb->expr()->eq('provider_id', $qb->createNamedParameter('twofactor_totp')))
106
-			->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter('user123')))
107
-			->andWhere($qb->expr()->eq('enabled', $qb->createNamedParameter(1)));
108
-		$res = $q->executeQuery();
109
-		$data = $res->fetchAllAssociative();
110
-		$res->closeCursor();
111
-
112
-		$this->assertCount(1, $data);
113
-	}
114
-
115
-	public function testDeleteByUser(): void {
116
-		$this->dao->persist('twofactor_fail', 'user1', 1);
117
-		$this->dao->persist('twofactor_u2f', 'user1', 1);
118
-		$this->dao->persist('twofactor_fail', 'user2', 0);
119
-		$this->dao->persist('twofactor_u2f', 'user2', 0);
120
-
121
-		$deleted = $this->dao->deleteByUser('user1');
122
-
123
-		$this->assertEquals(
124
-			[
125
-				[
126
-					'uid' => 'user1',
127
-					'provider_id' => 'twofactor_fail',
128
-					'enabled' => true,
129
-				],
130
-				[
131
-					'uid' => 'user1',
132
-					'provider_id' => 'twofactor_u2f',
133
-					'enabled' => true,
134
-				],
135
-			],
136
-			$deleted
137
-		);
138
-		$statesUser1 = $this->dao->getState('user1');
139
-		$statesUser2 = $this->dao->getState('user2');
140
-		$this->assertCount(0, $statesUser1);
141
-		$this->assertCount(2, $statesUser2);
142
-	}
143
-
144
-	public function testDeleteAll(): void {
145
-		$this->dao->persist('twofactor_fail', 'user1', 1);
146
-		$this->dao->persist('twofactor_u2f', 'user1', 1);
147
-		$this->dao->persist('twofactor_fail', 'user2', 0);
148
-		$this->dao->persist('twofactor_u2f', 'user1', 0);
149
-
150
-		$this->dao->deleteAll('twofactor_fail');
151
-
152
-		$statesUser1 = $this->dao->getState('user1');
153
-		$statesUser2 = $this->dao->getState('user2');
154
-		$this->assertCount(1, $statesUser1);
155
-		$this->assertCount(0, $statesUser2);
156
-	}
19
+    /** @var IDBConnection */
20
+    private $dbConn;
21
+
22
+    /** @var ProviderUserAssignmentDao */
23
+    private $dao;
24
+
25
+    protected function setUp(): void {
26
+        parent::setUp();
27
+
28
+        $this->dbConn = Server::get(IDBConnection::class);
29
+        $qb = $this->dbConn->getQueryBuilder();
30
+        $q = $qb->delete(ProviderUserAssignmentDao::TABLE_NAME);
31
+        $q->executeStatement();
32
+
33
+        $this->dao = new ProviderUserAssignmentDao($this->dbConn);
34
+    }
35
+
36
+    public function testGetState(): void {
37
+        $qb = $this->dbConn->getQueryBuilder();
38
+        $q1 = $qb->insert(ProviderUserAssignmentDao::TABLE_NAME)->values([
39
+            'provider_id' => $qb->createNamedParameter('twofactor_u2f'),
40
+            'uid' => $qb->createNamedParameter('user123'),
41
+            'enabled' => $qb->createNamedParameter(1),
42
+        ]);
43
+        $q1->executeStatement();
44
+        $q2 = $qb->insert(ProviderUserAssignmentDao::TABLE_NAME)->values([
45
+            'provider_id' => $qb->createNamedParameter('twofactor_totp'),
46
+            'uid' => $qb->createNamedParameter('user123'),
47
+            'enabled' => $qb->createNamedParameter(0),
48
+        ]);
49
+        $q2->executeStatement();
50
+        $expected = [
51
+            'twofactor_u2f' => true,
52
+            'twofactor_totp' => false,
53
+        ];
54
+
55
+        $state = $this->dao->getState('user123');
56
+
57
+        $this->assertEquals($expected, $state);
58
+    }
59
+
60
+    public function testPersist(): void {
61
+        $qb = $this->dbConn->getQueryBuilder();
62
+
63
+        $this->dao->persist('twofactor_totp', 'user123', 0);
64
+
65
+        $q = $qb
66
+            ->select('*')
67
+            ->from(ProviderUserAssignmentDao::TABLE_NAME)
68
+            ->where($qb->expr()->eq('provider_id', $qb->createNamedParameter('twofactor_totp')))
69
+            ->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter('user123')))
70
+            ->andWhere($qb->expr()->eq('enabled', $qb->createNamedParameter(0)));
71
+        $res = $q->executeQuery();
72
+        $data = $res->fetchAllAssociative();
73
+        $res->closeCursor();
74
+        $this->assertCount(1, $data);
75
+    }
76
+
77
+    public function testPersistTwice(): void {
78
+        $qb = $this->dbConn->getQueryBuilder();
79
+
80
+        $this->dao->persist('twofactor_totp', 'user123', 0);
81
+        $this->dao->persist('twofactor_totp', 'user123', 1);
82
+
83
+        $q = $qb
84
+            ->select('*')
85
+            ->from(ProviderUserAssignmentDao::TABLE_NAME)
86
+            ->where($qb->expr()->eq('provider_id', $qb->createNamedParameter('twofactor_totp')))
87
+            ->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter('user123')))
88
+            ->andWhere($qb->expr()->eq('enabled', $qb->createNamedParameter(1)));
89
+        $res = $q->executeQuery();
90
+        $data = $res->fetchAllAssociative();
91
+        $res->closeCursor();
92
+
93
+        $this->assertCount(1, $data);
94
+    }
95
+
96
+    public function testPersistSameStateTwice(): void {
97
+        $qb = $this->dbConn->getQueryBuilder();
98
+
99
+        $this->dao->persist('twofactor_totp', 'user123', 1);
100
+        $this->dao->persist('twofactor_totp', 'user123', 1);
101
+
102
+        $q = $qb
103
+            ->select('*')
104
+            ->from(ProviderUserAssignmentDao::TABLE_NAME)
105
+            ->where($qb->expr()->eq('provider_id', $qb->createNamedParameter('twofactor_totp')))
106
+            ->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter('user123')))
107
+            ->andWhere($qb->expr()->eq('enabled', $qb->createNamedParameter(1)));
108
+        $res = $q->executeQuery();
109
+        $data = $res->fetchAllAssociative();
110
+        $res->closeCursor();
111
+
112
+        $this->assertCount(1, $data);
113
+    }
114
+
115
+    public function testDeleteByUser(): void {
116
+        $this->dao->persist('twofactor_fail', 'user1', 1);
117
+        $this->dao->persist('twofactor_u2f', 'user1', 1);
118
+        $this->dao->persist('twofactor_fail', 'user2', 0);
119
+        $this->dao->persist('twofactor_u2f', 'user2', 0);
120
+
121
+        $deleted = $this->dao->deleteByUser('user1');
122
+
123
+        $this->assertEquals(
124
+            [
125
+                [
126
+                    'uid' => 'user1',
127
+                    'provider_id' => 'twofactor_fail',
128
+                    'enabled' => true,
129
+                ],
130
+                [
131
+                    'uid' => 'user1',
132
+                    'provider_id' => 'twofactor_u2f',
133
+                    'enabled' => true,
134
+                ],
135
+            ],
136
+            $deleted
137
+        );
138
+        $statesUser1 = $this->dao->getState('user1');
139
+        $statesUser2 = $this->dao->getState('user2');
140
+        $this->assertCount(0, $statesUser1);
141
+        $this->assertCount(2, $statesUser2);
142
+    }
143
+
144
+    public function testDeleteAll(): void {
145
+        $this->dao->persist('twofactor_fail', 'user1', 1);
146
+        $this->dao->persist('twofactor_u2f', 'user1', 1);
147
+        $this->dao->persist('twofactor_fail', 'user2', 0);
148
+        $this->dao->persist('twofactor_u2f', 'user1', 0);
149
+
150
+        $this->dao->deleteAll('twofactor_fail');
151
+
152
+        $statesUser1 = $this->dao->getState('user1');
153
+        $statesUser2 = $this->dao->getState('user2');
154
+        $this->assertCount(1, $statesUser1);
155
+        $this->assertCount(0, $statesUser2);
156
+    }
157 157
 }
Please login to merge, or discard this patch.
tests/lib/Authentication/Token/PublicKeyTokenMapperTest.php 2 patches
Indentation   +232 added lines, -232 removed lines patch added patch discarded remove patch
@@ -20,244 +20,244 @@
 block discarded – undo
20 20
 
21 21
 #[\PHPUnit\Framework\Attributes\Group('DB')]
22 22
 class PublicKeyTokenMapperTest extends TestCase {
23
-	/** @var PublicKeyTokenMapper */
24
-	private $mapper;
25
-
26
-	/** @var IDBConnection */
27
-	private $dbConnection;
28
-
29
-	/** @var int */
30
-	private $time;
31
-
32
-	protected function setUp(): void {
33
-		parent::setUp();
34
-
35
-		$this->dbConnection = Server::get(IDBConnection::class);
36
-		$this->time = time();
37
-		$this->resetDatabase();
38
-
39
-		$this->mapper = new PublicKeyTokenMapper($this->dbConnection);
40
-	}
41
-
42
-	private function resetDatabase() {
43
-		$qb = $this->dbConnection->getQueryBuilder();
44
-		$qb->delete('authtoken')->executeStatement();
45
-		$qb->insert('authtoken')->values([
46
-			'uid' => $qb->createNamedParameter('user1'),
47
-			'login_name' => $qb->createNamedParameter('User1'),
48
-			'password' => $qb->createNamedParameter('a75c7116460c082912d8f6860a850904|3nz5qbG1nNSLLi6V|c55365a0e54cfdfac4a175bcf11a7612aea74492277bba6e5d96a24497fa9272488787cb2f3ad34d8b9b8060934fce02f008d371df3ff3848f4aa61944851ff0'),
49
-			'name' => $qb->createNamedParameter('Firefox on Linux'),
50
-			'token' => $qb->createNamedParameter('9c5a2e661482b65597408a6bb6c4a3d1af36337381872ac56e445a06cdb7fea2b1039db707545c11027a4966919918b19d875a8b774840b18c6cbb7ae56fe206'),
51
-			'type' => $qb->createNamedParameter(IToken::TEMPORARY_TOKEN),
52
-			'last_activity' => $qb->createNamedParameter($this->time - 120, IQueryBuilder::PARAM_INT), // Two minutes ago
53
-			'last_check' => $this->time - 60 * 10, // 10mins ago
54
-			'public_key' => $qb->createNamedParameter('public key'),
55
-			'private_key' => $qb->createNamedParameter('private key'),
56
-			'version' => $qb->createNamedParameter(2),
57
-		])->executeStatement();
58
-		$qb->insert('authtoken')->values([
59
-			'uid' => $qb->createNamedParameter('user2'),
60
-			'login_name' => $qb->createNamedParameter('User2'),
61
-			'password' => $qb->createNamedParameter('971a337057853344700bbeccf836519f|UwOQwyb34sJHtqPV|036d4890f8c21d17bbc7b88072d8ef049a5c832a38e97f3e3d5f9186e896c2593aee16883f617322fa242728d0236ff32d163caeb4bd45e14ca002c57a88665f'),
62
-			'name' => $qb->createNamedParameter('Firefox on Android'),
63
-			'token' => $qb->createNamedParameter('1504445f1524fc801035448a95681a9378ba2e83930c814546c56e5d6ebde221198792fd900c88ed5ead0555780dad1ebce3370d7e154941cd5de87eb419899b'),
64
-			'type' => $qb->createNamedParameter(IToken::TEMPORARY_TOKEN),
65
-			'last_activity' => $qb->createNamedParameter($this->time - 60 * 60 * 24 * 3, IQueryBuilder::PARAM_INT), // Three days ago
66
-			'last_check' => $this->time - 10, // 10secs ago
67
-			'public_key' => $qb->createNamedParameter('public key'),
68
-			'private_key' => $qb->createNamedParameter('private key'),
69
-			'version' => $qb->createNamedParameter(2),
70
-		])->executeStatement();
71
-		$qb->insert('authtoken')->values([
72
-			'uid' => $qb->createNamedParameter('user1'),
73
-			'login_name' => $qb->createNamedParameter('User1'),
74
-			'password' => $qb->createNamedParameter('063de945d6f6b26862d9b6f40652f2d5|DZ/z520tfdXPtd0T|395f6b89be8d9d605e409e20b9d9abe477fde1be38a3223f9e508f979bf906e50d9eaa4dca983ca4fb22a241eb696c3f98654e7775f78c4caf13108f98642b53'),
75
-			'name' => $qb->createNamedParameter('Iceweasel on Linux'),
76
-			'token' => $qb->createNamedParameter('47af8697ba590fb82579b5f1b3b6e8066773a62100abbe0db09a289a62f5d980dc300fa3d98b01d7228468d1ab05c1aa14c8d14bd5b6eee9cdf1ac14864680c3'),
77
-			'type' => $qb->createNamedParameter(IToken::TEMPORARY_TOKEN),
78
-			'last_activity' => $qb->createNamedParameter($this->time - 120, IQueryBuilder::PARAM_INT), // Two minutes ago
79
-			'last_check' => $this->time - 60 * 10, // 10mins ago
80
-			'public_key' => $qb->createNamedParameter('public key'),
81
-			'private_key' => $qb->createNamedParameter('private key'),
82
-			'version' => $qb->createNamedParameter(2),
83
-		])->executeStatement();
84
-		$qb->insert('authtoken')->values([
85
-			'uid' => $qb->createNamedParameter('user3'),
86
-			'login_name' => $qb->createNamedParameter('User3'),
87
-			'password' => $qb->createNamedParameter('063de945d6f6b26862d9b6f40652f2d5|DZ/z520tfdXPtd0T|395f6b89be8d9d605e409e20b9d9abe477fde1be38a3223f9e508f979bf906e50d9eaa4dca983ca4fb22a241eb696c3f98654e7775f78c4caf13108f98642b53'),
88
-			'name' => $qb->createNamedParameter('Iceweasel on Linux'),
89
-			'token' => $qb->createNamedParameter('6d9a290d239d09f2cc33a03cc54cccd46f7dc71630dcc27d39214824bd3e093f1feb4e2b55eb159d204caa15dee9556c202a5aa0b9d67806c3f4ec2cde11af67'),
90
-			'type' => $qb->createNamedParameter(IToken::TEMPORARY_TOKEN),
91
-			'last_activity' => $qb->createNamedParameter($this->time - 120, IQueryBuilder::PARAM_INT), // Two minutes ago
92
-			'last_check' => $this->time - 60 * 10, // 10mins ago
93
-			'public_key' => $qb->createNamedParameter('public key'),
94
-			'private_key' => $qb->createNamedParameter('private key'),
95
-			'version' => $qb->createNamedParameter(2),
96
-			'password_invalid' => $qb->createNamedParameter(1),
97
-		])->executeStatement();
98
-		$qb->insert('authtoken')->values([
99
-			'uid' => $qb->createNamedParameter('user3'),
100
-			'login_name' => $qb->createNamedParameter('User3'),
101
-			'password' => $qb->createNamedParameter('063de945d6f6b26862d9b6f40652f2d5|DZ/z520tfdXPtd0T|395f6b89be8d9d605e409e20b9d9abe477fde1be38a3223f9e508f979bf906e50d9eaa4dca983ca4fb22a241eb696c3f98654e7775f78c4caf13108f98642b53'),
102
-			'name' => $qb->createNamedParameter('Iceweasel on Linux'),
103
-			'token' => $qb->createNamedParameter('84c5808c6445b6d65b8aa5b03840f09b27de603f0fb970906fb14ea4b115b7bf5ec53fada5c093fe46afdcd7bbc9617253a4d105f7dfb32719f9973d72412f31'),
104
-			'type' => $qb->createNamedParameter(IToken::PERMANENT_TOKEN),
105
-			'last_activity' => $qb->createNamedParameter($this->time - 60 * 3, IQueryBuilder::PARAM_INT), // Three minutes ago
106
-			'last_check' => $this->time - 60 * 10, // 10mins ago
107
-			'public_key' => $qb->createNamedParameter('public key'),
108
-			'private_key' => $qb->createNamedParameter('private key'),
109
-			'version' => $qb->createNamedParameter(2),
110
-			'password_invalid' => $qb->createNamedParameter(1),
111
-		])->executeStatement();
112
-	}
113
-
114
-	private function getNumberOfTokens() {
115
-		$qb = $this->dbConnection->getQueryBuilder();
116
-		$result = $qb->select($qb->func()->count('*', 'count'))
117
-			->from('authtoken')
118
-			->executeQuery()
119
-			->fetchAssociative();
120
-		return (int)$result['count'];
121
-	}
122
-
123
-	public function testInvalidate(): void {
124
-		$token = '9c5a2e661482b65597408a6bb6c4a3d1af36337381872ac56e445a06cdb7fea2b1039db707545c11027a4966919918b19d875a8b774840b18c6cbb7ae56fe206';
125
-
126
-		$this->mapper->invalidate($token);
127
-
128
-		$this->assertSame(4, $this->getNumberOfTokens());
129
-	}
130
-
131
-	public function testInvalidateInvalid(): void {
132
-		$token = 'youwontfindthisoneinthedatabase';
133
-
134
-		$this->mapper->invalidate($token);
135
-
136
-		$this->assertSame(5, $this->getNumberOfTokens());
137
-	}
138
-
139
-	public function testInvalidateOld(): void {
140
-		$olderThan = $this->time - 60 * 60; // One hour
141
-
142
-		$this->mapper->invalidateOld($olderThan);
143
-
144
-		$this->assertSame(4, $this->getNumberOfTokens());
145
-	}
146
-
147
-	public function testInvalidateLastUsedBefore(): void {
148
-		$before = $this->time - 60 * 2; // Two minutes
149
-
150
-		$this->mapper->invalidateLastUsedBefore('user3', $before);
151
-
152
-		$this->assertSame(4, $this->getNumberOfTokens());
153
-	}
154
-
155
-	public function testGetToken(): void {
156
-		$token = new PublicKeyToken();
157
-		$token->setUid('user2');
158
-		$token->setLoginName('User2');
159
-		$token->setPassword('971a337057853344700bbeccf836519f|UwOQwyb34sJHtqPV|036d4890f8c21d17bbc7b88072d8ef049a5c832a38e97f3e3d5f9186e896c2593aee16883f617322fa242728d0236ff32d163caeb4bd45e14ca002c57a88665f');
160
-		$token->setName('Firefox on Android');
161
-		$token->setToken('1504445f1524fc801035448a95681a9378ba2e83930c814546c56e5d6ebde221198792fd900c88ed5ead0555780dad1ebce3370d7e154941cd5de87eb419899b');
162
-		$token->setType(IToken::TEMPORARY_TOKEN);
163
-		$token->setRemember(IToken::DO_NOT_REMEMBER);
164
-		$token->setLastActivity($this->time - 60 * 60 * 24 * 3);
165
-		$token->setLastCheck($this->time - 10);
166
-		$token->setPublicKey('public key');
167
-		$token->setPrivateKey('private key');
168
-		$token->setVersion(PublicKeyToken::VERSION);
169
-
170
-		$dbToken = $this->mapper->getToken($token->getToken());
171
-
172
-		$token->setId($dbToken->getId()); // We don't know the ID
173
-		$token->resetUpdatedFields();
174
-
175
-		$this->assertEquals($token, $dbToken);
176
-	}
177
-
178
-
179
-	public function testGetInvalidToken(): void {
180
-		$this->expectException(DoesNotExistException::class);
181
-
182
-		$token = 'thisisaninvalidtokenthatisnotinthedatabase';
183
-
184
-		$this->mapper->getToken($token);
185
-	}
186
-
187
-	public function testGetTokenById(): void {
188
-		$token = new PublicKeyToken();
189
-		$token->setUid('user2');
190
-		$token->setLoginName('User2');
191
-		$token->setPassword('971a337057853344700bbeccf836519f|UwOQwyb34sJHtqPV|036d4890f8c21d17bbc7b88072d8ef049a5c832a38e97f3e3d5f9186e896c2593aee16883f617322fa242728d0236ff32d163caeb4bd45e14ca002c57a88665f');
192
-		$token->setName('Firefox on Android');
193
-		$token->setToken('1504445f1524fc801035448a95681a9378ba2e83930c814546c56e5d6ebde221198792fd900c88ed5ead0555780dad1ebce3370d7e154941cd5de87eb419899b');
194
-		$token->setType(IToken::TEMPORARY_TOKEN);
195
-		$token->setRemember(IToken::DO_NOT_REMEMBER);
196
-		$token->setLastActivity($this->time - 60 * 60 * 24 * 3);
197
-		$token->setLastCheck($this->time - 10);
198
-		$token->setPublicKey('public key');
199
-		$token->setPrivateKey('private key');
200
-		$token->setVersion(PublicKeyToken::VERSION);
201
-
202
-		$dbToken = $this->mapper->getToken($token->getToken());
203
-		$token->setId($dbToken->getId()); // We don't know the ID
204
-		$token->resetUpdatedFields();
205
-
206
-		$dbToken = $this->mapper->getTokenById($token->getId());
207
-		$this->assertEquals($token, $dbToken);
208
-	}
209
-
210
-
211
-	public function testGetTokenByIdNotFound(): void {
212
-		$this->expectException(DoesNotExistException::class);
23
+    /** @var PublicKeyTokenMapper */
24
+    private $mapper;
25
+
26
+    /** @var IDBConnection */
27
+    private $dbConnection;
28
+
29
+    /** @var int */
30
+    private $time;
31
+
32
+    protected function setUp(): void {
33
+        parent::setUp();
34
+
35
+        $this->dbConnection = Server::get(IDBConnection::class);
36
+        $this->time = time();
37
+        $this->resetDatabase();
38
+
39
+        $this->mapper = new PublicKeyTokenMapper($this->dbConnection);
40
+    }
41
+
42
+    private function resetDatabase() {
43
+        $qb = $this->dbConnection->getQueryBuilder();
44
+        $qb->delete('authtoken')->executeStatement();
45
+        $qb->insert('authtoken')->values([
46
+            'uid' => $qb->createNamedParameter('user1'),
47
+            'login_name' => $qb->createNamedParameter('User1'),
48
+            'password' => $qb->createNamedParameter('a75c7116460c082912d8f6860a850904|3nz5qbG1nNSLLi6V|c55365a0e54cfdfac4a175bcf11a7612aea74492277bba6e5d96a24497fa9272488787cb2f3ad34d8b9b8060934fce02f008d371df3ff3848f4aa61944851ff0'),
49
+            'name' => $qb->createNamedParameter('Firefox on Linux'),
50
+            'token' => $qb->createNamedParameter('9c5a2e661482b65597408a6bb6c4a3d1af36337381872ac56e445a06cdb7fea2b1039db707545c11027a4966919918b19d875a8b774840b18c6cbb7ae56fe206'),
51
+            'type' => $qb->createNamedParameter(IToken::TEMPORARY_TOKEN),
52
+            'last_activity' => $qb->createNamedParameter($this->time - 120, IQueryBuilder::PARAM_INT), // Two minutes ago
53
+            'last_check' => $this->time - 60 * 10, // 10mins ago
54
+            'public_key' => $qb->createNamedParameter('public key'),
55
+            'private_key' => $qb->createNamedParameter('private key'),
56
+            'version' => $qb->createNamedParameter(2),
57
+        ])->executeStatement();
58
+        $qb->insert('authtoken')->values([
59
+            'uid' => $qb->createNamedParameter('user2'),
60
+            'login_name' => $qb->createNamedParameter('User2'),
61
+            'password' => $qb->createNamedParameter('971a337057853344700bbeccf836519f|UwOQwyb34sJHtqPV|036d4890f8c21d17bbc7b88072d8ef049a5c832a38e97f3e3d5f9186e896c2593aee16883f617322fa242728d0236ff32d163caeb4bd45e14ca002c57a88665f'),
62
+            'name' => $qb->createNamedParameter('Firefox on Android'),
63
+            'token' => $qb->createNamedParameter('1504445f1524fc801035448a95681a9378ba2e83930c814546c56e5d6ebde221198792fd900c88ed5ead0555780dad1ebce3370d7e154941cd5de87eb419899b'),
64
+            'type' => $qb->createNamedParameter(IToken::TEMPORARY_TOKEN),
65
+            'last_activity' => $qb->createNamedParameter($this->time - 60 * 60 * 24 * 3, IQueryBuilder::PARAM_INT), // Three days ago
66
+            'last_check' => $this->time - 10, // 10secs ago
67
+            'public_key' => $qb->createNamedParameter('public key'),
68
+            'private_key' => $qb->createNamedParameter('private key'),
69
+            'version' => $qb->createNamedParameter(2),
70
+        ])->executeStatement();
71
+        $qb->insert('authtoken')->values([
72
+            'uid' => $qb->createNamedParameter('user1'),
73
+            'login_name' => $qb->createNamedParameter('User1'),
74
+            'password' => $qb->createNamedParameter('063de945d6f6b26862d9b6f40652f2d5|DZ/z520tfdXPtd0T|395f6b89be8d9d605e409e20b9d9abe477fde1be38a3223f9e508f979bf906e50d9eaa4dca983ca4fb22a241eb696c3f98654e7775f78c4caf13108f98642b53'),
75
+            'name' => $qb->createNamedParameter('Iceweasel on Linux'),
76
+            'token' => $qb->createNamedParameter('47af8697ba590fb82579b5f1b3b6e8066773a62100abbe0db09a289a62f5d980dc300fa3d98b01d7228468d1ab05c1aa14c8d14bd5b6eee9cdf1ac14864680c3'),
77
+            'type' => $qb->createNamedParameter(IToken::TEMPORARY_TOKEN),
78
+            'last_activity' => $qb->createNamedParameter($this->time - 120, IQueryBuilder::PARAM_INT), // Two minutes ago
79
+            'last_check' => $this->time - 60 * 10, // 10mins ago
80
+            'public_key' => $qb->createNamedParameter('public key'),
81
+            'private_key' => $qb->createNamedParameter('private key'),
82
+            'version' => $qb->createNamedParameter(2),
83
+        ])->executeStatement();
84
+        $qb->insert('authtoken')->values([
85
+            'uid' => $qb->createNamedParameter('user3'),
86
+            'login_name' => $qb->createNamedParameter('User3'),
87
+            'password' => $qb->createNamedParameter('063de945d6f6b26862d9b6f40652f2d5|DZ/z520tfdXPtd0T|395f6b89be8d9d605e409e20b9d9abe477fde1be38a3223f9e508f979bf906e50d9eaa4dca983ca4fb22a241eb696c3f98654e7775f78c4caf13108f98642b53'),
88
+            'name' => $qb->createNamedParameter('Iceweasel on Linux'),
89
+            'token' => $qb->createNamedParameter('6d9a290d239d09f2cc33a03cc54cccd46f7dc71630dcc27d39214824bd3e093f1feb4e2b55eb159d204caa15dee9556c202a5aa0b9d67806c3f4ec2cde11af67'),
90
+            'type' => $qb->createNamedParameter(IToken::TEMPORARY_TOKEN),
91
+            'last_activity' => $qb->createNamedParameter($this->time - 120, IQueryBuilder::PARAM_INT), // Two minutes ago
92
+            'last_check' => $this->time - 60 * 10, // 10mins ago
93
+            'public_key' => $qb->createNamedParameter('public key'),
94
+            'private_key' => $qb->createNamedParameter('private key'),
95
+            'version' => $qb->createNamedParameter(2),
96
+            'password_invalid' => $qb->createNamedParameter(1),
97
+        ])->executeStatement();
98
+        $qb->insert('authtoken')->values([
99
+            'uid' => $qb->createNamedParameter('user3'),
100
+            'login_name' => $qb->createNamedParameter('User3'),
101
+            'password' => $qb->createNamedParameter('063de945d6f6b26862d9b6f40652f2d5|DZ/z520tfdXPtd0T|395f6b89be8d9d605e409e20b9d9abe477fde1be38a3223f9e508f979bf906e50d9eaa4dca983ca4fb22a241eb696c3f98654e7775f78c4caf13108f98642b53'),
102
+            'name' => $qb->createNamedParameter('Iceweasel on Linux'),
103
+            'token' => $qb->createNamedParameter('84c5808c6445b6d65b8aa5b03840f09b27de603f0fb970906fb14ea4b115b7bf5ec53fada5c093fe46afdcd7bbc9617253a4d105f7dfb32719f9973d72412f31'),
104
+            'type' => $qb->createNamedParameter(IToken::PERMANENT_TOKEN),
105
+            'last_activity' => $qb->createNamedParameter($this->time - 60 * 3, IQueryBuilder::PARAM_INT), // Three minutes ago
106
+            'last_check' => $this->time - 60 * 10, // 10mins ago
107
+            'public_key' => $qb->createNamedParameter('public key'),
108
+            'private_key' => $qb->createNamedParameter('private key'),
109
+            'version' => $qb->createNamedParameter(2),
110
+            'password_invalid' => $qb->createNamedParameter(1),
111
+        ])->executeStatement();
112
+    }
113
+
114
+    private function getNumberOfTokens() {
115
+        $qb = $this->dbConnection->getQueryBuilder();
116
+        $result = $qb->select($qb->func()->count('*', 'count'))
117
+            ->from('authtoken')
118
+            ->executeQuery()
119
+            ->fetchAssociative();
120
+        return (int)$result['count'];
121
+    }
122
+
123
+    public function testInvalidate(): void {
124
+        $token = '9c5a2e661482b65597408a6bb6c4a3d1af36337381872ac56e445a06cdb7fea2b1039db707545c11027a4966919918b19d875a8b774840b18c6cbb7ae56fe206';
125
+
126
+        $this->mapper->invalidate($token);
127
+
128
+        $this->assertSame(4, $this->getNumberOfTokens());
129
+    }
130
+
131
+    public function testInvalidateInvalid(): void {
132
+        $token = 'youwontfindthisoneinthedatabase';
133
+
134
+        $this->mapper->invalidate($token);
135
+
136
+        $this->assertSame(5, $this->getNumberOfTokens());
137
+    }
138
+
139
+    public function testInvalidateOld(): void {
140
+        $olderThan = $this->time - 60 * 60; // One hour
141
+
142
+        $this->mapper->invalidateOld($olderThan);
143
+
144
+        $this->assertSame(4, $this->getNumberOfTokens());
145
+    }
146
+
147
+    public function testInvalidateLastUsedBefore(): void {
148
+        $before = $this->time - 60 * 2; // Two minutes
149
+
150
+        $this->mapper->invalidateLastUsedBefore('user3', $before);
151
+
152
+        $this->assertSame(4, $this->getNumberOfTokens());
153
+    }
154
+
155
+    public function testGetToken(): void {
156
+        $token = new PublicKeyToken();
157
+        $token->setUid('user2');
158
+        $token->setLoginName('User2');
159
+        $token->setPassword('971a337057853344700bbeccf836519f|UwOQwyb34sJHtqPV|036d4890f8c21d17bbc7b88072d8ef049a5c832a38e97f3e3d5f9186e896c2593aee16883f617322fa242728d0236ff32d163caeb4bd45e14ca002c57a88665f');
160
+        $token->setName('Firefox on Android');
161
+        $token->setToken('1504445f1524fc801035448a95681a9378ba2e83930c814546c56e5d6ebde221198792fd900c88ed5ead0555780dad1ebce3370d7e154941cd5de87eb419899b');
162
+        $token->setType(IToken::TEMPORARY_TOKEN);
163
+        $token->setRemember(IToken::DO_NOT_REMEMBER);
164
+        $token->setLastActivity($this->time - 60 * 60 * 24 * 3);
165
+        $token->setLastCheck($this->time - 10);
166
+        $token->setPublicKey('public key');
167
+        $token->setPrivateKey('private key');
168
+        $token->setVersion(PublicKeyToken::VERSION);
169
+
170
+        $dbToken = $this->mapper->getToken($token->getToken());
171
+
172
+        $token->setId($dbToken->getId()); // We don't know the ID
173
+        $token->resetUpdatedFields();
174
+
175
+        $this->assertEquals($token, $dbToken);
176
+    }
177
+
178
+
179
+    public function testGetInvalidToken(): void {
180
+        $this->expectException(DoesNotExistException::class);
181
+
182
+        $token = 'thisisaninvalidtokenthatisnotinthedatabase';
183
+
184
+        $this->mapper->getToken($token);
185
+    }
186
+
187
+    public function testGetTokenById(): void {
188
+        $token = new PublicKeyToken();
189
+        $token->setUid('user2');
190
+        $token->setLoginName('User2');
191
+        $token->setPassword('971a337057853344700bbeccf836519f|UwOQwyb34sJHtqPV|036d4890f8c21d17bbc7b88072d8ef049a5c832a38e97f3e3d5f9186e896c2593aee16883f617322fa242728d0236ff32d163caeb4bd45e14ca002c57a88665f');
192
+        $token->setName('Firefox on Android');
193
+        $token->setToken('1504445f1524fc801035448a95681a9378ba2e83930c814546c56e5d6ebde221198792fd900c88ed5ead0555780dad1ebce3370d7e154941cd5de87eb419899b');
194
+        $token->setType(IToken::TEMPORARY_TOKEN);
195
+        $token->setRemember(IToken::DO_NOT_REMEMBER);
196
+        $token->setLastActivity($this->time - 60 * 60 * 24 * 3);
197
+        $token->setLastCheck($this->time - 10);
198
+        $token->setPublicKey('public key');
199
+        $token->setPrivateKey('private key');
200
+        $token->setVersion(PublicKeyToken::VERSION);
201
+
202
+        $dbToken = $this->mapper->getToken($token->getToken());
203
+        $token->setId($dbToken->getId()); // We don't know the ID
204
+        $token->resetUpdatedFields();
205
+
206
+        $dbToken = $this->mapper->getTokenById($token->getId());
207
+        $this->assertEquals($token, $dbToken);
208
+    }
209
+
210
+
211
+    public function testGetTokenByIdNotFound(): void {
212
+        $this->expectException(DoesNotExistException::class);
213 213
 
214
-		$this->mapper->getTokenById(-1);
215
-	}
214
+        $this->mapper->getTokenById(-1);
215
+    }
216 216
 
217 217
 
218
-	public function testGetInvalidTokenById(): void {
219
-		$this->expectException(DoesNotExistException::class);
218
+    public function testGetInvalidTokenById(): void {
219
+        $this->expectException(DoesNotExistException::class);
220 220
 
221
-		$id = '42';
221
+        $id = '42';
222 222
 
223
-		$this->mapper->getToken($id);
224
-	}
223
+        $this->mapper->getToken($id);
224
+    }
225 225
 
226
-	public function testGetTokenByUser(): void {
227
-		$this->assertCount(2, $this->mapper->getTokenByUser('user1'));
228
-	}
226
+    public function testGetTokenByUser(): void {
227
+        $this->assertCount(2, $this->mapper->getTokenByUser('user1'));
228
+    }
229 229
 
230
-	public function testGetTokenByUserNotFound(): void {
231
-		$this->assertCount(0, $this->mapper->getTokenByUser('user1000'));
232
-	}
230
+    public function testGetTokenByUserNotFound(): void {
231
+        $this->assertCount(0, $this->mapper->getTokenByUser('user1000'));
232
+    }
233 233
 
234
-	public function testGetById(): void {
235
-		/** @var IUser|\PHPUnit\Framework\MockObject\MockObject $user */
236
-		$user = $this->createMock(IUser::class);
237
-		$qb = $this->dbConnection->getQueryBuilder();
238
-		$qb->select('id')
239
-			->from('authtoken')
240
-			->where($qb->expr()->eq('token', $qb->createNamedParameter('9c5a2e661482b65597408a6bb6c4a3d1af36337381872ac56e445a06cdb7fea2b1039db707545c11027a4966919918b19d875a8b774840b18c6cbb7ae56fe206')));
241
-		$result = $qb->executeQuery();
242
-		$id = $result->fetchAssociative()['id'];
243
-
244
-		$token = $this->mapper->getTokenById((int)$id);
245
-		$this->assertEquals('user1', $token->getUID());
246
-	}
247
-
248
-	public function testDeleteByName(): void {
249
-		$qb = $this->dbConnection->getQueryBuilder();
250
-		$qb->select('name')
251
-			->from('authtoken')
252
-			->where($qb->expr()->eq('token', $qb->createNamedParameter('9c5a2e661482b65597408a6bb6c4a3d1af36337381872ac56e445a06cdb7fea2b1039db707545c11027a4966919918b19d875a8b774840b18c6cbb7ae56fe206')));
253
-		$result = $qb->executeQuery();
254
-		$name = $result->fetchAssociative()['name'];
255
-		$this->mapper->deleteByName($name);
256
-		$this->assertEquals(4, $this->getNumberOfTokens());
257
-	}
258
-
259
-	public function testHasExpiredTokens(): void {
260
-		$this->assertFalse($this->mapper->hasExpiredTokens('user1'));
261
-		$this->assertTrue($this->mapper->hasExpiredTokens('user3'));
262
-	}
234
+    public function testGetById(): void {
235
+        /** @var IUser|\PHPUnit\Framework\MockObject\MockObject $user */
236
+        $user = $this->createMock(IUser::class);
237
+        $qb = $this->dbConnection->getQueryBuilder();
238
+        $qb->select('id')
239
+            ->from('authtoken')
240
+            ->where($qb->expr()->eq('token', $qb->createNamedParameter('9c5a2e661482b65597408a6bb6c4a3d1af36337381872ac56e445a06cdb7fea2b1039db707545c11027a4966919918b19d875a8b774840b18c6cbb7ae56fe206')));
241
+        $result = $qb->executeQuery();
242
+        $id = $result->fetchAssociative()['id'];
243
+
244
+        $token = $this->mapper->getTokenById((int)$id);
245
+        $this->assertEquals('user1', $token->getUID());
246
+    }
247
+
248
+    public function testDeleteByName(): void {
249
+        $qb = $this->dbConnection->getQueryBuilder();
250
+        $qb->select('name')
251
+            ->from('authtoken')
252
+            ->where($qb->expr()->eq('token', $qb->createNamedParameter('9c5a2e661482b65597408a6bb6c4a3d1af36337381872ac56e445a06cdb7fea2b1039db707545c11027a4966919918b19d875a8b774840b18c6cbb7ae56fe206')));
253
+        $result = $qb->executeQuery();
254
+        $name = $result->fetchAssociative()['name'];
255
+        $this->mapper->deleteByName($name);
256
+        $this->assertEquals(4, $this->getNumberOfTokens());
257
+    }
258
+
259
+    public function testHasExpiredTokens(): void {
260
+        $this->assertFalse($this->mapper->hasExpiredTokens('user1'));
261
+        $this->assertTrue($this->mapper->hasExpiredTokens('user3'));
262
+    }
263 263
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -117,7 +117,7 @@  discard block
 block discarded – undo
117 117
 			->from('authtoken')
118 118
 			->executeQuery()
119 119
 			->fetchAssociative();
120
-		return (int)$result['count'];
120
+		return (int) $result['count'];
121 121
 	}
122 122
 
123 123
 	public function testInvalidate(): void {
@@ -241,7 +241,7 @@  discard block
 block discarded – undo
241 241
 		$result = $qb->executeQuery();
242 242
 		$id = $result->fetchAssociative()['id'];
243 243
 
244
-		$token = $this->mapper->getTokenById((int)$id);
244
+		$token = $this->mapper->getTokenById((int) $id);
245 245
 		$this->assertEquals('user1', $token->getUID());
246 246
 	}
247 247
 
Please login to merge, or discard this patch.
tests/lib/DB/AdapterTest.php 1 patch
Indentation   +190 added lines, -190 removed lines patch added patch discarded remove patch
@@ -12,194 +12,194 @@
 block discarded – undo
12 12
 use Test\TestCase;
13 13
 
14 14
 class AdapterTest extends TestCase {
15
-	private string $appId;
16
-	private $connection;
17
-
18
-	public function setUp(): void {
19
-		$this->connection = Server::get(IDBConnection::class);
20
-		$this->appId = substr(uniqid('test_db_adapter', true), 0, 32);
21
-	}
22
-
23
-	public function tearDown(): void {
24
-		$qb = $this->connection->getQueryBuilder();
25
-
26
-		$qb->delete('appconfig')
27
-			->from('appconfig')
28
-			->where($qb->expr()->eq('appid', $qb->createNamedParameter($this->appId)))
29
-			->executeStatement();
30
-	}
31
-
32
-	public function testInsertIgnoreOnConflictDuplicate(): void {
33
-		$configKey = uniqid('key', true);
34
-		$expected = [
35
-			[
36
-				'configkey' => $configKey,
37
-				'configvalue' => '1',
38
-			]
39
-		];
40
-		$result = $this->connection->insertIgnoreConflict('appconfig', [
41
-			'appid' => $this->appId,
42
-			'configkey' => $configKey,
43
-			'configvalue' => '1',
44
-		]);
45
-		$this->assertEquals(1, $result);
46
-		$rows = $this->getRows($configKey);
47
-		$this->assertSame($expected, $rows);
48
-
49
-
50
-		$result = $this->connection->insertIgnoreConflict('appconfig', [
51
-			'appid' => $this->appId,
52
-			'configkey' => $configKey,
53
-			'configvalue' => '2',
54
-		]);
55
-		$this->assertEquals(0, $result);
56
-		$rows = $this->getRows($configKey);
57
-		$this->assertSame($expected, $rows);
58
-	}
59
-
60
-	private function getRows(string $configKey): array {
61
-		$qb = $this->connection->getQueryBuilder();
62
-		return $qb->select(['configkey', 'configvalue'])
63
-			->from('appconfig')
64
-			->where($qb->expr()->eq('appid', $qb->createNamedParameter($this->appId)))
65
-			->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($configKey)))
66
-			->executeQuery()
67
-			->fetchAllAssociative();
68
-	}
69
-
70
-	public function fetchAssociative(): void {
71
-		$insert = $this->connection->getQueryBuilder();
72
-		$insert->insert('appconfig')
73
-			->values([
74
-				'appid' => $this->appId,
75
-				'configkey' => 'test',
76
-				'configvalue' => '1',
77
-			])
78
-			->executeStatement();
79
-
80
-		// fetch all associative
81
-		$qb = $this->connection->getQueryBuilder();
82
-		$result = $qb->select(['configkey', 'configvalue', 'appid'])
83
-			->from('appconfig')
84
-			->executeQuery();
85
-
86
-		$rows = $result->fetchAllAssociative();
87
-		$this->assertEquals([
88
-			[
89
-				'appid' => $this->appId,
90
-				'configkey' => 'test',
91
-				'configvalue' => '1',
92
-			]
93
-		], $rows);
94
-
95
-		// fetch associative
96
-		$qb = $this->connection->getQueryBuilder();
97
-		$result = $qb->select(['configkey', 'configvalue', 'appid'])
98
-			->from('appconfig')
99
-			->executeQuery();
100
-		$row = $result->fetchAssociative();
101
-		$this->assertEquals([
102
-			'appid' => $this->appId,
103
-			'configkey' => 'test',
104
-			'configvalue' => '1',
105
-		], $row);
106
-
107
-		// iterate associative
108
-		$qb = $this->connection->getQueryBuilder();
109
-		$result = $qb->select(['configkey', 'configvalue', 'appid'])
110
-			->from('appconfig')
111
-			->executeQuery();
112
-		$row = iterator_to_array($result->iterateAssociative());
113
-		$this->assertEquals([
114
-			'appid' => $this->appId,
115
-			'configkey' => 'test',
116
-			'configvalue' => '1',
117
-		], $row);
118
-	}
119
-
120
-	public function fetchNumeric(): void {
121
-		$insert = $this->connection->getQueryBuilder();
122
-		$insert->insert('appconfig')
123
-			->values([
124
-				'appid' => $this->appId,
125
-				'configkey' => 'test',
126
-				'configvalue' => '1',
127
-			])
128
-			->executeStatement();
129
-
130
-		// fetch all associative
131
-		$qb = $this->connection->getQueryBuilder();
132
-		$result = $qb->select(['configkey', 'configvalue', 'appid'])
133
-			->from('appconfig')
134
-			->executeQuery();
135
-
136
-		$rows = $result->fetchAllNumeric();
137
-		$this->assertEquals([
138
-			[
139
-				0 => $this->appId,
140
-				1 => 'test',
141
-				2 => '1',
142
-			]
143
-		], $rows);
144
-
145
-		// fetch associative
146
-		$qb = $this->connection->getQueryBuilder();
147
-		$result = $qb->select(['configkey', 'configvalue', 'appid'])
148
-			->from('appconfig')
149
-			->executeQuery();
150
-		$row = $result->fetchNumeric();
151
-		$this->assertEquals([
152
-			0 => $this->appId,
153
-			1 => 'test',
154
-			2 => '1',
155
-		], $row);
156
-
157
-		// iterate associative
158
-		$qb = $this->connection->getQueryBuilder();
159
-		$result = $qb->select(['configkey', 'configvalue', 'appid'])
160
-			->from('appconfig')
161
-			->executeQuery();
162
-		$row = iterator_to_array($result->iterateNumeric());
163
-		$this->assertEquals([
164
-			0 => $this->appId,
165
-			1 => 'test',
166
-			2 => '1',
167
-		], $row);
168
-	}
169
-
170
-	public function fetchOne(): void {
171
-		$insert = $this->connection->getQueryBuilder();
172
-		$insert->insert('appconfig')
173
-			->values([
174
-				'appid' => $this->appId,
175
-				'configkey' => 'test',
176
-				'configvalue' => '1',
177
-			])
178
-			->executeStatement();
179
-
180
-		// fetch all associative
181
-		$qb = $this->connection->getQueryBuilder();
182
-		$result = $qb->select(['configkey', 'configvalue', 'appid'])
183
-			->from('appconfig')
184
-			->executeQuery();
185
-
186
-		$rows = $result->fetchFirstColumn();
187
-		$this->assertEquals($this->appId, $rows);
188
-
189
-		// fetch associative
190
-		$qb = $this->connection->getQueryBuilder();
191
-		$result = $qb->select(['configkey', 'configvalue', 'appid'])
192
-			->from('appconfig')
193
-			->executeQuery();
194
-		$row = $result->fetchFirstColumn();
195
-		$this->assertEquals($this->appId, $row);
196
-
197
-		// iterate associative
198
-		$qb = $this->connection->getQueryBuilder();
199
-		$result = $qb->select(['configkey', 'configvalue', 'appid'])
200
-			->from('appconfig')
201
-			->executeQuery();
202
-		$rows = iterator_to_array($result->iterateNumeric());
203
-		$this->assertEquals([$this->appId], $rows);
204
-	}
15
+    private string $appId;
16
+    private $connection;
17
+
18
+    public function setUp(): void {
19
+        $this->connection = Server::get(IDBConnection::class);
20
+        $this->appId = substr(uniqid('test_db_adapter', true), 0, 32);
21
+    }
22
+
23
+    public function tearDown(): void {
24
+        $qb = $this->connection->getQueryBuilder();
25
+
26
+        $qb->delete('appconfig')
27
+            ->from('appconfig')
28
+            ->where($qb->expr()->eq('appid', $qb->createNamedParameter($this->appId)))
29
+            ->executeStatement();
30
+    }
31
+
32
+    public function testInsertIgnoreOnConflictDuplicate(): void {
33
+        $configKey = uniqid('key', true);
34
+        $expected = [
35
+            [
36
+                'configkey' => $configKey,
37
+                'configvalue' => '1',
38
+            ]
39
+        ];
40
+        $result = $this->connection->insertIgnoreConflict('appconfig', [
41
+            'appid' => $this->appId,
42
+            'configkey' => $configKey,
43
+            'configvalue' => '1',
44
+        ]);
45
+        $this->assertEquals(1, $result);
46
+        $rows = $this->getRows($configKey);
47
+        $this->assertSame($expected, $rows);
48
+
49
+
50
+        $result = $this->connection->insertIgnoreConflict('appconfig', [
51
+            'appid' => $this->appId,
52
+            'configkey' => $configKey,
53
+            'configvalue' => '2',
54
+        ]);
55
+        $this->assertEquals(0, $result);
56
+        $rows = $this->getRows($configKey);
57
+        $this->assertSame($expected, $rows);
58
+    }
59
+
60
+    private function getRows(string $configKey): array {
61
+        $qb = $this->connection->getQueryBuilder();
62
+        return $qb->select(['configkey', 'configvalue'])
63
+            ->from('appconfig')
64
+            ->where($qb->expr()->eq('appid', $qb->createNamedParameter($this->appId)))
65
+            ->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($configKey)))
66
+            ->executeQuery()
67
+            ->fetchAllAssociative();
68
+    }
69
+
70
+    public function fetchAssociative(): void {
71
+        $insert = $this->connection->getQueryBuilder();
72
+        $insert->insert('appconfig')
73
+            ->values([
74
+                'appid' => $this->appId,
75
+                'configkey' => 'test',
76
+                'configvalue' => '1',
77
+            ])
78
+            ->executeStatement();
79
+
80
+        // fetch all associative
81
+        $qb = $this->connection->getQueryBuilder();
82
+        $result = $qb->select(['configkey', 'configvalue', 'appid'])
83
+            ->from('appconfig')
84
+            ->executeQuery();
85
+
86
+        $rows = $result->fetchAllAssociative();
87
+        $this->assertEquals([
88
+            [
89
+                'appid' => $this->appId,
90
+                'configkey' => 'test',
91
+                'configvalue' => '1',
92
+            ]
93
+        ], $rows);
94
+
95
+        // fetch associative
96
+        $qb = $this->connection->getQueryBuilder();
97
+        $result = $qb->select(['configkey', 'configvalue', 'appid'])
98
+            ->from('appconfig')
99
+            ->executeQuery();
100
+        $row = $result->fetchAssociative();
101
+        $this->assertEquals([
102
+            'appid' => $this->appId,
103
+            'configkey' => 'test',
104
+            'configvalue' => '1',
105
+        ], $row);
106
+
107
+        // iterate associative
108
+        $qb = $this->connection->getQueryBuilder();
109
+        $result = $qb->select(['configkey', 'configvalue', 'appid'])
110
+            ->from('appconfig')
111
+            ->executeQuery();
112
+        $row = iterator_to_array($result->iterateAssociative());
113
+        $this->assertEquals([
114
+            'appid' => $this->appId,
115
+            'configkey' => 'test',
116
+            'configvalue' => '1',
117
+        ], $row);
118
+    }
119
+
120
+    public function fetchNumeric(): void {
121
+        $insert = $this->connection->getQueryBuilder();
122
+        $insert->insert('appconfig')
123
+            ->values([
124
+                'appid' => $this->appId,
125
+                'configkey' => 'test',
126
+                'configvalue' => '1',
127
+            ])
128
+            ->executeStatement();
129
+
130
+        // fetch all associative
131
+        $qb = $this->connection->getQueryBuilder();
132
+        $result = $qb->select(['configkey', 'configvalue', 'appid'])
133
+            ->from('appconfig')
134
+            ->executeQuery();
135
+
136
+        $rows = $result->fetchAllNumeric();
137
+        $this->assertEquals([
138
+            [
139
+                0 => $this->appId,
140
+                1 => 'test',
141
+                2 => '1',
142
+            ]
143
+        ], $rows);
144
+
145
+        // fetch associative
146
+        $qb = $this->connection->getQueryBuilder();
147
+        $result = $qb->select(['configkey', 'configvalue', 'appid'])
148
+            ->from('appconfig')
149
+            ->executeQuery();
150
+        $row = $result->fetchNumeric();
151
+        $this->assertEquals([
152
+            0 => $this->appId,
153
+            1 => 'test',
154
+            2 => '1',
155
+        ], $row);
156
+
157
+        // iterate associative
158
+        $qb = $this->connection->getQueryBuilder();
159
+        $result = $qb->select(['configkey', 'configvalue', 'appid'])
160
+            ->from('appconfig')
161
+            ->executeQuery();
162
+        $row = iterator_to_array($result->iterateNumeric());
163
+        $this->assertEquals([
164
+            0 => $this->appId,
165
+            1 => 'test',
166
+            2 => '1',
167
+        ], $row);
168
+    }
169
+
170
+    public function fetchOne(): void {
171
+        $insert = $this->connection->getQueryBuilder();
172
+        $insert->insert('appconfig')
173
+            ->values([
174
+                'appid' => $this->appId,
175
+                'configkey' => 'test',
176
+                'configvalue' => '1',
177
+            ])
178
+            ->executeStatement();
179
+
180
+        // fetch all associative
181
+        $qb = $this->connection->getQueryBuilder();
182
+        $result = $qb->select(['configkey', 'configvalue', 'appid'])
183
+            ->from('appconfig')
184
+            ->executeQuery();
185
+
186
+        $rows = $result->fetchFirstColumn();
187
+        $this->assertEquals($this->appId, $rows);
188
+
189
+        // fetch associative
190
+        $qb = $this->connection->getQueryBuilder();
191
+        $result = $qb->select(['configkey', 'configvalue', 'appid'])
192
+            ->from('appconfig')
193
+            ->executeQuery();
194
+        $row = $result->fetchFirstColumn();
195
+        $this->assertEquals($this->appId, $row);
196
+
197
+        // iterate associative
198
+        $qb = $this->connection->getQueryBuilder();
199
+        $result = $qb->select(['configkey', 'configvalue', 'appid'])
200
+            ->from('appconfig')
201
+            ->executeQuery();
202
+        $rows = iterator_to_array($result->iterateNumeric());
203
+        $this->assertEquals([$this->appId], $rows);
204
+    }
205 205
 }
Please login to merge, or discard this patch.
tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php 1 patch
Indentation   +404 added lines, -404 removed lines patch added patch discarded remove patch
@@ -24,408 +24,408 @@
 block discarded – undo
24 24
  */
25 25
 #[\PHPUnit\Framework\Attributes\Group('DB')]
26 26
 class ExpressionBuilderTest extends TestCase {
27
-	/** @var ExpressionBuilder */
28
-	protected $expressionBuilder;
29
-
30
-	/** @var DoctrineExpressionBuilder */
31
-	protected $doctrineExpressionBuilder;
32
-
33
-	/** @var IDBConnection */
34
-	protected $connection;
35
-
36
-	/** @var \Doctrine\DBAL\Connection */
37
-	protected $internalConnection;
38
-
39
-	/** @var LoggerInterface */
40
-	protected $logger;
41
-
42
-	protected function setUp(): void {
43
-		parent::setUp();
44
-
45
-		$this->connection = Server::get(IDBConnection::class);
46
-		$this->internalConnection = Server::get(\OC\DB\Connection::class);
47
-		$this->logger = $this->createMock(LoggerInterface::class);
48
-
49
-		$queryBuilder = $this->createMock(IQueryBuilder::class);
50
-
51
-		$this->expressionBuilder = new ExpressionBuilder($this->connection, $queryBuilder, $this->logger);
52
-
53
-		$this->doctrineExpressionBuilder = new DoctrineExpressionBuilder($this->internalConnection);
54
-	}
55
-
56
-	public static function dataComparison(): array {
57
-		$valueSets = self::dataComparisons();
58
-		$comparisonOperators = ['=', '<>', '<', '>', '<=', '>='];
59
-
60
-		$testSets = [];
61
-		foreach ($comparisonOperators as $operator) {
62
-			foreach ($valueSets as $values) {
63
-				$testSets[] = array_merge([$operator], $values);
64
-			}
65
-		}
66
-		return $testSets;
67
-	}
68
-
69
-	/**
70
-	 *
71
-	 * @param string $comparison
72
-	 * @param mixed $input1
73
-	 * @param bool $isInput1Literal
74
-	 * @param mixed $input2
75
-	 * @param bool $isInput2Literal
76
-	 */
77
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataComparison')]
78
-	public function testComparison($comparison, $input1, $isInput1Literal, $input2, $isInput2Literal): void {
79
-		[$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
80
-		[$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
81
-
82
-		$this->assertEquals(
83
-			$this->doctrineExpressionBuilder->comparison($doctrineInput1, $comparison, $doctrineInput2),
84
-			$this->expressionBuilder->comparison($ocInput1, $comparison, $ocInput2)
85
-		);
86
-	}
87
-
88
-	public static function dataComparisons(): array {
89
-		return [
90
-			['value', false, 'value', false],
91
-			['value', false, 'value', true],
92
-			['value', true, 'value', false],
93
-			['value', true, 'value', true],
94
-		];
95
-	}
96
-
97
-	/**
98
-	 *
99
-	 * @param mixed $input1
100
-	 * @param bool $isInput1Literal
101
-	 * @param mixed $input2
102
-	 * @param bool $isInput2Literal
103
-	 */
104
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
105
-	public function testEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void {
106
-		[$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
107
-		[$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
108
-
109
-		$this->assertEquals(
110
-			$this->doctrineExpressionBuilder->eq($doctrineInput1, $doctrineInput2),
111
-			$this->expressionBuilder->eq($ocInput1, $ocInput2)
112
-		);
113
-	}
114
-
115
-	/**
116
-	 *
117
-	 * @param mixed $input1
118
-	 * @param bool $isInput1Literal
119
-	 * @param mixed $input2
120
-	 * @param bool $isInput2Literal
121
-	 */
122
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
123
-	public function testNotEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void {
124
-		[$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
125
-		[$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
126
-
127
-		$this->assertEquals(
128
-			$this->doctrineExpressionBuilder->neq($doctrineInput1, $doctrineInput2),
129
-			$this->expressionBuilder->neq($ocInput1, $ocInput2)
130
-		);
131
-	}
132
-
133
-	/**
134
-	 *
135
-	 * @param mixed $input1
136
-	 * @param bool $isInput1Literal
137
-	 * @param mixed $input2
138
-	 * @param bool $isInput2Literal
139
-	 */
140
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
141
-	public function testLowerThan($input1, $isInput1Literal, $input2, $isInput2Literal): void {
142
-		[$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
143
-		[$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
144
-
145
-		$this->assertEquals(
146
-			$this->doctrineExpressionBuilder->lt($doctrineInput1, $doctrineInput2),
147
-			$this->expressionBuilder->lt($ocInput1, $ocInput2)
148
-		);
149
-	}
150
-
151
-	/**
152
-	 *
153
-	 * @param mixed $input1
154
-	 * @param bool $isInput1Literal
155
-	 * @param mixed $input2
156
-	 * @param bool $isInput2Literal
157
-	 */
158
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
159
-	public function testLowerThanEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void {
160
-		[$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
161
-		[$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
162
-
163
-		$this->assertEquals(
164
-			$this->doctrineExpressionBuilder->lte($doctrineInput1, $doctrineInput2),
165
-			$this->expressionBuilder->lte($ocInput1, $ocInput2)
166
-		);
167
-	}
168
-
169
-	/**
170
-	 *
171
-	 * @param mixed $input1
172
-	 * @param bool $isInput1Literal
173
-	 * @param mixed $input2
174
-	 * @param bool $isInput2Literal
175
-	 */
176
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
177
-	public function testGreaterThan($input1, $isInput1Literal, $input2, $isInput2Literal): void {
178
-		[$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
179
-		[$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
180
-
181
-		$this->assertEquals(
182
-			$this->doctrineExpressionBuilder->gt($doctrineInput1, $doctrineInput2),
183
-			$this->expressionBuilder->gt($ocInput1, $ocInput2)
184
-		);
185
-	}
186
-
187
-	/**
188
-	 *
189
-	 * @param mixed $input1
190
-	 * @param bool $isInput1Literal
191
-	 * @param mixed $input2
192
-	 * @param bool $isInput2Literal
193
-	 */
194
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
195
-	public function testGreaterThanEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void {
196
-		[$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
197
-		[$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
198
-
199
-		$this->assertEquals(
200
-			$this->doctrineExpressionBuilder->gte($doctrineInput1, $doctrineInput2),
201
-			$this->expressionBuilder->gte($ocInput1, $ocInput2)
202
-		);
203
-	}
204
-
205
-	public function testIsNull(): void {
206
-		$this->assertEquals(
207
-			$this->doctrineExpressionBuilder->isNull('`test`'),
208
-			$this->expressionBuilder->isNull('test')
209
-		);
210
-	}
211
-
212
-	public function testIsNotNull(): void {
213
-		$this->assertEquals(
214
-			$this->doctrineExpressionBuilder->isNotNull('`test`'),
215
-			$this->expressionBuilder->isNotNull('test')
216
-		);
217
-	}
218
-
219
-	public static function dataLike(): array {
220
-		return [
221
-			['value', false],
222
-			['value', true],
223
-		];
224
-	}
225
-
226
-	/**
227
-	 *
228
-	 * @param mixed $input
229
-	 * @param bool $isLiteral
230
-	 */
231
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataLike')]
232
-	public function testLike($input, $isLiteral): void {
233
-		[$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral);
234
-
235
-		$this->assertEquals(
236
-			$this->doctrineExpressionBuilder->like('`test`', $doctrineInput),
237
-			$this->expressionBuilder->like('test', $ocInput)
238
-		);
239
-	}
240
-
241
-	/**
242
-	 *
243
-	 * @param mixed $input
244
-	 * @param bool $isLiteral
245
-	 */
246
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataLike')]
247
-	public function testNotLike($input, $isLiteral): void {
248
-		[$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral);
249
-
250
-		$this->assertEquals(
251
-			$this->doctrineExpressionBuilder->notLike('`test`', $doctrineInput),
252
-			$this->expressionBuilder->notLike('test', $ocInput)
253
-		);
254
-	}
255
-
256
-	public static function dataIn(): array {
257
-		return [
258
-			['value', false],
259
-			['value', true],
260
-			[['value'], false],
261
-			[['value'], true],
262
-		];
263
-	}
264
-
265
-	/**
266
-	 *
267
-	 * @param mixed $input
268
-	 * @param bool $isLiteral
269
-	 */
270
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataIn')]
271
-	public function testIn($input, $isLiteral): void {
272
-		[$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral);
273
-
274
-		$this->assertEquals(
275
-			$this->doctrineExpressionBuilder->in('`test`', $doctrineInput),
276
-			$this->expressionBuilder->in('test', $ocInput)
277
-		);
278
-	}
279
-
280
-	/**
281
-	 *
282
-	 * @param mixed $input
283
-	 * @param bool $isLiteral
284
-	 */
285
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataIn')]
286
-	public function testNotIn($input, $isLiteral): void {
287
-		[$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral);
288
-
289
-		$this->assertEquals(
290
-			$this->doctrineExpressionBuilder->notIn('`test`', $doctrineInput),
291
-			$this->expressionBuilder->notIn('test', $ocInput)
292
-		);
293
-	}
294
-
295
-	protected function helpWithLiteral($input, $isLiteral) {
296
-		if ($isLiteral) {
297
-			if (is_array($input)) {
298
-				$doctrineInput = array_map(function ($ident) {
299
-					return $this->doctrineExpressionBuilder->literal($ident);
300
-				}, $input);
301
-				$ocInput = array_map(function ($ident) {
302
-					return $this->expressionBuilder->literal($ident);
303
-				}, $input);
304
-			} else {
305
-				$doctrineInput = $this->doctrineExpressionBuilder->literal($input);
306
-				$ocInput = $this->expressionBuilder->literal($input);
307
-			}
308
-		} else {
309
-			if (is_array($input)) {
310
-				$doctrineInput = array_map(function ($input) {
311
-					return '`' . $input . '`';
312
-				}, $input);
313
-				$ocInput = $input;
314
-			} else {
315
-				$doctrineInput = '`' . $input . '`';
316
-				$ocInput = $input;
317
-			}
318
-		}
319
-
320
-		return [$doctrineInput, $ocInput];
321
-	}
322
-
323
-	public static function dataLiteral(): array {
324
-		return [
325
-			['value', null],
326
-			['1', null],
327
-			[1, null],
328
-			[1, 'string'],
329
-			[1, 'integer'],
330
-			[1, IQueryBuilder::PARAM_INT],
331
-		];
332
-	}
333
-
334
-	/**
335
-	 *
336
-	 * @param mixed $input
337
-	 * @param string|null $type
338
-	 */
339
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataLiteral')]
340
-	public function testLiteral($input, $type): void {
341
-		/** @var \OC\DB\QueryBuilder\Literal $actual */
342
-		$actual = $this->expressionBuilder->literal($input, $type);
343
-
344
-		$this->assertInstanceOf('\OC\DB\QueryBuilder\Literal', $actual);
345
-		$this->assertEquals(
346
-			$this->doctrineExpressionBuilder->literal($input, $type),
347
-			$actual->__toString()
348
-		);
349
-	}
350
-
351
-	public static function dataClobComparisons(): array {
352
-		return [
353
-			['eq', '5', IQueryBuilder::PARAM_STR, false, 3],
354
-			['eq', '5', IQueryBuilder::PARAM_STR, true, 1],
355
-			['neq', '5', IQueryBuilder::PARAM_STR, false, 8],
356
-			['neq', '5', IQueryBuilder::PARAM_STR, true, 6],
357
-			['lt', '5', IQueryBuilder::PARAM_STR, false, 3],
358
-			['lt', '5', IQueryBuilder::PARAM_STR, true, 1],
359
-			['lte', '5', IQueryBuilder::PARAM_STR, false, 6],
360
-			['lte', '5', IQueryBuilder::PARAM_STR, true, 4],
361
-			['gt', '5', IQueryBuilder::PARAM_STR, false, 5],
362
-			['gt', '5', IQueryBuilder::PARAM_STR, true, 1],
363
-			['gte', '5', IQueryBuilder::PARAM_STR, false, 8],
364
-			['gte', '5', IQueryBuilder::PARAM_STR, true, 4],
365
-			['like', '%5%', IQueryBuilder::PARAM_STR, false, 3],
366
-			['like', '%5%', IQueryBuilder::PARAM_STR, true, 1],
367
-			['like', 'under_%', IQueryBuilder::PARAM_STR, false, 2],
368
-			['like', 'under\_%', IQueryBuilder::PARAM_STR, false, 1],
369
-			['notLike', '%5%', IQueryBuilder::PARAM_STR, false, 8],
370
-			['notLike', '%5%', IQueryBuilder::PARAM_STR, true, 6],
371
-			['in', ['5'], IQueryBuilder::PARAM_STR_ARRAY, false, 3],
372
-			['in', ['5'], IQueryBuilder::PARAM_STR_ARRAY, true, 1],
373
-			['notIn', ['5'], IQueryBuilder::PARAM_STR_ARRAY, false, 8],
374
-			['notIn', ['5'], IQueryBuilder::PARAM_STR_ARRAY, true, 6],
375
-		];
376
-	}
377
-
378
-	/**
379
-	 * @param string $function
380
-	 * @param mixed $value
381
-	 * @param mixed $type
382
-	 * @param bool $compareKeyToValue
383
-	 * @param int $expected
384
-	 */
385
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataClobComparisons')]
386
-	public function testClobComparisons($function, $value, $type, $compareKeyToValue, $expected): void {
387
-		$appId = $this->getUniqueID('testing');
388
-		$this->createConfig($appId, 1, 4);
389
-		$this->createConfig($appId, 2, 5);
390
-		$this->createConfig($appId, 3, 6);
391
-		$this->createConfig($appId, 4, 4);
392
-		$this->createConfig($appId, 5, 5);
393
-		$this->createConfig($appId, 6, 6);
394
-		$this->createConfig($appId, 7, 4);
395
-		$this->createConfig($appId, 8, 5);
396
-		$this->createConfig($appId, 9, 6);
397
-		$this->createConfig($appId, 10, 'under_score');
398
-		$this->createConfig($appId, 11, 'underscore');
399
-
400
-		$query = $this->connection->getQueryBuilder();
401
-		$query->select($query->func()->count('*', 'count'))
402
-			->from('appconfig')
403
-			->where($query->expr()->eq('appid', $query->createNamedParameter($appId)))
404
-			->andWhere(call_user_func([$query->expr(), $function], 'configvalue', $query->createNamedParameter($value, $type), IQueryBuilder::PARAM_STR));
405
-
406
-		if ($compareKeyToValue) {
407
-			$query->andWhere(call_user_func([$query->expr(), $function], 'configkey', 'configvalue', IQueryBuilder::PARAM_STR));
408
-		}
409
-
410
-		$result = $query->executeQuery();
411
-
412
-		$this->assertEquals(['count' => $expected], $result->fetchAssociative());
413
-		$result->closeCursor();
414
-
415
-		$query = $this->connection->getQueryBuilder();
416
-		$query->delete('appconfig')
417
-			->where($query->expr()->eq('appid', $query->createNamedParameter($appId)))
418
-			->executeStatement();
419
-	}
420
-
421
-	protected function createConfig($appId, $key, $value) {
422
-		$query = $this->connection->getQueryBuilder();
423
-		$query->insert('appconfig')
424
-			->values([
425
-				'appid' => $query->createNamedParameter($appId),
426
-				'configkey' => $query->createNamedParameter((string)$key),
427
-				'configvalue' => $query->createNamedParameter((string)$value),
428
-			])
429
-			->executeStatement();
430
-	}
27
+    /** @var ExpressionBuilder */
28
+    protected $expressionBuilder;
29
+
30
+    /** @var DoctrineExpressionBuilder */
31
+    protected $doctrineExpressionBuilder;
32
+
33
+    /** @var IDBConnection */
34
+    protected $connection;
35
+
36
+    /** @var \Doctrine\DBAL\Connection */
37
+    protected $internalConnection;
38
+
39
+    /** @var LoggerInterface */
40
+    protected $logger;
41
+
42
+    protected function setUp(): void {
43
+        parent::setUp();
44
+
45
+        $this->connection = Server::get(IDBConnection::class);
46
+        $this->internalConnection = Server::get(\OC\DB\Connection::class);
47
+        $this->logger = $this->createMock(LoggerInterface::class);
48
+
49
+        $queryBuilder = $this->createMock(IQueryBuilder::class);
50
+
51
+        $this->expressionBuilder = new ExpressionBuilder($this->connection, $queryBuilder, $this->logger);
52
+
53
+        $this->doctrineExpressionBuilder = new DoctrineExpressionBuilder($this->internalConnection);
54
+    }
55
+
56
+    public static function dataComparison(): array {
57
+        $valueSets = self::dataComparisons();
58
+        $comparisonOperators = ['=', '<>', '<', '>', '<=', '>='];
59
+
60
+        $testSets = [];
61
+        foreach ($comparisonOperators as $operator) {
62
+            foreach ($valueSets as $values) {
63
+                $testSets[] = array_merge([$operator], $values);
64
+            }
65
+        }
66
+        return $testSets;
67
+    }
68
+
69
+    /**
70
+     *
71
+     * @param string $comparison
72
+     * @param mixed $input1
73
+     * @param bool $isInput1Literal
74
+     * @param mixed $input2
75
+     * @param bool $isInput2Literal
76
+     */
77
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataComparison')]
78
+    public function testComparison($comparison, $input1, $isInput1Literal, $input2, $isInput2Literal): void {
79
+        [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
80
+        [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
81
+
82
+        $this->assertEquals(
83
+            $this->doctrineExpressionBuilder->comparison($doctrineInput1, $comparison, $doctrineInput2),
84
+            $this->expressionBuilder->comparison($ocInput1, $comparison, $ocInput2)
85
+        );
86
+    }
87
+
88
+    public static function dataComparisons(): array {
89
+        return [
90
+            ['value', false, 'value', false],
91
+            ['value', false, 'value', true],
92
+            ['value', true, 'value', false],
93
+            ['value', true, 'value', true],
94
+        ];
95
+    }
96
+
97
+    /**
98
+     *
99
+     * @param mixed $input1
100
+     * @param bool $isInput1Literal
101
+     * @param mixed $input2
102
+     * @param bool $isInput2Literal
103
+     */
104
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
105
+    public function testEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void {
106
+        [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
107
+        [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
108
+
109
+        $this->assertEquals(
110
+            $this->doctrineExpressionBuilder->eq($doctrineInput1, $doctrineInput2),
111
+            $this->expressionBuilder->eq($ocInput1, $ocInput2)
112
+        );
113
+    }
114
+
115
+    /**
116
+     *
117
+     * @param mixed $input1
118
+     * @param bool $isInput1Literal
119
+     * @param mixed $input2
120
+     * @param bool $isInput2Literal
121
+     */
122
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
123
+    public function testNotEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void {
124
+        [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
125
+        [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
126
+
127
+        $this->assertEquals(
128
+            $this->doctrineExpressionBuilder->neq($doctrineInput1, $doctrineInput2),
129
+            $this->expressionBuilder->neq($ocInput1, $ocInput2)
130
+        );
131
+    }
132
+
133
+    /**
134
+     *
135
+     * @param mixed $input1
136
+     * @param bool $isInput1Literal
137
+     * @param mixed $input2
138
+     * @param bool $isInput2Literal
139
+     */
140
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
141
+    public function testLowerThan($input1, $isInput1Literal, $input2, $isInput2Literal): void {
142
+        [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
143
+        [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
144
+
145
+        $this->assertEquals(
146
+            $this->doctrineExpressionBuilder->lt($doctrineInput1, $doctrineInput2),
147
+            $this->expressionBuilder->lt($ocInput1, $ocInput2)
148
+        );
149
+    }
150
+
151
+    /**
152
+     *
153
+     * @param mixed $input1
154
+     * @param bool $isInput1Literal
155
+     * @param mixed $input2
156
+     * @param bool $isInput2Literal
157
+     */
158
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
159
+    public function testLowerThanEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void {
160
+        [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
161
+        [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
162
+
163
+        $this->assertEquals(
164
+            $this->doctrineExpressionBuilder->lte($doctrineInput1, $doctrineInput2),
165
+            $this->expressionBuilder->lte($ocInput1, $ocInput2)
166
+        );
167
+    }
168
+
169
+    /**
170
+     *
171
+     * @param mixed $input1
172
+     * @param bool $isInput1Literal
173
+     * @param mixed $input2
174
+     * @param bool $isInput2Literal
175
+     */
176
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
177
+    public function testGreaterThan($input1, $isInput1Literal, $input2, $isInput2Literal): void {
178
+        [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
179
+        [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
180
+
181
+        $this->assertEquals(
182
+            $this->doctrineExpressionBuilder->gt($doctrineInput1, $doctrineInput2),
183
+            $this->expressionBuilder->gt($ocInput1, $ocInput2)
184
+        );
185
+    }
186
+
187
+    /**
188
+     *
189
+     * @param mixed $input1
190
+     * @param bool $isInput1Literal
191
+     * @param mixed $input2
192
+     * @param bool $isInput2Literal
193
+     */
194
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
195
+    public function testGreaterThanEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void {
196
+        [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
197
+        [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
198
+
199
+        $this->assertEquals(
200
+            $this->doctrineExpressionBuilder->gte($doctrineInput1, $doctrineInput2),
201
+            $this->expressionBuilder->gte($ocInput1, $ocInput2)
202
+        );
203
+    }
204
+
205
+    public function testIsNull(): void {
206
+        $this->assertEquals(
207
+            $this->doctrineExpressionBuilder->isNull('`test`'),
208
+            $this->expressionBuilder->isNull('test')
209
+        );
210
+    }
211
+
212
+    public function testIsNotNull(): void {
213
+        $this->assertEquals(
214
+            $this->doctrineExpressionBuilder->isNotNull('`test`'),
215
+            $this->expressionBuilder->isNotNull('test')
216
+        );
217
+    }
218
+
219
+    public static function dataLike(): array {
220
+        return [
221
+            ['value', false],
222
+            ['value', true],
223
+        ];
224
+    }
225
+
226
+    /**
227
+     *
228
+     * @param mixed $input
229
+     * @param bool $isLiteral
230
+     */
231
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataLike')]
232
+    public function testLike($input, $isLiteral): void {
233
+        [$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral);
234
+
235
+        $this->assertEquals(
236
+            $this->doctrineExpressionBuilder->like('`test`', $doctrineInput),
237
+            $this->expressionBuilder->like('test', $ocInput)
238
+        );
239
+    }
240
+
241
+    /**
242
+     *
243
+     * @param mixed $input
244
+     * @param bool $isLiteral
245
+     */
246
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataLike')]
247
+    public function testNotLike($input, $isLiteral): void {
248
+        [$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral);
249
+
250
+        $this->assertEquals(
251
+            $this->doctrineExpressionBuilder->notLike('`test`', $doctrineInput),
252
+            $this->expressionBuilder->notLike('test', $ocInput)
253
+        );
254
+    }
255
+
256
+    public static function dataIn(): array {
257
+        return [
258
+            ['value', false],
259
+            ['value', true],
260
+            [['value'], false],
261
+            [['value'], true],
262
+        ];
263
+    }
264
+
265
+    /**
266
+     *
267
+     * @param mixed $input
268
+     * @param bool $isLiteral
269
+     */
270
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataIn')]
271
+    public function testIn($input, $isLiteral): void {
272
+        [$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral);
273
+
274
+        $this->assertEquals(
275
+            $this->doctrineExpressionBuilder->in('`test`', $doctrineInput),
276
+            $this->expressionBuilder->in('test', $ocInput)
277
+        );
278
+    }
279
+
280
+    /**
281
+     *
282
+     * @param mixed $input
283
+     * @param bool $isLiteral
284
+     */
285
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataIn')]
286
+    public function testNotIn($input, $isLiteral): void {
287
+        [$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral);
288
+
289
+        $this->assertEquals(
290
+            $this->doctrineExpressionBuilder->notIn('`test`', $doctrineInput),
291
+            $this->expressionBuilder->notIn('test', $ocInput)
292
+        );
293
+    }
294
+
295
+    protected function helpWithLiteral($input, $isLiteral) {
296
+        if ($isLiteral) {
297
+            if (is_array($input)) {
298
+                $doctrineInput = array_map(function ($ident) {
299
+                    return $this->doctrineExpressionBuilder->literal($ident);
300
+                }, $input);
301
+                $ocInput = array_map(function ($ident) {
302
+                    return $this->expressionBuilder->literal($ident);
303
+                }, $input);
304
+            } else {
305
+                $doctrineInput = $this->doctrineExpressionBuilder->literal($input);
306
+                $ocInput = $this->expressionBuilder->literal($input);
307
+            }
308
+        } else {
309
+            if (is_array($input)) {
310
+                $doctrineInput = array_map(function ($input) {
311
+                    return '`' . $input . '`';
312
+                }, $input);
313
+                $ocInput = $input;
314
+            } else {
315
+                $doctrineInput = '`' . $input . '`';
316
+                $ocInput = $input;
317
+            }
318
+        }
319
+
320
+        return [$doctrineInput, $ocInput];
321
+    }
322
+
323
+    public static function dataLiteral(): array {
324
+        return [
325
+            ['value', null],
326
+            ['1', null],
327
+            [1, null],
328
+            [1, 'string'],
329
+            [1, 'integer'],
330
+            [1, IQueryBuilder::PARAM_INT],
331
+        ];
332
+    }
333
+
334
+    /**
335
+     *
336
+     * @param mixed $input
337
+     * @param string|null $type
338
+     */
339
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataLiteral')]
340
+    public function testLiteral($input, $type): void {
341
+        /** @var \OC\DB\QueryBuilder\Literal $actual */
342
+        $actual = $this->expressionBuilder->literal($input, $type);
343
+
344
+        $this->assertInstanceOf('\OC\DB\QueryBuilder\Literal', $actual);
345
+        $this->assertEquals(
346
+            $this->doctrineExpressionBuilder->literal($input, $type),
347
+            $actual->__toString()
348
+        );
349
+    }
350
+
351
+    public static function dataClobComparisons(): array {
352
+        return [
353
+            ['eq', '5', IQueryBuilder::PARAM_STR, false, 3],
354
+            ['eq', '5', IQueryBuilder::PARAM_STR, true, 1],
355
+            ['neq', '5', IQueryBuilder::PARAM_STR, false, 8],
356
+            ['neq', '5', IQueryBuilder::PARAM_STR, true, 6],
357
+            ['lt', '5', IQueryBuilder::PARAM_STR, false, 3],
358
+            ['lt', '5', IQueryBuilder::PARAM_STR, true, 1],
359
+            ['lte', '5', IQueryBuilder::PARAM_STR, false, 6],
360
+            ['lte', '5', IQueryBuilder::PARAM_STR, true, 4],
361
+            ['gt', '5', IQueryBuilder::PARAM_STR, false, 5],
362
+            ['gt', '5', IQueryBuilder::PARAM_STR, true, 1],
363
+            ['gte', '5', IQueryBuilder::PARAM_STR, false, 8],
364
+            ['gte', '5', IQueryBuilder::PARAM_STR, true, 4],
365
+            ['like', '%5%', IQueryBuilder::PARAM_STR, false, 3],
366
+            ['like', '%5%', IQueryBuilder::PARAM_STR, true, 1],
367
+            ['like', 'under_%', IQueryBuilder::PARAM_STR, false, 2],
368
+            ['like', 'under\_%', IQueryBuilder::PARAM_STR, false, 1],
369
+            ['notLike', '%5%', IQueryBuilder::PARAM_STR, false, 8],
370
+            ['notLike', '%5%', IQueryBuilder::PARAM_STR, true, 6],
371
+            ['in', ['5'], IQueryBuilder::PARAM_STR_ARRAY, false, 3],
372
+            ['in', ['5'], IQueryBuilder::PARAM_STR_ARRAY, true, 1],
373
+            ['notIn', ['5'], IQueryBuilder::PARAM_STR_ARRAY, false, 8],
374
+            ['notIn', ['5'], IQueryBuilder::PARAM_STR_ARRAY, true, 6],
375
+        ];
376
+    }
377
+
378
+    /**
379
+     * @param string $function
380
+     * @param mixed $value
381
+     * @param mixed $type
382
+     * @param bool $compareKeyToValue
383
+     * @param int $expected
384
+     */
385
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataClobComparisons')]
386
+    public function testClobComparisons($function, $value, $type, $compareKeyToValue, $expected): void {
387
+        $appId = $this->getUniqueID('testing');
388
+        $this->createConfig($appId, 1, 4);
389
+        $this->createConfig($appId, 2, 5);
390
+        $this->createConfig($appId, 3, 6);
391
+        $this->createConfig($appId, 4, 4);
392
+        $this->createConfig($appId, 5, 5);
393
+        $this->createConfig($appId, 6, 6);
394
+        $this->createConfig($appId, 7, 4);
395
+        $this->createConfig($appId, 8, 5);
396
+        $this->createConfig($appId, 9, 6);
397
+        $this->createConfig($appId, 10, 'under_score');
398
+        $this->createConfig($appId, 11, 'underscore');
399
+
400
+        $query = $this->connection->getQueryBuilder();
401
+        $query->select($query->func()->count('*', 'count'))
402
+            ->from('appconfig')
403
+            ->where($query->expr()->eq('appid', $query->createNamedParameter($appId)))
404
+            ->andWhere(call_user_func([$query->expr(), $function], 'configvalue', $query->createNamedParameter($value, $type), IQueryBuilder::PARAM_STR));
405
+
406
+        if ($compareKeyToValue) {
407
+            $query->andWhere(call_user_func([$query->expr(), $function], 'configkey', 'configvalue', IQueryBuilder::PARAM_STR));
408
+        }
409
+
410
+        $result = $query->executeQuery();
411
+
412
+        $this->assertEquals(['count' => $expected], $result->fetchAssociative());
413
+        $result->closeCursor();
414
+
415
+        $query = $this->connection->getQueryBuilder();
416
+        $query->delete('appconfig')
417
+            ->where($query->expr()->eq('appid', $query->createNamedParameter($appId)))
418
+            ->executeStatement();
419
+    }
420
+
421
+    protected function createConfig($appId, $key, $value) {
422
+        $query = $this->connection->getQueryBuilder();
423
+        $query->insert('appconfig')
424
+            ->values([
425
+                'appid' => $query->createNamedParameter($appId),
426
+                'configkey' => $query->createNamedParameter((string)$key),
427
+                'configvalue' => $query->createNamedParameter((string)$value),
428
+            ])
429
+            ->executeStatement();
430
+    }
431 431
 }
Please login to merge, or discard this patch.
tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php 1 patch
Indentation   +262 added lines, -262 removed lines patch added patch discarded remove patch
@@ -18,266 +18,266 @@
 block discarded – undo
18 18
 
19 19
 #[\PHPUnit\Framework\Attributes\Group('DB')]
20 20
 class ExpressionBuilderDBTest extends TestCase {
21
-	/** @var \Doctrine\DBAL\Connection|IDBConnection */
22
-	protected $connection;
23
-	protected $schemaSetup = false;
24
-
25
-	protected function setUp(): void {
26
-		parent::setUp();
27
-
28
-		$this->connection = Server::get(IDBConnection::class);
29
-		$this->prepareTestingTable();
30
-	}
31
-
32
-	public static function likeProvider(): array {
33
-		$connection = Server::get(IDBConnection::class);
34
-
35
-		return [
36
-			['foo', 'bar', false],
37
-			['foo', 'foo', true],
38
-			['foo', 'f%', true],
39
-			['foo', '%o', true],
40
-			['foo', '%', true],
41
-			['foo', 'fo_', true],
42
-			['foo', 'foo_', false],
43
-			['foo', $connection->escapeLikeParameter('fo_'), false],
44
-			['foo', $connection->escapeLikeParameter('f%'), false],
45
-		];
46
-	}
47
-
48
-	/**
49
-	 *
50
-	 * @param string $param1
51
-	 * @param string $param2
52
-	 * @param boolean $match
53
-	 */
54
-	#[\PHPUnit\Framework\Attributes\DataProvider('likeProvider')]
55
-	public function testLike($param1, $param2, $match): void {
56
-		$query = $this->connection->getQueryBuilder();
57
-
58
-		$query->select(new Literal('1'))
59
-			->from('users')
60
-			->where($query->expr()->like($query->createNamedParameter($param1), $query->createNamedParameter($param2)));
61
-
62
-		$result = $query->executeQuery();
63
-		$column = $result->fetchOne();
64
-		$result->closeCursor();
65
-		$this->assertEquals($match, $column);
66
-	}
67
-
68
-	public static function ilikeProvider(): array {
69
-		$connection = Server::get(IDBConnection::class);
70
-
71
-		return [
72
-			['foo', 'bar', false],
73
-			['foo', 'foo', true],
74
-			['foo', 'Foo', true],
75
-			['foo', 'f%', true],
76
-			['foo', '%o', true],
77
-			['foo', '%', true],
78
-			['foo', 'fo_', true],
79
-			['foo', 'foo_', false],
80
-			['foo', $connection->escapeLikeParameter('fo_'), false],
81
-			['foo', $connection->escapeLikeParameter('f%'), false],
82
-		];
83
-	}
84
-
85
-	/**
86
-	 *
87
-	 * @param string $param1
88
-	 * @param string $param2
89
-	 * @param boolean $match
90
-	 */
91
-	#[\PHPUnit\Framework\Attributes\DataProvider('ilikeProvider')]
92
-	public function testILike($param1, $param2, $match): void {
93
-		$query = $this->connection->getQueryBuilder();
94
-
95
-		$query->select(new Literal('1'))
96
-			->from('users')
97
-			->where($query->expr()->iLike($query->createNamedParameter($param1), $query->createNamedParameter($param2)));
98
-
99
-		$result = $query->executeQuery();
100
-		$column = $result->fetchOne();
101
-		$result->closeCursor();
102
-		$this->assertEquals($match, $column);
103
-	}
104
-
105
-	public function testCastColumn(): void {
106
-		$appId = $this->getUniqueID('testing');
107
-		$this->createConfig($appId, '1', '4');
108
-
109
-		$query = $this->connection->getQueryBuilder();
110
-		$query->update('appconfig')
111
-			->set('configvalue',
112
-				$query->expr()->castColumn(
113
-					$query->createFunction(
114
-						'(' . $query->expr()->castColumn('configvalue', IQueryBuilder::PARAM_INT)
115
-						. ' + 1)'
116
-					), IQueryBuilder::PARAM_STR
117
-				)
118
-			)
119
-			->where($query->expr()->eq('appid', $query->createNamedParameter($appId)))
120
-			->andWhere($query->expr()->eq('configkey', $query->createNamedParameter('1')));
121
-
122
-		$result = $query->executeStatement();
123
-		$this->assertEquals(1, $result);
124
-	}
125
-
126
-	public function testLongText(): void {
127
-		$appId = $this->getUniqueID('testing');
128
-		$this->createConfig($appId, 'mykey', 'myvalue');
129
-
130
-		$query = $this->connection->getQueryBuilder();
131
-		$query->select('*')
132
-			->from('appconfig')
133
-			->where($query->expr()->eq('appid', $query->createNamedParameter($appId)))
134
-			->andWhere($query->expr()->eq('configkey', $query->createNamedParameter('mykey')))
135
-			->andWhere($query->expr()->eq('configvalue', $query->createNamedParameter('myvalue', IQueryBuilder::PARAM_STR), IQueryBuilder::PARAM_STR));
136
-
137
-		$result = $query->executeQuery();
138
-		$entries = $result->fetchAllAssociative();
139
-		$result->closeCursor();
140
-		self::assertCount(1, $entries);
141
-		self::assertEquals('myvalue', $entries[0]['configvalue']);
142
-	}
143
-
144
-	public function testJson(): void {
145
-		if ($this->connection->getDatabaseProvider(true) === IDBConnection::PLATFORM_ORACLE) {
146
-			$result = $this->connection->executeQuery('SELECT VERSION FROM PRODUCT_COMPONENT_VERSION');
147
-			$version = $result->fetchOne();
148
-			$result->closeCursor();
149
-			if (str_starts_with($version, '11.')) {
150
-				$this->markTestSkipped('JSON is not supported on Oracle 11, skipping until deprecation was clarified: ' . $version);
151
-			}
152
-		}
153
-
154
-
155
-		$appId = $this->getUniqueID('testing');
156
-		$query = $this->connection->getQueryBuilder();
157
-		$query->insert('share')
158
-			->values([
159
-				'uid_owner' => $query->createNamedParameter('uid_owner'),
160
-				'item_type' => $query->createNamedParameter('item_type'),
161
-				'permissions' => $query->createNamedParameter(0),
162
-				'stime' => $query->createNamedParameter(0),
163
-				'accepted' => $query->createNamedParameter(0),
164
-				'mail_send' => $query->createNamedParameter(0),
165
-				'share_type' => $query->createNamedParameter(0),
166
-				'share_with' => $query->createNamedParameter($appId),
167
-				'attributes' => $query->createNamedParameter('[["permissions","before"]]'),
168
-			])
169
-			->executeStatement();
170
-
171
-		$query = $this->connection->getQueryBuilder();
172
-		$query->update('share')
173
-			->set('attributes', $query->createNamedParameter('[["permissions","after"]]'));
174
-		if ($this->connection->getDatabaseProvider(true) === IDBConnection::PLATFORM_MYSQL) {
175
-			$query->where($query->expr()->eq('attributes', $query->createFunction("JSON_ARRAY(JSON_ARRAY('permissions','before'))"), IQueryBuilder::PARAM_JSON));
176
-		} else {
177
-			$query->where($query->expr()->eq('attributes', $query->createNamedParameter('[["permissions","before"]]'), IQueryBuilder::PARAM_JSON));
178
-		}
179
-		$query->executeStatement();
180
-
181
-		$query = $this->connection->getQueryBuilder();
182
-		$query->select('attributes')
183
-			->from('share')
184
-			->where($query->expr()->eq('share_with', $query->createNamedParameter($appId)));
185
-
186
-		$result = $query->executeQuery();
187
-		$entries = $result->fetchAll();
188
-		$result->closeCursor();
189
-		self::assertCount(1, $entries);
190
-		self::assertEquals([['permissions','after']], json_decode($entries[0]['attributes'], true));
191
-	}
192
-
193
-	public function testDateTimeEquals(): void {
194
-		$dateTime = new \DateTime('2023-01-01');
195
-		$insert = $this->connection->getQueryBuilder();
196
-		$insert->insert('testing')
197
-			->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE)])
198
-			->executeStatement();
199
-
200
-		$query = $this->connection->getQueryBuilder();
201
-		$result = $query->select('*')
202
-			->from('testing')
203
-			->where($query->expr()->eq('datetime', $query->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE)))
204
-			->executeQuery();
205
-		$entries = $result->fetchAllAssociative();
206
-		$result->closeCursor();
207
-		self::assertCount(1, $entries);
208
-	}
209
-
210
-	public function testDateTimeLess(): void {
211
-		$dateTime = new \DateTime('2022-01-01');
212
-		$dateTimeCompare = new \DateTime('2022-01-02');
213
-		$insert = $this->connection->getQueryBuilder();
214
-		$insert->insert('testing')
215
-			->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE)])
216
-			->executeStatement();
217
-
218
-		$query = $this->connection->getQueryBuilder();
219
-		$result = $query->select('*')
220
-			->from('testing')
221
-			->where($query->expr()->lt('datetime', $query->createNamedParameter($dateTimeCompare, IQueryBuilder::PARAM_DATETIME_MUTABLE)))
222
-			->executeQuery();
223
-		$entries = $result->fetchAllAssociative();
224
-		$result->closeCursor();
225
-		self::assertCount(1, $entries);
226
-	}
227
-
228
-	public function testDateTimeGreater(): void {
229
-		$dateTime = new \DateTime('2023-01-02');
230
-		$dateTimeCompare = new \DateTime('2023-01-01');
231
-		$insert = $this->connection->getQueryBuilder();
232
-		$insert->insert('testing')
233
-			->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE)])
234
-			->executeStatement();
235
-
236
-		$query = $this->connection->getQueryBuilder();
237
-		$result = $query->select('*')
238
-			->from('testing')
239
-			->where($query->expr()->gt('datetime', $query->createNamedParameter($dateTimeCompare, IQueryBuilder::PARAM_DATETIME_MUTABLE)))
240
-			->executeQuery();
241
-		$entries = $result->fetchAllAssociative();
242
-		$result->closeCursor();
243
-		self::assertCount(1, $entries);
244
-	}
245
-
246
-	protected function createConfig($appId, $key, $value) {
247
-		$query = $this->connection->getQueryBuilder();
248
-		$query->insert('appconfig')
249
-			->values([
250
-				'appid' => $query->createNamedParameter($appId),
251
-				'configkey' => $query->createNamedParameter((string)$key),
252
-				'configvalue' => $query->createNamedParameter((string)$value),
253
-			])
254
-			->executeStatement();
255
-	}
256
-
257
-	protected function prepareTestingTable(): void {
258
-		if ($this->schemaSetup) {
259
-			$this->connection->getQueryBuilder()->delete('testing')->executeStatement();
260
-		}
261
-
262
-		$prefix = Server::get(IConfig::class)->getSystemValueString('dbtableprefix', 'oc_');
263
-		$schema = $this->connection->createSchema();
264
-		try {
265
-			$schema->getTable($prefix . 'testing');
266
-			$this->connection->getQueryBuilder()->delete('testing')->executeStatement();
267
-		} catch (SchemaException $e) {
268
-			$this->schemaSetup = true;
269
-			$table = $schema->createTable($prefix . 'testing');
270
-			$table->addColumn('id', Types::BIGINT, [
271
-				'autoincrement' => true,
272
-				'notnull' => true,
273
-			]);
274
-
275
-			$table->addColumn('datetime', Types::DATETIME, [
276
-				'notnull' => false,
277
-			]);
278
-
279
-			$table->setPrimaryKey(['id']);
280
-			$this->connection->migrateToSchema($schema);
281
-		}
282
-	}
21
+    /** @var \Doctrine\DBAL\Connection|IDBConnection */
22
+    protected $connection;
23
+    protected $schemaSetup = false;
24
+
25
+    protected function setUp(): void {
26
+        parent::setUp();
27
+
28
+        $this->connection = Server::get(IDBConnection::class);
29
+        $this->prepareTestingTable();
30
+    }
31
+
32
+    public static function likeProvider(): array {
33
+        $connection = Server::get(IDBConnection::class);
34
+
35
+        return [
36
+            ['foo', 'bar', false],
37
+            ['foo', 'foo', true],
38
+            ['foo', 'f%', true],
39
+            ['foo', '%o', true],
40
+            ['foo', '%', true],
41
+            ['foo', 'fo_', true],
42
+            ['foo', 'foo_', false],
43
+            ['foo', $connection->escapeLikeParameter('fo_'), false],
44
+            ['foo', $connection->escapeLikeParameter('f%'), false],
45
+        ];
46
+    }
47
+
48
+    /**
49
+     *
50
+     * @param string $param1
51
+     * @param string $param2
52
+     * @param boolean $match
53
+     */
54
+    #[\PHPUnit\Framework\Attributes\DataProvider('likeProvider')]
55
+    public function testLike($param1, $param2, $match): void {
56
+        $query = $this->connection->getQueryBuilder();
57
+
58
+        $query->select(new Literal('1'))
59
+            ->from('users')
60
+            ->where($query->expr()->like($query->createNamedParameter($param1), $query->createNamedParameter($param2)));
61
+
62
+        $result = $query->executeQuery();
63
+        $column = $result->fetchOne();
64
+        $result->closeCursor();
65
+        $this->assertEquals($match, $column);
66
+    }
67
+
68
+    public static function ilikeProvider(): array {
69
+        $connection = Server::get(IDBConnection::class);
70
+
71
+        return [
72
+            ['foo', 'bar', false],
73
+            ['foo', 'foo', true],
74
+            ['foo', 'Foo', true],
75
+            ['foo', 'f%', true],
76
+            ['foo', '%o', true],
77
+            ['foo', '%', true],
78
+            ['foo', 'fo_', true],
79
+            ['foo', 'foo_', false],
80
+            ['foo', $connection->escapeLikeParameter('fo_'), false],
81
+            ['foo', $connection->escapeLikeParameter('f%'), false],
82
+        ];
83
+    }
84
+
85
+    /**
86
+     *
87
+     * @param string $param1
88
+     * @param string $param2
89
+     * @param boolean $match
90
+     */
91
+    #[\PHPUnit\Framework\Attributes\DataProvider('ilikeProvider')]
92
+    public function testILike($param1, $param2, $match): void {
93
+        $query = $this->connection->getQueryBuilder();
94
+
95
+        $query->select(new Literal('1'))
96
+            ->from('users')
97
+            ->where($query->expr()->iLike($query->createNamedParameter($param1), $query->createNamedParameter($param2)));
98
+
99
+        $result = $query->executeQuery();
100
+        $column = $result->fetchOne();
101
+        $result->closeCursor();
102
+        $this->assertEquals($match, $column);
103
+    }
104
+
105
+    public function testCastColumn(): void {
106
+        $appId = $this->getUniqueID('testing');
107
+        $this->createConfig($appId, '1', '4');
108
+
109
+        $query = $this->connection->getQueryBuilder();
110
+        $query->update('appconfig')
111
+            ->set('configvalue',
112
+                $query->expr()->castColumn(
113
+                    $query->createFunction(
114
+                        '(' . $query->expr()->castColumn('configvalue', IQueryBuilder::PARAM_INT)
115
+                        . ' + 1)'
116
+                    ), IQueryBuilder::PARAM_STR
117
+                )
118
+            )
119
+            ->where($query->expr()->eq('appid', $query->createNamedParameter($appId)))
120
+            ->andWhere($query->expr()->eq('configkey', $query->createNamedParameter('1')));
121
+
122
+        $result = $query->executeStatement();
123
+        $this->assertEquals(1, $result);
124
+    }
125
+
126
+    public function testLongText(): void {
127
+        $appId = $this->getUniqueID('testing');
128
+        $this->createConfig($appId, 'mykey', 'myvalue');
129
+
130
+        $query = $this->connection->getQueryBuilder();
131
+        $query->select('*')
132
+            ->from('appconfig')
133
+            ->where($query->expr()->eq('appid', $query->createNamedParameter($appId)))
134
+            ->andWhere($query->expr()->eq('configkey', $query->createNamedParameter('mykey')))
135
+            ->andWhere($query->expr()->eq('configvalue', $query->createNamedParameter('myvalue', IQueryBuilder::PARAM_STR), IQueryBuilder::PARAM_STR));
136
+
137
+        $result = $query->executeQuery();
138
+        $entries = $result->fetchAllAssociative();
139
+        $result->closeCursor();
140
+        self::assertCount(1, $entries);
141
+        self::assertEquals('myvalue', $entries[0]['configvalue']);
142
+    }
143
+
144
+    public function testJson(): void {
145
+        if ($this->connection->getDatabaseProvider(true) === IDBConnection::PLATFORM_ORACLE) {
146
+            $result = $this->connection->executeQuery('SELECT VERSION FROM PRODUCT_COMPONENT_VERSION');
147
+            $version = $result->fetchOne();
148
+            $result->closeCursor();
149
+            if (str_starts_with($version, '11.')) {
150
+                $this->markTestSkipped('JSON is not supported on Oracle 11, skipping until deprecation was clarified: ' . $version);
151
+            }
152
+        }
153
+
154
+
155
+        $appId = $this->getUniqueID('testing');
156
+        $query = $this->connection->getQueryBuilder();
157
+        $query->insert('share')
158
+            ->values([
159
+                'uid_owner' => $query->createNamedParameter('uid_owner'),
160
+                'item_type' => $query->createNamedParameter('item_type'),
161
+                'permissions' => $query->createNamedParameter(0),
162
+                'stime' => $query->createNamedParameter(0),
163
+                'accepted' => $query->createNamedParameter(0),
164
+                'mail_send' => $query->createNamedParameter(0),
165
+                'share_type' => $query->createNamedParameter(0),
166
+                'share_with' => $query->createNamedParameter($appId),
167
+                'attributes' => $query->createNamedParameter('[["permissions","before"]]'),
168
+            ])
169
+            ->executeStatement();
170
+
171
+        $query = $this->connection->getQueryBuilder();
172
+        $query->update('share')
173
+            ->set('attributes', $query->createNamedParameter('[["permissions","after"]]'));
174
+        if ($this->connection->getDatabaseProvider(true) === IDBConnection::PLATFORM_MYSQL) {
175
+            $query->where($query->expr()->eq('attributes', $query->createFunction("JSON_ARRAY(JSON_ARRAY('permissions','before'))"), IQueryBuilder::PARAM_JSON));
176
+        } else {
177
+            $query->where($query->expr()->eq('attributes', $query->createNamedParameter('[["permissions","before"]]'), IQueryBuilder::PARAM_JSON));
178
+        }
179
+        $query->executeStatement();
180
+
181
+        $query = $this->connection->getQueryBuilder();
182
+        $query->select('attributes')
183
+            ->from('share')
184
+            ->where($query->expr()->eq('share_with', $query->createNamedParameter($appId)));
185
+
186
+        $result = $query->executeQuery();
187
+        $entries = $result->fetchAll();
188
+        $result->closeCursor();
189
+        self::assertCount(1, $entries);
190
+        self::assertEquals([['permissions','after']], json_decode($entries[0]['attributes'], true));
191
+    }
192
+
193
+    public function testDateTimeEquals(): void {
194
+        $dateTime = new \DateTime('2023-01-01');
195
+        $insert = $this->connection->getQueryBuilder();
196
+        $insert->insert('testing')
197
+            ->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE)])
198
+            ->executeStatement();
199
+
200
+        $query = $this->connection->getQueryBuilder();
201
+        $result = $query->select('*')
202
+            ->from('testing')
203
+            ->where($query->expr()->eq('datetime', $query->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE)))
204
+            ->executeQuery();
205
+        $entries = $result->fetchAllAssociative();
206
+        $result->closeCursor();
207
+        self::assertCount(1, $entries);
208
+    }
209
+
210
+    public function testDateTimeLess(): void {
211
+        $dateTime = new \DateTime('2022-01-01');
212
+        $dateTimeCompare = new \DateTime('2022-01-02');
213
+        $insert = $this->connection->getQueryBuilder();
214
+        $insert->insert('testing')
215
+            ->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE)])
216
+            ->executeStatement();
217
+
218
+        $query = $this->connection->getQueryBuilder();
219
+        $result = $query->select('*')
220
+            ->from('testing')
221
+            ->where($query->expr()->lt('datetime', $query->createNamedParameter($dateTimeCompare, IQueryBuilder::PARAM_DATETIME_MUTABLE)))
222
+            ->executeQuery();
223
+        $entries = $result->fetchAllAssociative();
224
+        $result->closeCursor();
225
+        self::assertCount(1, $entries);
226
+    }
227
+
228
+    public function testDateTimeGreater(): void {
229
+        $dateTime = new \DateTime('2023-01-02');
230
+        $dateTimeCompare = new \DateTime('2023-01-01');
231
+        $insert = $this->connection->getQueryBuilder();
232
+        $insert->insert('testing')
233
+            ->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE)])
234
+            ->executeStatement();
235
+
236
+        $query = $this->connection->getQueryBuilder();
237
+        $result = $query->select('*')
238
+            ->from('testing')
239
+            ->where($query->expr()->gt('datetime', $query->createNamedParameter($dateTimeCompare, IQueryBuilder::PARAM_DATETIME_MUTABLE)))
240
+            ->executeQuery();
241
+        $entries = $result->fetchAllAssociative();
242
+        $result->closeCursor();
243
+        self::assertCount(1, $entries);
244
+    }
245
+
246
+    protected function createConfig($appId, $key, $value) {
247
+        $query = $this->connection->getQueryBuilder();
248
+        $query->insert('appconfig')
249
+            ->values([
250
+                'appid' => $query->createNamedParameter($appId),
251
+                'configkey' => $query->createNamedParameter((string)$key),
252
+                'configvalue' => $query->createNamedParameter((string)$value),
253
+            ])
254
+            ->executeStatement();
255
+    }
256
+
257
+    protected function prepareTestingTable(): void {
258
+        if ($this->schemaSetup) {
259
+            $this->connection->getQueryBuilder()->delete('testing')->executeStatement();
260
+        }
261
+
262
+        $prefix = Server::get(IConfig::class)->getSystemValueString('dbtableprefix', 'oc_');
263
+        $schema = $this->connection->createSchema();
264
+        try {
265
+            $schema->getTable($prefix . 'testing');
266
+            $this->connection->getQueryBuilder()->delete('testing')->executeStatement();
267
+        } catch (SchemaException $e) {
268
+            $this->schemaSetup = true;
269
+            $table = $schema->createTable($prefix . 'testing');
270
+            $table->addColumn('id', Types::BIGINT, [
271
+                'autoincrement' => true,
272
+                'notnull' => true,
273
+            ]);
274
+
275
+            $table->addColumn('datetime', Types::DATETIME, [
276
+                'notnull' => false,
277
+            ]);
278
+
279
+            $table->setPrimaryKey(['id']);
280
+            $this->connection->migrateToSchema($schema);
281
+        }
282
+    }
283 283
 }
Please login to merge, or discard this patch.
tests/lib/Collaboration/Collaborators/MailPluginTest.php 2 patches
Indentation   +1050 added lines, -1050 removed lines patch added patch discarded remove patch
@@ -27,1102 +27,1102 @@
 block discarded – undo
27 27
 use Test\Traits\EmailValidatorTrait;
28 28
 
29 29
 class MailPluginTest extends TestCase {
30
-	use EmailValidatorTrait;
30
+    use EmailValidatorTrait;
31 31
 
32
-	/** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
33
-	protected $config;
32
+    /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
33
+    protected $config;
34 34
 
35
-	/** @var IManager|\PHPUnit\Framework\MockObject\MockObject */
36
-	protected $contactsManager;
35
+    /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */
36
+    protected $contactsManager;
37 37
 
38
-	/** @var ICloudIdManager|\PHPUnit\Framework\MockObject\MockObject */
39
-	protected $cloudIdManager;
38
+    /** @var ICloudIdManager|\PHPUnit\Framework\MockObject\MockObject */
39
+    protected $cloudIdManager;
40 40
 
41
-	/** @var MailPlugin */
42
-	protected $plugin;
41
+    /** @var MailPlugin */
42
+    protected $plugin;
43 43
 
44
-	/** @var SearchResult */
45
-	protected $searchResult;
44
+    /** @var SearchResult */
45
+    protected $searchResult;
46 46
 
47
-	/** @var IGroupManager|\PHPUnit\Framework\MockObject\MockObject */
48
-	protected $groupManager;
47
+    /** @var IGroupManager|\PHPUnit\Framework\MockObject\MockObject */
48
+    protected $groupManager;
49 49
 
50
-	/** @var KnownUserService|\PHPUnit\Framework\MockObject\MockObject */
51
-	protected $knownUserService;
50
+    /** @var KnownUserService|\PHPUnit\Framework\MockObject\MockObject */
51
+    protected $knownUserService;
52 52
 
53
-	/** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */
54
-	protected $userSession;
53
+    /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */
54
+    protected $userSession;
55 55
 
56
-	protected function setUp(): void {
57
-		parent::setUp();
56
+    protected function setUp(): void {
57
+        parent::setUp();
58 58
 
59
-		$this->config = $this->createMock(IConfig::class);
60
-		$this->contactsManager = $this->createMock(IManager::class);
61
-		$this->groupManager = $this->createMock(IGroupManager::class);
62
-		$this->knownUserService = $this->createMock(KnownUserService::class);
63
-		$this->userSession = $this->createMock(IUserSession::class);
64
-		$this->cloudIdManager = new CloudIdManager(
65
-			$this->createMock(ICacheFactory::class),
66
-			$this->createMock(IEventDispatcher::class),
67
-			$this->contactsManager,
68
-			$this->createMock(IURLGenerator::class),
69
-			$this->createMock(IUserManager::class),
70
-		);
59
+        $this->config = $this->createMock(IConfig::class);
60
+        $this->contactsManager = $this->createMock(IManager::class);
61
+        $this->groupManager = $this->createMock(IGroupManager::class);
62
+        $this->knownUserService = $this->createMock(KnownUserService::class);
63
+        $this->userSession = $this->createMock(IUserSession::class);
64
+        $this->cloudIdManager = new CloudIdManager(
65
+            $this->createMock(ICacheFactory::class),
66
+            $this->createMock(IEventDispatcher::class),
67
+            $this->contactsManager,
68
+            $this->createMock(IURLGenerator::class),
69
+            $this->createMock(IUserManager::class),
70
+        );
71 71
 
72
-		$this->searchResult = new SearchResult();
73
-	}
72
+        $this->searchResult = new SearchResult();
73
+    }
74 74
 
75
-	public function instantiatePlugin(int $shareType) {
76
-		$this->plugin = new MailPlugin(
77
-			$this->contactsManager,
78
-			$this->cloudIdManager,
79
-			$this->config,
80
-			$this->groupManager,
81
-			$this->knownUserService,
82
-			$this->userSession,
83
-			$this->getEmailValidatorWithStrictEmailCheck(),
84
-			[],
85
-			$shareType,
86
-		);
87
-	}
75
+    public function instantiatePlugin(int $shareType) {
76
+        $this->plugin = new MailPlugin(
77
+            $this->contactsManager,
78
+            $this->cloudIdManager,
79
+            $this->config,
80
+            $this->groupManager,
81
+            $this->knownUserService,
82
+            $this->userSession,
83
+            $this->getEmailValidatorWithStrictEmailCheck(),
84
+            [],
85
+            $shareType,
86
+        );
87
+    }
88 88
 
89
-	/**
90
-	 *
91
-	 * @param string $searchTerm
92
-	 * @param array $contacts
93
-	 * @param bool $shareeEnumeration
94
-	 * @param array $expectedResult
95
-	 * @param bool $expectedExactIdMatch
96
-	 * @param bool $expectedMoreResults
97
-	 * @param bool $validEmail
98
-	 */
99
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataSearchEmail')]
100
-	public function testSearchEmail($searchTerm, $contacts, $shareeEnumeration, $expectedResult, $expectedExactIdMatch, $expectedMoreResults, $validEmail): void {
101
-		$this->config->expects($this->any())
102
-			->method('getAppValue')
103
-			->willReturnCallback(
104
-				function ($appName, $key, $default) use ($shareeEnumeration) {
105
-					if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
106
-						return $shareeEnumeration ? 'yes' : 'no';
107
-					}
108
-					return $default;
109
-				}
110
-			);
89
+    /**
90
+     *
91
+     * @param string $searchTerm
92
+     * @param array $contacts
93
+     * @param bool $shareeEnumeration
94
+     * @param array $expectedResult
95
+     * @param bool $expectedExactIdMatch
96
+     * @param bool $expectedMoreResults
97
+     * @param bool $validEmail
98
+     */
99
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataSearchEmail')]
100
+    public function testSearchEmail($searchTerm, $contacts, $shareeEnumeration, $expectedResult, $expectedExactIdMatch, $expectedMoreResults, $validEmail): void {
101
+        $this->config->expects($this->any())
102
+            ->method('getAppValue')
103
+            ->willReturnCallback(
104
+                function ($appName, $key, $default) use ($shareeEnumeration) {
105
+                    if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
106
+                        return $shareeEnumeration ? 'yes' : 'no';
107
+                    }
108
+                    return $default;
109
+                }
110
+            );
111 111
 
112
-		$this->instantiatePlugin(IShare::TYPE_EMAIL);
112
+        $this->instantiatePlugin(IShare::TYPE_EMAIL);
113 113
 
114
-		$currentUser = $this->createMock(IUser::class);
115
-		$currentUser->method('getUID')
116
-			->willReturn('current');
117
-		$this->userSession->method('getUser')
118
-			->willReturn($currentUser);
114
+        $currentUser = $this->createMock(IUser::class);
115
+        $currentUser->method('getUID')
116
+            ->willReturn('current');
117
+        $this->userSession->method('getUser')
118
+            ->willReturn($currentUser);
119 119
 
120
-		$this->contactsManager->expects($this->any())
121
-			->method('search')
122
-			->willReturnCallback(function ($search, $searchAttributes) use ($searchTerm, $contacts) {
123
-				if ($search === $searchTerm) {
124
-					return $contacts;
125
-				}
126
-				return [];
127
-			});
120
+        $this->contactsManager->expects($this->any())
121
+            ->method('search')
122
+            ->willReturnCallback(function ($search, $searchAttributes) use ($searchTerm, $contacts) {
123
+                if ($search === $searchTerm) {
124
+                    return $contacts;
125
+                }
126
+                return [];
127
+            });
128 128
 
129
-		$moreResults = $this->plugin->search($searchTerm, 2, 0, $this->searchResult);
130
-		$result = $this->searchResult->asArray();
129
+        $moreResults = $this->plugin->search($searchTerm, 2, 0, $this->searchResult);
130
+        $result = $this->searchResult->asArray();
131 131
 
132
-		$this->assertSame($expectedExactIdMatch, $this->searchResult->hasExactIdMatch(new SearchResultType('emails')));
133
-		$this->assertEquals($expectedResult, $result);
134
-		$this->assertSame($expectedMoreResults, $moreResults);
135
-	}
132
+        $this->assertSame($expectedExactIdMatch, $this->searchResult->hasExactIdMatch(new SearchResultType('emails')));
133
+        $this->assertEquals($expectedResult, $result);
134
+        $this->assertSame($expectedMoreResults, $moreResults);
135
+    }
136 136
 
137
-	public static function dataSearchEmail(): array {
138
-		return [
139
-			// data set 0
140
-			['test', [], true, ['emails' => [], 'exact' => ['emails' => []]], false, false, false],
141
-			// data set 1
142
-			['test', [], false, ['emails' => [], 'exact' => ['emails' => []]], false, false, false],
143
-			// data set 2
144
-			[
145
-				'[email protected]',
146
-				[],
147
-				true,
148
-				['emails' => [], 'exact' => ['emails' => [['uuid' => '[email protected]', 'label' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
149
-				false,
150
-				false,
151
-				true,
152
-			],
153
-			// data set 3
154
-			[ // no valid email address
155
-				'test@remote',
156
-				[],
157
-				true,
158
-				['emails' => [], 'exact' => ['emails' => []]],
159
-				false,
160
-				false,
161
-				false,
162
-			],
163
-			// data set 4
164
-			[
165
-				'[email protected]',
166
-				[],
167
-				false,
168
-				['emails' => [], 'exact' => ['emails' => [['uuid' => '[email protected]', 'label' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
169
-				false,
170
-				false,
171
-				true,
172
-			],
173
-			// data set 5
174
-			[
175
-				'test',
176
-				[
177
-					[
178
-						'UID' => 'uid3',
179
-						'FN' => 'User3 @ Localhost',
180
-					],
181
-					[
182
-						'UID' => 'uid2',
183
-						'FN' => 'User2 @ Localhost',
184
-						'EMAIL' => [
185
-						],
186
-					],
187
-					[
188
-						'UID' => 'uid1',
189
-						'FN' => 'User @ Localhost',
190
-						'EMAIL' => [
191
-							'[email protected]',
192
-						],
193
-					],
194
-				],
195
-				true,
196
-				['emails' => [['uuid' => 'uid1', 'name' => 'User @ Localhost', 'type' => '', 'label' => 'User @ Localhost ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]], 'exact' => ['emails' => []]],
197
-				false,
198
-				false,
199
-				false,
200
-			],
201
-			// data set 6
202
-			[
203
-				'test',
204
-				[
205
-					[
206
-						'UID' => 'uid3',
207
-						'FN' => 'User3 @ Localhost',
208
-					],
209
-					[
210
-						'UID' => 'uid2',
211
-						'FN' => 'User2 @ Localhost',
212
-						'EMAIL' => [
213
-						],
214
-					],
215
-					[
216
-						'isLocalSystemBook' => true,
217
-						'UID' => 'uid1',
218
-						'FN' => 'User @ Localhost',
219
-						'EMAIL' => [
220
-							'username@localhost',
221
-						],
222
-					],
223
-				],
224
-				false,
225
-				['emails' => [], 'exact' => ['emails' => []]],
226
-				false,
227
-				false,
228
-				false,
229
-			],
230
-			// data set 7
231
-			[
232
-				'[email protected]',
233
-				[
234
-					[
235
-						'UID' => 'uid3',
236
-						'FN' => 'User3 @ example.com',
237
-					],
238
-					[
239
-						'UID' => 'uid2',
240
-						'FN' => 'User2 @ example.com',
241
-						'EMAIL' => [
242
-						],
243
-					],
244
-					[
245
-						'UID' => 'uid1',
246
-						'FN' => 'User @ example.com',
247
-						'EMAIL' => [
248
-							'[email protected]',
249
-						],
250
-					],
251
-				],
252
-				true,
253
-				['emails' => [['uuid' => 'uid1', 'name' => 'User @ example.com', 'type' => '', 'label' => 'User @ example.com ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]], 'exact' => ['emails' => [['label' => '[email protected]', 'uuid' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
254
-				false,
255
-				false,
256
-				true,
257
-			],
258
-			// data set 8
259
-			[
260
-				'[email protected]',
261
-				[
262
-					[
263
-						'UID' => 'uid3',
264
-						'FN' => 'User3 @ Localhost',
265
-					],
266
-					[
267
-						'UID' => 'uid2',
268
-						'FN' => 'User2 @ Localhost',
269
-						'EMAIL' => [
270
-						],
271
-					],
272
-					[
273
-						'isLocalSystemBook' => true,
274
-						'UID' => 'uid1',
275
-						'FN' => 'User @ Localhost',
276
-						'EMAIL' => [
277
-							'username@localhost',
278
-						],
279
-					],
280
-				],
281
-				false,
282
-				['emails' => [], 'exact' => ['emails' => [['label' => '[email protected]', 'uuid' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
283
-				false,
284
-				false,
285
-				true,
286
-			],
287
-			// data set 9
288
-			[
289
-				'[email protected]',
290
-				[
291
-					[
292
-						'UID' => 'uid3',
293
-						'FN' => 'User3 @ example.com',
294
-					],
295
-					[
296
-						'UID' => 'uid2',
297
-						'FN' => 'User2 @ example.com',
298
-						'EMAIL' => [
299
-						],
300
-					],
301
-					[
302
-						'UID' => 'uid1',
303
-						'FN' => 'User @ example.com',
304
-						'EMAIL' => [
305
-							'[email protected]',
306
-						],
307
-					],
308
-				],
309
-				true,
310
-				['emails' => [], 'exact' => ['emails' => [['name' => 'User @ example.com', 'uuid' => 'uid1', 'type' => '', 'label' => 'User @ example.com ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
311
-				true,
312
-				false,
313
-				false,
314
-			],
315
-			// data set 10
316
-			[
317
-				'[email protected]',
318
-				[
319
-					[
320
-						'UID' => 'uid1',
321
-						'FN' => 'User3 @ example.com',
322
-					],
323
-					[
324
-						'UID' => 'uid2',
325
-						'FN' => 'User2 @ example.com',
326
-						'EMAIL' => [
327
-						],
328
-					],
329
-					[
330
-						'UID' => 'uid1',
331
-						'FN' => 'User @ example.com',
332
-						'EMAIL' => [
333
-							'[email protected]',
334
-						],
335
-					],
336
-				],
337
-				false,
338
-				['emails' => [], 'exact' => ['emails' => [['name' => 'User @ example.com', 'uuid' => 'uid1', 'type' => '', 'label' => 'User @ example.com ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
339
-				true,
340
-				false,
341
-				false,
342
-			],
343
-			// data set 11
344
-			// contact with space
345
-			[
346
-				'user name@localhost',
347
-				[
348
-					[
349
-						'UID' => 'uid3',
350
-						'FN' => 'User3 @ Localhost',
351
-					],
352
-					[
353
-						'UID' => 'uid2',
354
-						'FN' => 'User2 @ Localhost',
355
-						'EMAIL' => [
356
-						],
357
-					],
358
-					[
359
-						'UID' => 'uid1',
360
-						'FN' => 'User Name @ Localhost',
361
-						'EMAIL' => [
362
-							'user name@localhost',
363
-						],
364
-					],
365
-				],
366
-				false,
367
-				['emails' => [], 'exact' => ['emails' => []]],
368
-				false,
369
-				false,
370
-				false,
371
-			],
372
-			// data set 12
373
-			// remote with space, no contact
374
-			[
375
-				'user [email protected]',
376
-				[
377
-					[
378
-						'UID' => 'uid3',
379
-						'FN' => 'User3 @ Localhost',
380
-					],
381
-					[
382
-						'UID' => 'uid2',
383
-						'FN' => 'User2 @ Localhost',
384
-						'EMAIL' => [
385
-						],
386
-					],
387
-					[
388
-						'isLocalSystemBook' => true,
389
-						'UID' => 'uid1',
390
-						'FN' => 'User @ Localhost',
391
-						'EMAIL' => [
392
-							'username@localhost',
393
-						],
394
-					],
395
-				],
396
-				false,
397
-				['emails' => [], 'exact' => ['emails' => []]],
398
-				false,
399
-				false,
400
-				false,
401
-			],
402
-			// data set 13
403
-			// Local user found by email => no result
404
-			[
405
-				'[email protected]',
406
-				[
407
-					[
408
-						'UID' => 'uid1',
409
-						'FN' => 'User',
410
-						'EMAIL' => ['[email protected]'],
411
-						'CLOUD' => ['test@localhost'],
412
-						'isLocalSystemBook' => true,
413
-					]
414
-				],
415
-				false,
416
-				['exact' => []],
417
-				false,
418
-				false,
419
-				true,
420
-			],
421
-			// data set 14
422
-			// Current local user found by email => no result
423
-			[
424
-				'[email protected]',
425
-				[
426
-					[
427
-						'UID' => 'uid1',
428
-						'FN' => 'User',
429
-						'EMAIL' => ['[email protected]'],
430
-						'CLOUD' => ['current@localhost'],
431
-						'isLocalSystemBook' => true,
432
-					]
433
-				],
434
-				true,
435
-				['exact' => []],
436
-				false,
437
-				false,
438
-				true,
439
-			],
440
-			// data set 15
441
-			// Several local users found by email => no result nor pagination
442
-			[
443
-				'test@example',
444
-				[
445
-					[
446
-						'UID' => 'uid1',
447
-						'FN' => 'User1',
448
-						'EMAIL' => ['[email protected]'],
449
-						'CLOUD' => ['test1@localhost'],
450
-						'isLocalSystemBook' => true,
451
-					],
452
-					[
453
-						'UID' => 'uid2',
454
-						'FN' => 'User2',
455
-						'EMAIL' => ['[email protected]'],
456
-						'CLOUD' => ['test2@localhost'],
457
-						'isLocalSystemBook' => true,
458
-					],
459
-					[
460
-						'UID' => 'uid3',
461
-						'FN' => 'User3',
462
-						'EMAIL' => ['[email protected]'],
463
-						'CLOUD' => ['test3@localhost'],
464
-						'isLocalSystemBook' => true,
465
-					],
466
-					[
467
-						'UID' => 'uid4',
468
-						'FN' => 'User4',
469
-						'EMAIL' => ['[email protected]'],
470
-						'CLOUD' => ['test4@localhost'],
471
-						'isLocalSystemBook' => true,
472
-					],
473
-				],
474
-				true,
475
-				['emails' => [], 'exact' => ['emails' => []]],
476
-				false,
477
-				false,
478
-				false,
479
-			],
480
-			// data set 16
481
-			// Pagination and "more results" for normal emails
482
-			[
483
-				'test@example',
484
-				[
485
-					[
486
-						'UID' => 'uid1',
487
-						'FN' => 'User1',
488
-						'EMAIL' => ['[email protected]'],
489
-						'CLOUD' => ['test1@localhost'],
490
-					],
491
-					[
492
-						'UID' => 'uid2',
493
-						'FN' => 'User2',
494
-						'EMAIL' => ['[email protected]'],
495
-						'CLOUD' => ['test2@localhost'],
496
-					],
497
-					[
498
-						'UID' => 'uid3',
499
-						'FN' => 'User3',
500
-						'EMAIL' => ['[email protected]'],
501
-						'CLOUD' => ['test3@localhost'],
502
-					],
503
-					[
504
-						'UID' => 'uid4',
505
-						'FN' => 'User4',
506
-						'EMAIL' => ['[email protected]'],
507
-						'CLOUD' => ['test4@localhost'],
508
-					],
509
-				],
510
-				true,
511
-				['emails' => [
512
-					['uuid' => 'uid1', 'name' => 'User1', 'type' => '', 'label' => 'User1 ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']],
513
-					['uuid' => 'uid2', 'name' => 'User2', 'type' => '', 'label' => 'User2 ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']],
514
-				], 'exact' => ['emails' => []]],
515
-				false,
516
-				true,
517
-				false,
518
-			],
519
-			// data set 17
520
-			// multiple email addresses with type
521
-			[
522
-				'User Name',
523
-				[
524
-					[
525
-						'UID' => 'uid3',
526
-						'FN' => 'User3',
527
-					],
528
-					[
529
-						'UID' => 'uid2',
530
-						'FN' => 'User2',
531
-						'EMAIL' => [
532
-						],
533
-					],
534
-					[
535
-						'UID' => 'uid1',
536
-						'FN' => 'User Name',
537
-						'EMAIL' => [
538
-							['type' => 'HOME', 'value' => '[email protected]'],
539
-							['type' => 'WORK', 'value' => '[email protected]'],
540
-						],
541
-					],
542
-				],
543
-				false,
544
-				['emails' => [
545
-				], 'exact' => ['emails' => [
546
-					['name' => 'User Name', 'uuid' => 'uid1', 'type' => 'HOME', 'label' => 'User Name ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']],
547
-					['name' => 'User Name', 'uuid' => 'uid1', 'type' => 'WORK', 'label' => 'User Name ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]
548
-				]]],
549
-				false,
550
-				false,
551
-				false,
552
-			],
553
-			// data set 18
554
-			// idn email
555
-			[
556
-				'test@lölölölölölölöl.com',
557
-				[],
558
-				true,
559
-				['emails' => [], 'exact' => ['emails' => [['uuid' => 'test@lölölölölölölöl.com', 'label' => 'test@lölölölölölölöl.com', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => 'test@lölölölölölölöl.com']]]]],
560
-				false,
561
-				false,
562
-				true,
563
-			],
564
-		];
565
-	}
137
+    public static function dataSearchEmail(): array {
138
+        return [
139
+            // data set 0
140
+            ['test', [], true, ['emails' => [], 'exact' => ['emails' => []]], false, false, false],
141
+            // data set 1
142
+            ['test', [], false, ['emails' => [], 'exact' => ['emails' => []]], false, false, false],
143
+            // data set 2
144
+            [
145
+                '[email protected]',
146
+                [],
147
+                true,
148
+                ['emails' => [], 'exact' => ['emails' => [['uuid' => '[email protected]', 'label' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
149
+                false,
150
+                false,
151
+                true,
152
+            ],
153
+            // data set 3
154
+            [ // no valid email address
155
+                'test@remote',
156
+                [],
157
+                true,
158
+                ['emails' => [], 'exact' => ['emails' => []]],
159
+                false,
160
+                false,
161
+                false,
162
+            ],
163
+            // data set 4
164
+            [
165
+                '[email protected]',
166
+                [],
167
+                false,
168
+                ['emails' => [], 'exact' => ['emails' => [['uuid' => '[email protected]', 'label' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
169
+                false,
170
+                false,
171
+                true,
172
+            ],
173
+            // data set 5
174
+            [
175
+                'test',
176
+                [
177
+                    [
178
+                        'UID' => 'uid3',
179
+                        'FN' => 'User3 @ Localhost',
180
+                    ],
181
+                    [
182
+                        'UID' => 'uid2',
183
+                        'FN' => 'User2 @ Localhost',
184
+                        'EMAIL' => [
185
+                        ],
186
+                    ],
187
+                    [
188
+                        'UID' => 'uid1',
189
+                        'FN' => 'User @ Localhost',
190
+                        'EMAIL' => [
191
+                            '[email protected]',
192
+                        ],
193
+                    ],
194
+                ],
195
+                true,
196
+                ['emails' => [['uuid' => 'uid1', 'name' => 'User @ Localhost', 'type' => '', 'label' => 'User @ Localhost ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]], 'exact' => ['emails' => []]],
197
+                false,
198
+                false,
199
+                false,
200
+            ],
201
+            // data set 6
202
+            [
203
+                'test',
204
+                [
205
+                    [
206
+                        'UID' => 'uid3',
207
+                        'FN' => 'User3 @ Localhost',
208
+                    ],
209
+                    [
210
+                        'UID' => 'uid2',
211
+                        'FN' => 'User2 @ Localhost',
212
+                        'EMAIL' => [
213
+                        ],
214
+                    ],
215
+                    [
216
+                        'isLocalSystemBook' => true,
217
+                        'UID' => 'uid1',
218
+                        'FN' => 'User @ Localhost',
219
+                        'EMAIL' => [
220
+                            'username@localhost',
221
+                        ],
222
+                    ],
223
+                ],
224
+                false,
225
+                ['emails' => [], 'exact' => ['emails' => []]],
226
+                false,
227
+                false,
228
+                false,
229
+            ],
230
+            // data set 7
231
+            [
232
+                '[email protected]',
233
+                [
234
+                    [
235
+                        'UID' => 'uid3',
236
+                        'FN' => 'User3 @ example.com',
237
+                    ],
238
+                    [
239
+                        'UID' => 'uid2',
240
+                        'FN' => 'User2 @ example.com',
241
+                        'EMAIL' => [
242
+                        ],
243
+                    ],
244
+                    [
245
+                        'UID' => 'uid1',
246
+                        'FN' => 'User @ example.com',
247
+                        'EMAIL' => [
248
+                            '[email protected]',
249
+                        ],
250
+                    ],
251
+                ],
252
+                true,
253
+                ['emails' => [['uuid' => 'uid1', 'name' => 'User @ example.com', 'type' => '', 'label' => 'User @ example.com ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]], 'exact' => ['emails' => [['label' => '[email protected]', 'uuid' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
254
+                false,
255
+                false,
256
+                true,
257
+            ],
258
+            // data set 8
259
+            [
260
+                '[email protected]',
261
+                [
262
+                    [
263
+                        'UID' => 'uid3',
264
+                        'FN' => 'User3 @ Localhost',
265
+                    ],
266
+                    [
267
+                        'UID' => 'uid2',
268
+                        'FN' => 'User2 @ Localhost',
269
+                        'EMAIL' => [
270
+                        ],
271
+                    ],
272
+                    [
273
+                        'isLocalSystemBook' => true,
274
+                        'UID' => 'uid1',
275
+                        'FN' => 'User @ Localhost',
276
+                        'EMAIL' => [
277
+                            'username@localhost',
278
+                        ],
279
+                    ],
280
+                ],
281
+                false,
282
+                ['emails' => [], 'exact' => ['emails' => [['label' => '[email protected]', 'uuid' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
283
+                false,
284
+                false,
285
+                true,
286
+            ],
287
+            // data set 9
288
+            [
289
+                '[email protected]',
290
+                [
291
+                    [
292
+                        'UID' => 'uid3',
293
+                        'FN' => 'User3 @ example.com',
294
+                    ],
295
+                    [
296
+                        'UID' => 'uid2',
297
+                        'FN' => 'User2 @ example.com',
298
+                        'EMAIL' => [
299
+                        ],
300
+                    ],
301
+                    [
302
+                        'UID' => 'uid1',
303
+                        'FN' => 'User @ example.com',
304
+                        'EMAIL' => [
305
+                            '[email protected]',
306
+                        ],
307
+                    ],
308
+                ],
309
+                true,
310
+                ['emails' => [], 'exact' => ['emails' => [['name' => 'User @ example.com', 'uuid' => 'uid1', 'type' => '', 'label' => 'User @ example.com ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
311
+                true,
312
+                false,
313
+                false,
314
+            ],
315
+            // data set 10
316
+            [
317
+                '[email protected]',
318
+                [
319
+                    [
320
+                        'UID' => 'uid1',
321
+                        'FN' => 'User3 @ example.com',
322
+                    ],
323
+                    [
324
+                        'UID' => 'uid2',
325
+                        'FN' => 'User2 @ example.com',
326
+                        'EMAIL' => [
327
+                        ],
328
+                    ],
329
+                    [
330
+                        'UID' => 'uid1',
331
+                        'FN' => 'User @ example.com',
332
+                        'EMAIL' => [
333
+                            '[email protected]',
334
+                        ],
335
+                    ],
336
+                ],
337
+                false,
338
+                ['emails' => [], 'exact' => ['emails' => [['name' => 'User @ example.com', 'uuid' => 'uid1', 'type' => '', 'label' => 'User @ example.com ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
339
+                true,
340
+                false,
341
+                false,
342
+            ],
343
+            // data set 11
344
+            // contact with space
345
+            [
346
+                'user name@localhost',
347
+                [
348
+                    [
349
+                        'UID' => 'uid3',
350
+                        'FN' => 'User3 @ Localhost',
351
+                    ],
352
+                    [
353
+                        'UID' => 'uid2',
354
+                        'FN' => 'User2 @ Localhost',
355
+                        'EMAIL' => [
356
+                        ],
357
+                    ],
358
+                    [
359
+                        'UID' => 'uid1',
360
+                        'FN' => 'User Name @ Localhost',
361
+                        'EMAIL' => [
362
+                            'user name@localhost',
363
+                        ],
364
+                    ],
365
+                ],
366
+                false,
367
+                ['emails' => [], 'exact' => ['emails' => []]],
368
+                false,
369
+                false,
370
+                false,
371
+            ],
372
+            // data set 12
373
+            // remote with space, no contact
374
+            [
375
+                'user [email protected]',
376
+                [
377
+                    [
378
+                        'UID' => 'uid3',
379
+                        'FN' => 'User3 @ Localhost',
380
+                    ],
381
+                    [
382
+                        'UID' => 'uid2',
383
+                        'FN' => 'User2 @ Localhost',
384
+                        'EMAIL' => [
385
+                        ],
386
+                    ],
387
+                    [
388
+                        'isLocalSystemBook' => true,
389
+                        'UID' => 'uid1',
390
+                        'FN' => 'User @ Localhost',
391
+                        'EMAIL' => [
392
+                            'username@localhost',
393
+                        ],
394
+                    ],
395
+                ],
396
+                false,
397
+                ['emails' => [], 'exact' => ['emails' => []]],
398
+                false,
399
+                false,
400
+                false,
401
+            ],
402
+            // data set 13
403
+            // Local user found by email => no result
404
+            [
405
+                '[email protected]',
406
+                [
407
+                    [
408
+                        'UID' => 'uid1',
409
+                        'FN' => 'User',
410
+                        'EMAIL' => ['[email protected]'],
411
+                        'CLOUD' => ['test@localhost'],
412
+                        'isLocalSystemBook' => true,
413
+                    ]
414
+                ],
415
+                false,
416
+                ['exact' => []],
417
+                false,
418
+                false,
419
+                true,
420
+            ],
421
+            // data set 14
422
+            // Current local user found by email => no result
423
+            [
424
+                '[email protected]',
425
+                [
426
+                    [
427
+                        'UID' => 'uid1',
428
+                        'FN' => 'User',
429
+                        'EMAIL' => ['[email protected]'],
430
+                        'CLOUD' => ['current@localhost'],
431
+                        'isLocalSystemBook' => true,
432
+                    ]
433
+                ],
434
+                true,
435
+                ['exact' => []],
436
+                false,
437
+                false,
438
+                true,
439
+            ],
440
+            // data set 15
441
+            // Several local users found by email => no result nor pagination
442
+            [
443
+                'test@example',
444
+                [
445
+                    [
446
+                        'UID' => 'uid1',
447
+                        'FN' => 'User1',
448
+                        'EMAIL' => ['[email protected]'],
449
+                        'CLOUD' => ['test1@localhost'],
450
+                        'isLocalSystemBook' => true,
451
+                    ],
452
+                    [
453
+                        'UID' => 'uid2',
454
+                        'FN' => 'User2',
455
+                        'EMAIL' => ['[email protected]'],
456
+                        'CLOUD' => ['test2@localhost'],
457
+                        'isLocalSystemBook' => true,
458
+                    ],
459
+                    [
460
+                        'UID' => 'uid3',
461
+                        'FN' => 'User3',
462
+                        'EMAIL' => ['[email protected]'],
463
+                        'CLOUD' => ['test3@localhost'],
464
+                        'isLocalSystemBook' => true,
465
+                    ],
466
+                    [
467
+                        'UID' => 'uid4',
468
+                        'FN' => 'User4',
469
+                        'EMAIL' => ['[email protected]'],
470
+                        'CLOUD' => ['test4@localhost'],
471
+                        'isLocalSystemBook' => true,
472
+                    ],
473
+                ],
474
+                true,
475
+                ['emails' => [], 'exact' => ['emails' => []]],
476
+                false,
477
+                false,
478
+                false,
479
+            ],
480
+            // data set 16
481
+            // Pagination and "more results" for normal emails
482
+            [
483
+                'test@example',
484
+                [
485
+                    [
486
+                        'UID' => 'uid1',
487
+                        'FN' => 'User1',
488
+                        'EMAIL' => ['[email protected]'],
489
+                        'CLOUD' => ['test1@localhost'],
490
+                    ],
491
+                    [
492
+                        'UID' => 'uid2',
493
+                        'FN' => 'User2',
494
+                        'EMAIL' => ['[email protected]'],
495
+                        'CLOUD' => ['test2@localhost'],
496
+                    ],
497
+                    [
498
+                        'UID' => 'uid3',
499
+                        'FN' => 'User3',
500
+                        'EMAIL' => ['[email protected]'],
501
+                        'CLOUD' => ['test3@localhost'],
502
+                    ],
503
+                    [
504
+                        'UID' => 'uid4',
505
+                        'FN' => 'User4',
506
+                        'EMAIL' => ['[email protected]'],
507
+                        'CLOUD' => ['test4@localhost'],
508
+                    ],
509
+                ],
510
+                true,
511
+                ['emails' => [
512
+                    ['uuid' => 'uid1', 'name' => 'User1', 'type' => '', 'label' => 'User1 ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']],
513
+                    ['uuid' => 'uid2', 'name' => 'User2', 'type' => '', 'label' => 'User2 ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']],
514
+                ], 'exact' => ['emails' => []]],
515
+                false,
516
+                true,
517
+                false,
518
+            ],
519
+            // data set 17
520
+            // multiple email addresses with type
521
+            [
522
+                'User Name',
523
+                [
524
+                    [
525
+                        'UID' => 'uid3',
526
+                        'FN' => 'User3',
527
+                    ],
528
+                    [
529
+                        'UID' => 'uid2',
530
+                        'FN' => 'User2',
531
+                        'EMAIL' => [
532
+                        ],
533
+                    ],
534
+                    [
535
+                        'UID' => 'uid1',
536
+                        'FN' => 'User Name',
537
+                        'EMAIL' => [
538
+                            ['type' => 'HOME', 'value' => '[email protected]'],
539
+                            ['type' => 'WORK', 'value' => '[email protected]'],
540
+                        ],
541
+                    ],
542
+                ],
543
+                false,
544
+                ['emails' => [
545
+                ], 'exact' => ['emails' => [
546
+                    ['name' => 'User Name', 'uuid' => 'uid1', 'type' => 'HOME', 'label' => 'User Name ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']],
547
+                    ['name' => 'User Name', 'uuid' => 'uid1', 'type' => 'WORK', 'label' => 'User Name ([email protected])', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]
548
+                ]]],
549
+                false,
550
+                false,
551
+                false,
552
+            ],
553
+            // data set 18
554
+            // idn email
555
+            [
556
+                'test@lölölölölölölöl.com',
557
+                [],
558
+                true,
559
+                ['emails' => [], 'exact' => ['emails' => [['uuid' => 'test@lölölölölölölöl.com', 'label' => 'test@lölölölölölölöl.com', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => 'test@lölölölölölölöl.com']]]]],
560
+                false,
561
+                false,
562
+                true,
563
+            ],
564
+        ];
565
+    }
566 566
 
567
-	/**
568
-	 *
569
-	 * @param string $searchTerm
570
-	 * @param array $contacts
571
-	 * @param bool $shareeEnumeration
572
-	 * @param array $expectedResult
573
-	 * @param bool $expectedExactIdMatch
574
-	 * @param bool $expectedMoreResults
575
-	 */
576
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataSearchUser')]
577
-	public function testSearchUser($searchTerm, $contacts, $shareeEnumeration, $expectedResult, $expectedExactIdMatch, $expectedMoreResults): void {
578
-		$this->config->expects($this->any())
579
-			->method('getAppValue')
580
-			->willReturnCallback(
581
-				function ($appName, $key, $default) use ($shareeEnumeration) {
582
-					if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
583
-						return $shareeEnumeration ? 'yes' : 'no';
584
-					}
585
-					return $default;
586
-				}
587
-			);
567
+    /**
568
+     *
569
+     * @param string $searchTerm
570
+     * @param array $contacts
571
+     * @param bool $shareeEnumeration
572
+     * @param array $expectedResult
573
+     * @param bool $expectedExactIdMatch
574
+     * @param bool $expectedMoreResults
575
+     */
576
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataSearchUser')]
577
+    public function testSearchUser($searchTerm, $contacts, $shareeEnumeration, $expectedResult, $expectedExactIdMatch, $expectedMoreResults): void {
578
+        $this->config->expects($this->any())
579
+            ->method('getAppValue')
580
+            ->willReturnCallback(
581
+                function ($appName, $key, $default) use ($shareeEnumeration) {
582
+                    if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
583
+                        return $shareeEnumeration ? 'yes' : 'no';
584
+                    }
585
+                    return $default;
586
+                }
587
+            );
588 588
 
589
-		$this->instantiatePlugin(IShare::TYPE_USER);
589
+        $this->instantiatePlugin(IShare::TYPE_USER);
590 590
 
591
-		$currentUser = $this->createMock(IUser::class);
592
-		$currentUser->method('getUID')
593
-			->willReturn('current');
594
-		$this->userSession->method('getUser')
595
-			->willReturn($currentUser);
591
+        $currentUser = $this->createMock(IUser::class);
592
+        $currentUser->method('getUID')
593
+            ->willReturn('current');
594
+        $this->userSession->method('getUser')
595
+            ->willReturn($currentUser);
596 596
 
597
-		$this->contactsManager->expects($this->any())
598
-			->method('search')
599
-			->willReturnCallback(function ($search, $searchAttributes) use ($searchTerm, $contacts) {
600
-				if ($search === $searchTerm) {
601
-					return $contacts;
602
-				}
603
-				return [];
604
-			});
597
+        $this->contactsManager->expects($this->any())
598
+            ->method('search')
599
+            ->willReturnCallback(function ($search, $searchAttributes) use ($searchTerm, $contacts) {
600
+                if ($search === $searchTerm) {
601
+                    return $contacts;
602
+                }
603
+                return [];
604
+            });
605 605
 
606
-		$moreResults = $this->plugin->search($searchTerm, 2, 0, $this->searchResult);
607
-		$result = $this->searchResult->asArray();
606
+        $moreResults = $this->plugin->search($searchTerm, 2, 0, $this->searchResult);
607
+        $result = $this->searchResult->asArray();
608 608
 
609
-		$this->assertSame($expectedExactIdMatch, $this->searchResult->hasExactIdMatch(new SearchResultType('emails')));
610
-		$this->assertEquals($expectedResult, $result);
611
-		$this->assertSame($expectedMoreResults, $moreResults);
612
-	}
609
+        $this->assertSame($expectedExactIdMatch, $this->searchResult->hasExactIdMatch(new SearchResultType('emails')));
610
+        $this->assertEquals($expectedResult, $result);
611
+        $this->assertSame($expectedMoreResults, $moreResults);
612
+    }
613 613
 
614
-	public static function dataSearchUser(): array {
615
-		return [
616
-			// data set 0
617
-			['test', [], true, ['exact' => []], false, false],
618
-			// data set 1
619
-			['test', [], false, ['exact' => []], false, false],
620
-			// data set 2
621
-			[
622
-				'[email protected]',
623
-				[],
624
-				true,
625
-				['exact' => []],
626
-				false,
627
-				false,
628
-			],
629
-			// data set 3
630
-			[
631
-				'[email protected]',
632
-				[],
633
-				false,
634
-				['exact' => []],
635
-				false,
636
-				false,
637
-			],
638
-			// data set 4
639
-			[
640
-				'test',
641
-				[
642
-					[
643
-						'UID' => 'uid3',
644
-						'FN' => 'User3 @ Localhost',
645
-					],
646
-					[
647
-						'UID' => 'uid2',
648
-						'FN' => 'User2 @ Localhost',
649
-						'EMAIL' => [
650
-						],
651
-					],
652
-					[
653
-						'UID' => 'uid1',
654
-						'FN' => 'User @ Localhost',
655
-						'EMAIL' => [
656
-							'username@localhost',
657
-						],
658
-					],
659
-				],
660
-				true,
661
-				['exact' => []],
662
-				false,
663
-				false,
664
-			],
665
-			// data set 5
666
-			[
667
-				'test',
668
-				[
669
-					[
670
-						'UID' => 'uid3',
671
-						'FN' => 'User3 @ Localhost',
672
-					],
673
-					[
674
-						'UID' => 'uid2',
675
-						'FN' => 'User2 @ Localhost',
676
-						'EMAIL' => [
677
-						],
678
-					],
679
-					[
680
-						'isLocalSystemBook' => true,
681
-						'UID' => 'uid1',
682
-						'FN' => 'User @ Localhost',
683
-						'EMAIL' => [
684
-							'username@localhost',
685
-						],
686
-					],
687
-				],
688
-				false,
689
-				['exact' => []],
690
-				false,
691
-				false,
692
-			],
693
-			// data set 6
694
-			[
695
-				'[email protected]',
696
-				[
697
-					[
698
-						'UID' => 'uid3',
699
-						'FN' => 'User3 @ Localhost',
700
-					],
701
-					[
702
-						'UID' => 'uid2',
703
-						'FN' => 'User2 @ Localhost',
704
-						'EMAIL' => [
705
-						],
706
-					],
707
-					[
708
-						'UID' => 'uid1',
709
-						'FN' => 'User @ Localhost',
710
-						'EMAIL' => [
711
-							'username@localhost',
712
-						],
713
-					],
714
-				],
715
-				true,
716
-				['exact' => []],
717
-				false,
718
-				false,
719
-			],
720
-			// data set 7
721
-			[
722
-				'username@localhost',
723
-				[
724
-					[
725
-						'UID' => 'uid3',
726
-						'FN' => 'User3 @ Localhost',
727
-					],
728
-					[
729
-						'UID' => 'uid2',
730
-						'FN' => 'User2 @ Localhost',
731
-						'EMAIL' => [
732
-						],
733
-					],
734
-					[
735
-						'UID' => 'uid1',
736
-						'FN' => 'User @ Localhost',
737
-						'EMAIL' => [
738
-							'username@localhost',
739
-						],
740
-					],
741
-				],
742
-				true,
743
-				['exact' => []],
744
-				false,
745
-				false,
746
-			],
747
-			// data set 8
748
-			// Local user found by email
749
-			[
750
-				'[email protected]',
751
-				[
752
-					[
753
-						'UID' => 'uid1',
754
-						'FN' => 'User',
755
-						'EMAIL' => ['[email protected]'],
756
-						'CLOUD' => ['test@localhost'],
757
-						'isLocalSystemBook' => true,
758
-					]
759
-				],
760
-				false,
761
-				['users' => [], 'exact' => ['users' => [['uuid' => 'uid1', 'name' => 'User', 'label' => 'User ([email protected])','value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'], 'shareWithDisplayNameUnique' => '[email protected]']]]],
762
-				true,
763
-				false,
764
-			],
765
-			// data set 9
766
-			// Current local user found by email => no result
767
-			[
768
-				'[email protected]',
769
-				[
770
-					[
771
-						'UID' => 'uid1',
772
-						'FN' => 'User',
773
-						'EMAIL' => ['[email protected]'],
774
-						'CLOUD' => ['current@localhost'],
775
-						'isLocalSystemBook' => true,
776
-					]
777
-				],
778
-				true,
779
-				['exact' => []],
780
-				false,
781
-				false,
782
-			],
783
-			// data set 10
784
-			// Pagination and "more results" for user matches by emails
785
-			[
786
-				'test@example',
787
-				[
788
-					[
789
-						'UID' => 'uid1',
790
-						'FN' => 'User1',
791
-						'EMAIL' => ['[email protected]'],
792
-						'CLOUD' => ['test1@localhost'],
793
-						'isLocalSystemBook' => true,
794
-					],
795
-					[
796
-						'UID' => 'uid2',
797
-						'FN' => 'User2',
798
-						'EMAIL' => ['[email protected]'],
799
-						'CLOUD' => ['test2@localhost'],
800
-						'isLocalSystemBook' => true,
801
-					],
802
-					[
803
-						'UID' => 'uid3',
804
-						'FN' => 'User3',
805
-						'EMAIL' => ['[email protected]'],
806
-						'CLOUD' => ['test3@localhost'],
807
-						'isLocalSystemBook' => true,
808
-					],
809
-					[
810
-						'UID' => 'uid4',
811
-						'FN' => 'User4',
812
-						'EMAIL' => ['[email protected]'],
813
-						'CLOUD' => ['test4@localhost'],
814
-						'isLocalSystemBook' => true,
815
-					],
816
-				],
817
-				true,
818
-				['users' => [
819
-					['uuid' => 'uid1', 'name' => 'User1', 'label' => 'User1 ([email protected])', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test1'], 'shareWithDisplayNameUnique' => '[email protected]'],
820
-					['uuid' => 'uid2', 'name' => 'User2', 'label' => 'User2 ([email protected])', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test2'], 'shareWithDisplayNameUnique' => '[email protected]'],
821
-				], 'exact' => ['users' => []]],
822
-				false,
823
-				true,
824
-			],
825
-			// data set 11
826
-			// Pagination and "more results" for normal emails
827
-			[
828
-				'test@example',
829
-				[
830
-					[
831
-						'UID' => 'uid1',
832
-						'FN' => 'User1',
833
-						'EMAIL' => ['[email protected]'],
834
-						'CLOUD' => ['test1@localhost'],
835
-					],
836
-					[
837
-						'UID' => 'uid2',
838
-						'FN' => 'User2',
839
-						'EMAIL' => ['[email protected]'],
840
-						'CLOUD' => ['test2@localhost'],
841
-					],
842
-					[
843
-						'UID' => 'uid3',
844
-						'FN' => 'User3',
845
-						'EMAIL' => ['[email protected]'],
846
-						'CLOUD' => ['test3@localhost'],
847
-					],
848
-					[
849
-						'UID' => 'uid4',
850
-						'FN' => 'User4',
851
-						'EMAIL' => ['[email protected]'],
852
-						'CLOUD' => ['test4@localhost'],
853
-					],
854
-				],
855
-				true,
856
-				['exact' => []],
857
-				false,
858
-				false,
859
-			],
860
-		];
861
-	}
614
+    public static function dataSearchUser(): array {
615
+        return [
616
+            // data set 0
617
+            ['test', [], true, ['exact' => []], false, false],
618
+            // data set 1
619
+            ['test', [], false, ['exact' => []], false, false],
620
+            // data set 2
621
+            [
622
+                '[email protected]',
623
+                [],
624
+                true,
625
+                ['exact' => []],
626
+                false,
627
+                false,
628
+            ],
629
+            // data set 3
630
+            [
631
+                '[email protected]',
632
+                [],
633
+                false,
634
+                ['exact' => []],
635
+                false,
636
+                false,
637
+            ],
638
+            // data set 4
639
+            [
640
+                'test',
641
+                [
642
+                    [
643
+                        'UID' => 'uid3',
644
+                        'FN' => 'User3 @ Localhost',
645
+                    ],
646
+                    [
647
+                        'UID' => 'uid2',
648
+                        'FN' => 'User2 @ Localhost',
649
+                        'EMAIL' => [
650
+                        ],
651
+                    ],
652
+                    [
653
+                        'UID' => 'uid1',
654
+                        'FN' => 'User @ Localhost',
655
+                        'EMAIL' => [
656
+                            'username@localhost',
657
+                        ],
658
+                    ],
659
+                ],
660
+                true,
661
+                ['exact' => []],
662
+                false,
663
+                false,
664
+            ],
665
+            // data set 5
666
+            [
667
+                'test',
668
+                [
669
+                    [
670
+                        'UID' => 'uid3',
671
+                        'FN' => 'User3 @ Localhost',
672
+                    ],
673
+                    [
674
+                        'UID' => 'uid2',
675
+                        'FN' => 'User2 @ Localhost',
676
+                        'EMAIL' => [
677
+                        ],
678
+                    ],
679
+                    [
680
+                        'isLocalSystemBook' => true,
681
+                        'UID' => 'uid1',
682
+                        'FN' => 'User @ Localhost',
683
+                        'EMAIL' => [
684
+                            'username@localhost',
685
+                        ],
686
+                    ],
687
+                ],
688
+                false,
689
+                ['exact' => []],
690
+                false,
691
+                false,
692
+            ],
693
+            // data set 6
694
+            [
695
+                '[email protected]',
696
+                [
697
+                    [
698
+                        'UID' => 'uid3',
699
+                        'FN' => 'User3 @ Localhost',
700
+                    ],
701
+                    [
702
+                        'UID' => 'uid2',
703
+                        'FN' => 'User2 @ Localhost',
704
+                        'EMAIL' => [
705
+                        ],
706
+                    ],
707
+                    [
708
+                        'UID' => 'uid1',
709
+                        'FN' => 'User @ Localhost',
710
+                        'EMAIL' => [
711
+                            'username@localhost',
712
+                        ],
713
+                    ],
714
+                ],
715
+                true,
716
+                ['exact' => []],
717
+                false,
718
+                false,
719
+            ],
720
+            // data set 7
721
+            [
722
+                'username@localhost',
723
+                [
724
+                    [
725
+                        'UID' => 'uid3',
726
+                        'FN' => 'User3 @ Localhost',
727
+                    ],
728
+                    [
729
+                        'UID' => 'uid2',
730
+                        'FN' => 'User2 @ Localhost',
731
+                        'EMAIL' => [
732
+                        ],
733
+                    ],
734
+                    [
735
+                        'UID' => 'uid1',
736
+                        'FN' => 'User @ Localhost',
737
+                        'EMAIL' => [
738
+                            'username@localhost',
739
+                        ],
740
+                    ],
741
+                ],
742
+                true,
743
+                ['exact' => []],
744
+                false,
745
+                false,
746
+            ],
747
+            // data set 8
748
+            // Local user found by email
749
+            [
750
+                '[email protected]',
751
+                [
752
+                    [
753
+                        'UID' => 'uid1',
754
+                        'FN' => 'User',
755
+                        'EMAIL' => ['[email protected]'],
756
+                        'CLOUD' => ['test@localhost'],
757
+                        'isLocalSystemBook' => true,
758
+                    ]
759
+                ],
760
+                false,
761
+                ['users' => [], 'exact' => ['users' => [['uuid' => 'uid1', 'name' => 'User', 'label' => 'User ([email protected])','value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'], 'shareWithDisplayNameUnique' => '[email protected]']]]],
762
+                true,
763
+                false,
764
+            ],
765
+            // data set 9
766
+            // Current local user found by email => no result
767
+            [
768
+                '[email protected]',
769
+                [
770
+                    [
771
+                        'UID' => 'uid1',
772
+                        'FN' => 'User',
773
+                        'EMAIL' => ['[email protected]'],
774
+                        'CLOUD' => ['current@localhost'],
775
+                        'isLocalSystemBook' => true,
776
+                    ]
777
+                ],
778
+                true,
779
+                ['exact' => []],
780
+                false,
781
+                false,
782
+            ],
783
+            // data set 10
784
+            // Pagination and "more results" for user matches by emails
785
+            [
786
+                'test@example',
787
+                [
788
+                    [
789
+                        'UID' => 'uid1',
790
+                        'FN' => 'User1',
791
+                        'EMAIL' => ['[email protected]'],
792
+                        'CLOUD' => ['test1@localhost'],
793
+                        'isLocalSystemBook' => true,
794
+                    ],
795
+                    [
796
+                        'UID' => 'uid2',
797
+                        'FN' => 'User2',
798
+                        'EMAIL' => ['[email protected]'],
799
+                        'CLOUD' => ['test2@localhost'],
800
+                        'isLocalSystemBook' => true,
801
+                    ],
802
+                    [
803
+                        'UID' => 'uid3',
804
+                        'FN' => 'User3',
805
+                        'EMAIL' => ['[email protected]'],
806
+                        'CLOUD' => ['test3@localhost'],
807
+                        'isLocalSystemBook' => true,
808
+                    ],
809
+                    [
810
+                        'UID' => 'uid4',
811
+                        'FN' => 'User4',
812
+                        'EMAIL' => ['[email protected]'],
813
+                        'CLOUD' => ['test4@localhost'],
814
+                        'isLocalSystemBook' => true,
815
+                    ],
816
+                ],
817
+                true,
818
+                ['users' => [
819
+                    ['uuid' => 'uid1', 'name' => 'User1', 'label' => 'User1 ([email protected])', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test1'], 'shareWithDisplayNameUnique' => '[email protected]'],
820
+                    ['uuid' => 'uid2', 'name' => 'User2', 'label' => 'User2 ([email protected])', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test2'], 'shareWithDisplayNameUnique' => '[email protected]'],
821
+                ], 'exact' => ['users' => []]],
822
+                false,
823
+                true,
824
+            ],
825
+            // data set 11
826
+            // Pagination and "more results" for normal emails
827
+            [
828
+                'test@example',
829
+                [
830
+                    [
831
+                        'UID' => 'uid1',
832
+                        'FN' => 'User1',
833
+                        'EMAIL' => ['[email protected]'],
834
+                        'CLOUD' => ['test1@localhost'],
835
+                    ],
836
+                    [
837
+                        'UID' => 'uid2',
838
+                        'FN' => 'User2',
839
+                        'EMAIL' => ['[email protected]'],
840
+                        'CLOUD' => ['test2@localhost'],
841
+                    ],
842
+                    [
843
+                        'UID' => 'uid3',
844
+                        'FN' => 'User3',
845
+                        'EMAIL' => ['[email protected]'],
846
+                        'CLOUD' => ['test3@localhost'],
847
+                    ],
848
+                    [
849
+                        'UID' => 'uid4',
850
+                        'FN' => 'User4',
851
+                        'EMAIL' => ['[email protected]'],
852
+                        'CLOUD' => ['test4@localhost'],
853
+                    ],
854
+                ],
855
+                true,
856
+                ['exact' => []],
857
+                false,
858
+                false,
859
+            ],
860
+        ];
861
+    }
862 862
 
863
-	/**
864
-	 *
865
-	 * @param string $searchTerm
866
-	 * @param array $contacts
867
-	 * @param array $expectedResult
868
-	 * @param bool $expectedExactIdMatch
869
-	 * @param bool $expectedMoreResults
870
-	 * @param array $userToGroupMapping
871
-	 * @param bool $validEmail
872
-	 */
873
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataSearchEmailGroupsOnly')]
874
-	public function testSearchEmailGroupsOnly($searchTerm, $contacts, $expectedResult, $expectedExactIdMatch, $expectedMoreResults, $userToGroupMapping, $validEmail): void {
875
-		$this->config->expects($this->any())
876
-			->method('getAppValue')
877
-			->willReturnCallback(
878
-				function ($appName, $key, $default) {
879
-					if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
880
-						return 'yes';
881
-					} elseif ($appName === 'core' && $key === 'shareapi_only_share_with_group_members') {
882
-						return 'yes';
883
-					}
884
-					return $default;
885
-				}
886
-			);
863
+    /**
864
+     *
865
+     * @param string $searchTerm
866
+     * @param array $contacts
867
+     * @param array $expectedResult
868
+     * @param bool $expectedExactIdMatch
869
+     * @param bool $expectedMoreResults
870
+     * @param array $userToGroupMapping
871
+     * @param bool $validEmail
872
+     */
873
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataSearchEmailGroupsOnly')]
874
+    public function testSearchEmailGroupsOnly($searchTerm, $contacts, $expectedResult, $expectedExactIdMatch, $expectedMoreResults, $userToGroupMapping, $validEmail): void {
875
+        $this->config->expects($this->any())
876
+            ->method('getAppValue')
877
+            ->willReturnCallback(
878
+                function ($appName, $key, $default) {
879
+                    if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
880
+                        return 'yes';
881
+                    } elseif ($appName === 'core' && $key === 'shareapi_only_share_with_group_members') {
882
+                        return 'yes';
883
+                    }
884
+                    return $default;
885
+                }
886
+            );
887 887
 
888
-		$this->instantiatePlugin(IShare::TYPE_EMAIL);
888
+        $this->instantiatePlugin(IShare::TYPE_EMAIL);
889 889
 
890
-		/** @var IUser|\PHPUnit\Framework\MockObject\MockObject */
891
-		$currentUser = $this->createMock('\OCP\IUser');
890
+        /** @var IUser|\PHPUnit\Framework\MockObject\MockObject */
891
+        $currentUser = $this->createMock('\OCP\IUser');
892 892
 
893
-		$currentUser->expects($this->any())
894
-			->method('getUID')
895
-			->willReturn('currentUser');
893
+        $currentUser->expects($this->any())
894
+            ->method('getUID')
895
+            ->willReturn('currentUser');
896 896
 
897
-		$this->contactsManager->expects($this->any())
898
-			->method('search')
899
-			->willReturnCallback(function ($search, $searchAttributes) use ($searchTerm, $contacts) {
900
-				if ($search === $searchTerm) {
901
-					return $contacts;
902
-				}
903
-				return [];
904
-			});
897
+        $this->contactsManager->expects($this->any())
898
+            ->method('search')
899
+            ->willReturnCallback(function ($search, $searchAttributes) use ($searchTerm, $contacts) {
900
+                if ($search === $searchTerm) {
901
+                    return $contacts;
902
+                }
903
+                return [];
904
+            });
905 905
 
906
-		$this->userSession->expects($this->any())
907
-			->method('getUser')
908
-			->willReturn($currentUser);
906
+        $this->userSession->expects($this->any())
907
+            ->method('getUser')
908
+            ->willReturn($currentUser);
909 909
 
910
-		$this->groupManager->expects($this->any())
911
-			->method('getUserGroupIds')
912
-			->willReturnCallback(function (IUser $user) use ($userToGroupMapping) {
913
-				return $userToGroupMapping[$user->getUID()];
914
-			});
910
+        $this->groupManager->expects($this->any())
911
+            ->method('getUserGroupIds')
912
+            ->willReturnCallback(function (IUser $user) use ($userToGroupMapping) {
913
+                return $userToGroupMapping[$user->getUID()];
914
+            });
915 915
 
916
-		$this->groupManager->expects($this->any())
917
-			->method('isInGroup')
918
-			->willReturnCallback(function ($userId, $group) use ($userToGroupMapping) {
919
-				return in_array($group, $userToGroupMapping[$userId]);
920
-			});
916
+        $this->groupManager->expects($this->any())
917
+            ->method('isInGroup')
918
+            ->willReturnCallback(function ($userId, $group) use ($userToGroupMapping) {
919
+                return in_array($group, $userToGroupMapping[$userId]);
920
+            });
921 921
 
922
-		$moreResults = $this->plugin->search($searchTerm, 2, 0, $this->searchResult);
923
-		$result = $this->searchResult->asArray();
922
+        $moreResults = $this->plugin->search($searchTerm, 2, 0, $this->searchResult);
923
+        $result = $this->searchResult->asArray();
924 924
 
925
-		$this->assertSame($expectedExactIdMatch, $this->searchResult->hasExactIdMatch(new SearchResultType('emails')));
926
-		$this->assertEquals($expectedResult, $result);
927
-		$this->assertSame($expectedMoreResults, $moreResults);
928
-	}
925
+        $this->assertSame($expectedExactIdMatch, $this->searchResult->hasExactIdMatch(new SearchResultType('emails')));
926
+        $this->assertEquals($expectedResult, $result);
927
+        $this->assertSame($expectedMoreResults, $moreResults);
928
+    }
929 929
 
930
-	public static function dataSearchEmailGroupsOnly(): array {
931
-		return [
932
-			// The user `User` can share with the current user
933
-			[
934
-				'test',
935
-				[
936
-					[
937
-						'FN' => 'User',
938
-						'EMAIL' => ['[email protected]'],
939
-						'CLOUD' => ['test@localhost'],
940
-						'isLocalSystemBook' => true,
941
-						'UID' => 'User',
942
-					]
943
-				],
944
-				['emails' => [], 'exact' => ['emails' => []]],
945
-				false,
946
-				false,
947
-				[
948
-					'currentUser' => ['group1'],
949
-					'User' => ['group1'],
950
-				],
951
-				false,
952
-			],
953
-			// The user `User` cannot share with the current user
954
-			[
955
-				'test',
956
-				[
957
-					[
958
-						'FN' => 'User',
959
-						'EMAIL' => ['[email protected]'],
960
-						'CLOUD' => ['test@localhost'],
961
-						'isLocalSystemBook' => true,
962
-						'UID' => 'User',
963
-					]
964
-				],
965
-				['emails' => [], 'exact' => ['emails' => []]],
966
-				false,
967
-				false,
968
-				[
969
-					'currentUser' => ['group1'],
970
-					'User' => ['group2'],
971
-				],
972
-				false,
973
-			],
974
-			// The user `User` cannot share with the current user, but there is an exact match on the e-mail address -> share by e-mail
975
-			[
976
-				'[email protected]',
977
-				[
978
-					[
979
-						'FN' => 'User',
980
-						'EMAIL' => ['[email protected]'],
981
-						'CLOUD' => ['test@localhost'],
982
-						'isLocalSystemBook' => true,
983
-						'UID' => 'User',
984
-					]
985
-				],
986
-				['emails' => [], 'exact' => ['emails' => [['label' => '[email protected]', 'uuid' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL,'shareWith' => '[email protected]']]]]],
987
-				false,
988
-				false,
989
-				[
990
-					'currentUser' => ['group1'],
991
-					'User' => ['group2'],
992
-				],
993
-				true,
994
-			]
995
-		];
996
-	}
930
+    public static function dataSearchEmailGroupsOnly(): array {
931
+        return [
932
+            // The user `User` can share with the current user
933
+            [
934
+                'test',
935
+                [
936
+                    [
937
+                        'FN' => 'User',
938
+                        'EMAIL' => ['[email protected]'],
939
+                        'CLOUD' => ['test@localhost'],
940
+                        'isLocalSystemBook' => true,
941
+                        'UID' => 'User',
942
+                    ]
943
+                ],
944
+                ['emails' => [], 'exact' => ['emails' => []]],
945
+                false,
946
+                false,
947
+                [
948
+                    'currentUser' => ['group1'],
949
+                    'User' => ['group1'],
950
+                ],
951
+                false,
952
+            ],
953
+            // The user `User` cannot share with the current user
954
+            [
955
+                'test',
956
+                [
957
+                    [
958
+                        'FN' => 'User',
959
+                        'EMAIL' => ['[email protected]'],
960
+                        'CLOUD' => ['test@localhost'],
961
+                        'isLocalSystemBook' => true,
962
+                        'UID' => 'User',
963
+                    ]
964
+                ],
965
+                ['emails' => [], 'exact' => ['emails' => []]],
966
+                false,
967
+                false,
968
+                [
969
+                    'currentUser' => ['group1'],
970
+                    'User' => ['group2'],
971
+                ],
972
+                false,
973
+            ],
974
+            // The user `User` cannot share with the current user, but there is an exact match on the e-mail address -> share by e-mail
975
+            [
976
+                '[email protected]',
977
+                [
978
+                    [
979
+                        'FN' => 'User',
980
+                        'EMAIL' => ['[email protected]'],
981
+                        'CLOUD' => ['test@localhost'],
982
+                        'isLocalSystemBook' => true,
983
+                        'UID' => 'User',
984
+                    ]
985
+                ],
986
+                ['emails' => [], 'exact' => ['emails' => [['label' => '[email protected]', 'uuid' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL,'shareWith' => '[email protected]']]]]],
987
+                false,
988
+                false,
989
+                [
990
+                    'currentUser' => ['group1'],
991
+                    'User' => ['group2'],
992
+                ],
993
+                true,
994
+            ]
995
+        ];
996
+    }
997 997
 
998
-	/**
999
-	 *
1000
-	 * @param string $searchTerm
1001
-	 * @param array $contacts
1002
-	 * @param array $expectedResult
1003
-	 * @param bool $expectedExactIdMatch
1004
-	 * @param bool $expectedMoreResults
1005
-	 * @param array $userToGroupMapping
1006
-	 */
1007
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataSearchUserGroupsOnly')]
1008
-	public function testSearchUserGroupsOnly($searchTerm, $contacts, $expectedResult, $expectedExactIdMatch, $expectedMoreResults, $userToGroupMapping): void {
1009
-		$this->config->expects($this->any())
1010
-			->method('getAppValue')
1011
-			->willReturnCallback(
1012
-				function ($appName, $key, $default) {
1013
-					if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
1014
-						return 'yes';
1015
-					} elseif ($appName === 'core' && $key === 'shareapi_only_share_with_group_members') {
1016
-						return 'yes';
1017
-					}
1018
-					return $default;
1019
-				}
1020
-			);
998
+    /**
999
+     *
1000
+     * @param string $searchTerm
1001
+     * @param array $contacts
1002
+     * @param array $expectedResult
1003
+     * @param bool $expectedExactIdMatch
1004
+     * @param bool $expectedMoreResults
1005
+     * @param array $userToGroupMapping
1006
+     */
1007
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataSearchUserGroupsOnly')]
1008
+    public function testSearchUserGroupsOnly($searchTerm, $contacts, $expectedResult, $expectedExactIdMatch, $expectedMoreResults, $userToGroupMapping): void {
1009
+        $this->config->expects($this->any())
1010
+            ->method('getAppValue')
1011
+            ->willReturnCallback(
1012
+                function ($appName, $key, $default) {
1013
+                    if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
1014
+                        return 'yes';
1015
+                    } elseif ($appName === 'core' && $key === 'shareapi_only_share_with_group_members') {
1016
+                        return 'yes';
1017
+                    }
1018
+                    return $default;
1019
+                }
1020
+            );
1021 1021
 
1022
-		$this->instantiatePlugin(IShare::TYPE_USER);
1022
+        $this->instantiatePlugin(IShare::TYPE_USER);
1023 1023
 
1024
-		/** @var IUser|\PHPUnit\Framework\MockObject\MockObject */
1025
-		$currentUser = $this->createMock('\OCP\IUser');
1024
+        /** @var IUser|\PHPUnit\Framework\MockObject\MockObject */
1025
+        $currentUser = $this->createMock('\OCP\IUser');
1026 1026
 
1027
-		$currentUser->expects($this->any())
1028
-			->method('getUID')
1029
-			->willReturn('currentUser');
1027
+        $currentUser->expects($this->any())
1028
+            ->method('getUID')
1029
+            ->willReturn('currentUser');
1030 1030
 
1031
-		$this->contactsManager->expects($this->any())
1032
-			->method('search')
1033
-			->willReturnCallback(function ($search, $searchAttributes) use ($searchTerm, $contacts) {
1034
-				if ($search === $searchTerm) {
1035
-					return $contacts;
1036
-				}
1037
-				return [];
1038
-			});
1031
+        $this->contactsManager->expects($this->any())
1032
+            ->method('search')
1033
+            ->willReturnCallback(function ($search, $searchAttributes) use ($searchTerm, $contacts) {
1034
+                if ($search === $searchTerm) {
1035
+                    return $contacts;
1036
+                }
1037
+                return [];
1038
+            });
1039 1039
 
1040
-		$this->userSession->expects($this->any())
1041
-			->method('getUser')
1042
-			->willReturn($currentUser);
1040
+        $this->userSession->expects($this->any())
1041
+            ->method('getUser')
1042
+            ->willReturn($currentUser);
1043 1043
 
1044
-		$this->groupManager->expects($this->any())
1045
-			->method('getUserGroupIds')
1046
-			->willReturnCallback(function (IUser $user) use ($userToGroupMapping) {
1047
-				return $userToGroupMapping[$user->getUID()];
1048
-			});
1044
+        $this->groupManager->expects($this->any())
1045
+            ->method('getUserGroupIds')
1046
+            ->willReturnCallback(function (IUser $user) use ($userToGroupMapping) {
1047
+                return $userToGroupMapping[$user->getUID()];
1048
+            });
1049 1049
 
1050
-		$this->groupManager->expects($this->any())
1051
-			->method('isInGroup')
1052
-			->willReturnCallback(function ($userId, $group) use ($userToGroupMapping) {
1053
-				return in_array($group, $userToGroupMapping[$userId]);
1054
-			});
1050
+        $this->groupManager->expects($this->any())
1051
+            ->method('isInGroup')
1052
+            ->willReturnCallback(function ($userId, $group) use ($userToGroupMapping) {
1053
+                return in_array($group, $userToGroupMapping[$userId]);
1054
+            });
1055 1055
 
1056
-		$moreResults = $this->plugin->search($searchTerm, 2, 0, $this->searchResult);
1057
-		$result = $this->searchResult->asArray();
1056
+        $moreResults = $this->plugin->search($searchTerm, 2, 0, $this->searchResult);
1057
+        $result = $this->searchResult->asArray();
1058 1058
 
1059
-		$this->assertSame($expectedExactIdMatch, $this->searchResult->hasExactIdMatch(new SearchResultType('emails')));
1060
-		$this->assertEquals($expectedResult, $result);
1061
-		$this->assertSame($expectedMoreResults, $moreResults);
1062
-	}
1059
+        $this->assertSame($expectedExactIdMatch, $this->searchResult->hasExactIdMatch(new SearchResultType('emails')));
1060
+        $this->assertEquals($expectedResult, $result);
1061
+        $this->assertSame($expectedMoreResults, $moreResults);
1062
+    }
1063 1063
 
1064
-	public static function dataSearchUserGroupsOnly(): array {
1065
-		return [
1066
-			// The user `User` can share with the current user
1067
-			[
1068
-				'test',
1069
-				[
1070
-					[
1071
-						'FN' => 'User',
1072
-						'EMAIL' => ['[email protected]'],
1073
-						'CLOUD' => ['test@localhost'],
1074
-						'isLocalSystemBook' => true,
1075
-						'UID' => 'User',
1076
-					]
1077
-				],
1078
-				['users' => [['label' => 'User ([email protected])', 'uuid' => 'User', 'name' => 'User', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'],'shareWithDisplayNameUnique' => '[email protected]',]], 'exact' => ['users' => []]],
1079
-				false,
1080
-				false,
1081
-				[
1082
-					'currentUser' => ['group1'],
1083
-					'User' => ['group1'],
1084
-				],
1085
-			],
1086
-			// The user `User` cannot share with the current user
1087
-			[
1088
-				'test',
1089
-				[
1090
-					[
1091
-						'FN' => 'User',
1092
-						'EMAIL' => ['[email protected]'],
1093
-						'CLOUD' => ['test@localhost'],
1094
-						'isLocalSystemBook' => true,
1095
-						'UID' => 'User',
1096
-					]
1097
-				],
1098
-				['exact' => []],
1099
-				false,
1100
-				false,
1101
-				[
1102
-					'currentUser' => ['group1'],
1103
-					'User' => ['group2'],
1104
-				],
1105
-			],
1106
-			// The user `User` cannot share with the current user, but there is an exact match on the e-mail address -> share by e-mail
1107
-			[
1108
-				'[email protected]',
1109
-				[
1110
-					[
1111
-						'FN' => 'User',
1112
-						'EMAIL' => ['[email protected]'],
1113
-						'CLOUD' => ['test@localhost'],
1114
-						'isLocalSystemBook' => true,
1115
-						'UID' => 'User',
1116
-					]
1117
-				],
1118
-				['exact' => []],
1119
-				false,
1120
-				false,
1121
-				[
1122
-					'currentUser' => ['group1'],
1123
-					'User' => ['group2'],
1124
-				],
1125
-			]
1126
-		];
1127
-	}
1064
+    public static function dataSearchUserGroupsOnly(): array {
1065
+        return [
1066
+            // The user `User` can share with the current user
1067
+            [
1068
+                'test',
1069
+                [
1070
+                    [
1071
+                        'FN' => 'User',
1072
+                        'EMAIL' => ['[email protected]'],
1073
+                        'CLOUD' => ['test@localhost'],
1074
+                        'isLocalSystemBook' => true,
1075
+                        'UID' => 'User',
1076
+                    ]
1077
+                ],
1078
+                ['users' => [['label' => 'User ([email protected])', 'uuid' => 'User', 'name' => 'User', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'],'shareWithDisplayNameUnique' => '[email protected]',]], 'exact' => ['users' => []]],
1079
+                false,
1080
+                false,
1081
+                [
1082
+                    'currentUser' => ['group1'],
1083
+                    'User' => ['group1'],
1084
+                ],
1085
+            ],
1086
+            // The user `User` cannot share with the current user
1087
+            [
1088
+                'test',
1089
+                [
1090
+                    [
1091
+                        'FN' => 'User',
1092
+                        'EMAIL' => ['[email protected]'],
1093
+                        'CLOUD' => ['test@localhost'],
1094
+                        'isLocalSystemBook' => true,
1095
+                        'UID' => 'User',
1096
+                    ]
1097
+                ],
1098
+                ['exact' => []],
1099
+                false,
1100
+                false,
1101
+                [
1102
+                    'currentUser' => ['group1'],
1103
+                    'User' => ['group2'],
1104
+                ],
1105
+            ],
1106
+            // The user `User` cannot share with the current user, but there is an exact match on the e-mail address -> share by e-mail
1107
+            [
1108
+                '[email protected]',
1109
+                [
1110
+                    [
1111
+                        'FN' => 'User',
1112
+                        'EMAIL' => ['[email protected]'],
1113
+                        'CLOUD' => ['test@localhost'],
1114
+                        'isLocalSystemBook' => true,
1115
+                        'UID' => 'User',
1116
+                    ]
1117
+                ],
1118
+                ['exact' => []],
1119
+                false,
1120
+                false,
1121
+                [
1122
+                    'currentUser' => ['group1'],
1123
+                    'User' => ['group2'],
1124
+                ],
1125
+            ]
1126
+        ];
1127
+    }
1128 1128
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -101,7 +101,7 @@  discard block
 block discarded – undo
101 101
 		$this->config->expects($this->any())
102 102
 			->method('getAppValue')
103 103
 			->willReturnCallback(
104
-				function ($appName, $key, $default) use ($shareeEnumeration) {
104
+				function($appName, $key, $default) use ($shareeEnumeration) {
105 105
 					if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
106 106
 						return $shareeEnumeration ? 'yes' : 'no';
107 107
 					}
@@ -119,7 +119,7 @@  discard block
 block discarded – undo
119 119
 
120 120
 		$this->contactsManager->expects($this->any())
121 121
 			->method('search')
122
-			->willReturnCallback(function ($search, $searchAttributes) use ($searchTerm, $contacts) {
122
+			->willReturnCallback(function($search, $searchAttributes) use ($searchTerm, $contacts) {
123 123
 				if ($search === $searchTerm) {
124 124
 					return $contacts;
125 125
 				}
@@ -151,7 +151,7 @@  discard block
 block discarded – undo
151 151
 				true,
152 152
 			],
153 153
 			// data set 3
154
-			[ // no valid email address
154
+			[// no valid email address
155 155
 				'test@remote',
156 156
 				[],
157 157
 				true,
@@ -578,7 +578,7 @@  discard block
 block discarded – undo
578 578
 		$this->config->expects($this->any())
579 579
 			->method('getAppValue')
580 580
 			->willReturnCallback(
581
-				function ($appName, $key, $default) use ($shareeEnumeration) {
581
+				function($appName, $key, $default) use ($shareeEnumeration) {
582 582
 					if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
583 583
 						return $shareeEnumeration ? 'yes' : 'no';
584 584
 					}
@@ -596,7 +596,7 @@  discard block
 block discarded – undo
596 596
 
597 597
 		$this->contactsManager->expects($this->any())
598 598
 			->method('search')
599
-			->willReturnCallback(function ($search, $searchAttributes) use ($searchTerm, $contacts) {
599
+			->willReturnCallback(function($search, $searchAttributes) use ($searchTerm, $contacts) {
600 600
 				if ($search === $searchTerm) {
601 601
 					return $contacts;
602 602
 				}
@@ -758,7 +758,7 @@  discard block
 block discarded – undo
758 758
 					]
759 759
 				],
760 760
 				false,
761
-				['users' => [], 'exact' => ['users' => [['uuid' => 'uid1', 'name' => 'User', 'label' => 'User ([email protected])','value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'], 'shareWithDisplayNameUnique' => '[email protected]']]]],
761
+				['users' => [], 'exact' => ['users' => [['uuid' => 'uid1', 'name' => 'User', 'label' => 'User ([email protected])', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'], 'shareWithDisplayNameUnique' => '[email protected]']]]],
762 762
 				true,
763 763
 				false,
764 764
 			],
@@ -875,7 +875,7 @@  discard block
 block discarded – undo
875 875
 		$this->config->expects($this->any())
876 876
 			->method('getAppValue')
877 877
 			->willReturnCallback(
878
-				function ($appName, $key, $default) {
878
+				function($appName, $key, $default) {
879 879
 					if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
880 880
 						return 'yes';
881 881
 					} elseif ($appName === 'core' && $key === 'shareapi_only_share_with_group_members') {
@@ -896,7 +896,7 @@  discard block
 block discarded – undo
896 896
 
897 897
 		$this->contactsManager->expects($this->any())
898 898
 			->method('search')
899
-			->willReturnCallback(function ($search, $searchAttributes) use ($searchTerm, $contacts) {
899
+			->willReturnCallback(function($search, $searchAttributes) use ($searchTerm, $contacts) {
900 900
 				if ($search === $searchTerm) {
901 901
 					return $contacts;
902 902
 				}
@@ -909,13 +909,13 @@  discard block
 block discarded – undo
909 909
 
910 910
 		$this->groupManager->expects($this->any())
911 911
 			->method('getUserGroupIds')
912
-			->willReturnCallback(function (IUser $user) use ($userToGroupMapping) {
912
+			->willReturnCallback(function(IUser $user) use ($userToGroupMapping) {
913 913
 				return $userToGroupMapping[$user->getUID()];
914 914
 			});
915 915
 
916 916
 		$this->groupManager->expects($this->any())
917 917
 			->method('isInGroup')
918
-			->willReturnCallback(function ($userId, $group) use ($userToGroupMapping) {
918
+			->willReturnCallback(function($userId, $group) use ($userToGroupMapping) {
919 919
 				return in_array($group, $userToGroupMapping[$userId]);
920 920
 			});
921 921
 
@@ -983,7 +983,7 @@  discard block
 block discarded – undo
983 983
 						'UID' => 'User',
984 984
 					]
985 985
 				],
986
-				['emails' => [], 'exact' => ['emails' => [['label' => '[email protected]', 'uuid' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL,'shareWith' => '[email protected]']]]]],
986
+				['emails' => [], 'exact' => ['emails' => [['label' => '[email protected]', 'uuid' => '[email protected]', 'value' => ['shareType' => IShare::TYPE_EMAIL, 'shareWith' => '[email protected]']]]]],
987 987
 				false,
988 988
 				false,
989 989
 				[
@@ -1009,7 +1009,7 @@  discard block
 block discarded – undo
1009 1009
 		$this->config->expects($this->any())
1010 1010
 			->method('getAppValue')
1011 1011
 			->willReturnCallback(
1012
-				function ($appName, $key, $default) {
1012
+				function($appName, $key, $default) {
1013 1013
 					if ($appName === 'core' && $key === 'shareapi_allow_share_dialog_user_enumeration') {
1014 1014
 						return 'yes';
1015 1015
 					} elseif ($appName === 'core' && $key === 'shareapi_only_share_with_group_members') {
@@ -1030,7 +1030,7 @@  discard block
 block discarded – undo
1030 1030
 
1031 1031
 		$this->contactsManager->expects($this->any())
1032 1032
 			->method('search')
1033
-			->willReturnCallback(function ($search, $searchAttributes) use ($searchTerm, $contacts) {
1033
+			->willReturnCallback(function($search, $searchAttributes) use ($searchTerm, $contacts) {
1034 1034
 				if ($search === $searchTerm) {
1035 1035
 					return $contacts;
1036 1036
 				}
@@ -1043,13 +1043,13 @@  discard block
 block discarded – undo
1043 1043
 
1044 1044
 		$this->groupManager->expects($this->any())
1045 1045
 			->method('getUserGroupIds')
1046
-			->willReturnCallback(function (IUser $user) use ($userToGroupMapping) {
1046
+			->willReturnCallback(function(IUser $user) use ($userToGroupMapping) {
1047 1047
 				return $userToGroupMapping[$user->getUID()];
1048 1048
 			});
1049 1049
 
1050 1050
 		$this->groupManager->expects($this->any())
1051 1051
 			->method('isInGroup')
1052
-			->willReturnCallback(function ($userId, $group) use ($userToGroupMapping) {
1052
+			->willReturnCallback(function($userId, $group) use ($userToGroupMapping) {
1053 1053
 				return in_array($group, $userToGroupMapping[$userId]);
1054 1054
 			});
1055 1055
 
@@ -1075,7 +1075,7 @@  discard block
 block discarded – undo
1075 1075
 						'UID' => 'User',
1076 1076
 					]
1077 1077
 				],
1078
-				['users' => [['label' => 'User ([email protected])', 'uuid' => 'User', 'name' => 'User', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'],'shareWithDisplayNameUnique' => '[email protected]',]], 'exact' => ['users' => []]],
1078
+				['users' => [['label' => 'User ([email protected])', 'uuid' => 'User', 'name' => 'User', 'value' => ['shareType' => IShare::TYPE_USER, 'shareWith' => 'test'], 'shareWithDisplayNameUnique' => '[email protected]', ]], 'exact' => ['users' => []]],
1079 1079
 				false,
1080 1080
 				false,
1081 1081
 				[
Please login to merge, or discard this patch.
tests/lib/AppConfigIntegrationTest.php 1 patch
Indentation   +1484 added lines, -1484 removed lines patch added patch discarded remove patch
@@ -27,1488 +27,1488 @@
 block discarded – undo
27 27
  */
28 28
 #[\PHPUnit\Framework\Attributes\Group('DB')]
29 29
 class AppConfigIntegrationTest extends TestCase {
30
-	protected IAppConfig $appConfig;
31
-	protected IDBConnection $connection;
32
-	private IConfig $config;
33
-	private ConfigManager $configManager;
34
-	private PresetManager $presetManager;
35
-	private LoggerInterface $logger;
36
-	private ICrypto $crypto;
37
-	private CacheFactory&MockObject $cacheFactory;
38
-
39
-	private array $originalConfig;
40
-
41
-	/**
42
-	 * @var array<string, array<string, array<string, string, int, bool, bool>>>
43
-	 *                                                                           [appId => [configKey, configValue, valueType, lazy, sensitive]]
44
-	 */
45
-	private static array $baseStruct
46
-		= [
47
-			'testapp' => [
48
-				'enabled' => ['enabled', 'yes'],
49
-				'installed_version' => ['installed_version', '1.2.3'],
50
-				'depends_on' => ['depends_on', 'someapp'],
51
-				'deletethis' => ['deletethis', 'deletethis'],
52
-				'key' => ['key', 'value']
53
-			],
54
-			'searchtest' => [
55
-				'search_key1' => ['search_key1', 'key1', IAppConfig::VALUE_STRING],
56
-				'search_key2' => ['search_key2', 'key2', IAppConfig::VALUE_STRING],
57
-				'search_key3' => ['search_key3', 'key3', IAppConfig::VALUE_STRING],
58
-				'searchnot_key4' => ['searchnot_key4', 'key4', IAppConfig::VALUE_STRING],
59
-				'search_key5_lazy' => ['search_key5_lazy', 'key5', IAppConfig::VALUE_STRING, true],
60
-			],
61
-			'someapp' => [
62
-				'key' => ['key', 'value'],
63
-				'otherkey' => ['otherkey', 'othervalue']
64
-			],
65
-			'123456' => [
66
-				'enabled' => ['enabled', 'yes'],
67
-				'key' => ['key', 'value']
68
-			],
69
-			'anotherapp' => [
70
-				'enabled' => ['enabled', 'no'],
71
-				'installed_version' => ['installed_version', '3.2.1'],
72
-				'key' => ['key', 'value']
73
-			],
74
-			'non-sensitive-app' => [
75
-				'lazy-key' => ['lazy-key', 'value', IAppConfig::VALUE_STRING, true, false],
76
-				'non-lazy-key' => ['non-lazy-key', 'value', IAppConfig::VALUE_STRING, false, false],
77
-			],
78
-			'sensitive-app' => [
79
-				'lazy-key' => ['lazy-key', 'value', IAppConfig::VALUE_STRING, true, true],
80
-				'non-lazy-key' => ['non-lazy-key', 'value', IAppConfig::VALUE_STRING, false, true],
81
-			],
82
-			'only-lazy' => [
83
-				'lazy-key' => ['lazy-key', 'value', IAppConfig::VALUE_STRING, true]
84
-			],
85
-			'typed' => [
86
-				'mixed' => ['mixed', 'mix', IAppConfig::VALUE_MIXED],
87
-				'string' => ['string', 'value', IAppConfig::VALUE_STRING],
88
-				'int' => ['int', '42', IAppConfig::VALUE_INT],
89
-				'float' => ['float', '3.14', IAppConfig::VALUE_FLOAT],
90
-				'bool' => ['bool', '1', IAppConfig::VALUE_BOOL],
91
-				'array' => ['array', '{"test": 1}', IAppConfig::VALUE_ARRAY],
92
-			],
93
-			'prefix-app' => [
94
-				'key1' => ['key1', 'value'],
95
-				'prefix1' => ['prefix1', 'value'],
96
-				'prefix-2' => ['prefix-2', 'value'],
97
-				'key-2' => ['key-2', 'value'],
98
-			]
99
-		];
100
-
101
-	protected function setUp(): void {
102
-		parent::setUp();
103
-
104
-		$this->connection = Server::get(IDBConnection::class);
105
-		$this->config = Server::get(IConfig::class);
106
-		$this->configManager = Server::get(ConfigManager::class);
107
-		$this->presetManager = Server::get(PresetManager::class);
108
-		$this->logger = Server::get(LoggerInterface::class);
109
-		$this->crypto = Server::get(ICrypto::class);
110
-		$this->cacheFactory = $this->createMock(CacheFactory::class);
111
-		$this->cacheFactory->method('isLocalCacheAvailable')->willReturn(false);
112
-
113
-		// storing current config and emptying the data table
114
-		$sql = $this->connection->getQueryBuilder();
115
-		$sql->select('*')
116
-			->from('appconfig');
117
-		$result = $sql->executeQuery();
118
-		$this->originalConfig = $result->fetchAllAssociative();
119
-		$result->closeCursor();
120
-
121
-		$sql = $this->connection->getQueryBuilder();
122
-		$sql->delete('appconfig');
123
-		$sql->executeStatement();
124
-
125
-		$sql = $this->connection->getQueryBuilder();
126
-		$sql->insert('appconfig')
127
-			->values(
128
-				[
129
-					'appid' => $sql->createParameter('appid'),
130
-					'configkey' => $sql->createParameter('configkey'),
131
-					'configvalue' => $sql->createParameter('configvalue'),
132
-					'type' => $sql->createParameter('type'),
133
-					'lazy' => $sql->createParameter('lazy')
134
-				]
135
-			);
136
-
137
-		foreach (self::$baseStruct as $appId => $appData) {
138
-			foreach ($appData as $key => $row) {
139
-				$value = $row[1];
140
-				$type = $row[2] ?? IAppConfig::VALUE_MIXED;
141
-				if (($row[4] ?? false) === true) {
142
-					$type |= IAppConfig::VALUE_SENSITIVE;
143
-					$value = self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX') . $this->crypto->encrypt($value);
144
-					self::$baseStruct[$appId][$key]['encrypted'] = $value;
145
-				}
146
-
147
-				$sql->setParameters(
148
-					[
149
-						'appid' => $appId,
150
-						'configkey' => $row[0],
151
-						'configvalue' => $value,
152
-						'type' => $type,
153
-						'lazy' => (($row[3] ?? false) === true) ? 1 : 0
154
-					]
155
-				)->executeStatement();
156
-			}
157
-		}
158
-	}
159
-
160
-	protected function tearDown(): void {
161
-		$sql = $this->connection->getQueryBuilder();
162
-		$sql->delete('appconfig');
163
-		$sql->executeStatement();
164
-
165
-		$sql = $this->connection->getQueryBuilder();
166
-		$sql->insert('appconfig')
167
-			->values(
168
-				[
169
-					'appid' => $sql->createParameter('appid'),
170
-					'configkey' => $sql->createParameter('configkey'),
171
-					'configvalue' => $sql->createParameter('configvalue'),
172
-					'lazy' => $sql->createParameter('lazy'),
173
-					'type' => $sql->createParameter('type'),
174
-				]
175
-			);
176
-
177
-		foreach ($this->originalConfig as $key => $configs) {
178
-			$sql->setParameter('appid', $configs['appid'])
179
-				->setParameter('configkey', $configs['configkey'])
180
-				->setParameter('configvalue', $configs['configvalue'])
181
-				->setParameter('lazy', ($configs['lazy'] === '1') ? '1' : '0')
182
-				->setParameter('type', $configs['type']);
183
-			$sql->executeStatement();
184
-		}
185
-
186
-		//		$this->restoreService(AppConfig::class);
187
-		parent::tearDown();
188
-	}
189
-
190
-	/**
191
-	 * @param bool $preLoading TRUE will preload the 'fast' cache, which is the normal behavior of usual
192
-	 *                         IAppConfig
193
-	 *
194
-	 * @return IAppConfig
195
-	 */
196
-	private function generateAppConfig(bool $preLoading = true): IAppConfig {
197
-		/** @var AppConfig $config */
198
-		$config = new AppConfig(
199
-			$this->connection,
200
-			$this->config,
201
-			$this->configManager,
202
-			$this->presetManager,
203
-			$this->logger,
204
-			$this->crypto,
205
-			$this->cacheFactory,
206
-		);
207
-		$msg = ' generateAppConfig() failed to confirm cache status';
208
-
209
-		// confirm cache status
210
-		$status = $config->statusCache();
211
-		$this->assertSame(false, $status['fastLoaded'], $msg);
212
-		$this->assertSame(false, $status['lazyLoaded'], $msg);
213
-		$this->assertSame([], $status['fastCache'], $msg);
214
-		$this->assertSame([], $status['lazyCache'], $msg);
215
-		if ($preLoading) {
216
-			// simple way to initiate the load of non-lazy config values in cache
217
-			$config->getValueString('core', 'preload', '');
218
-
219
-			// confirm cache status
220
-			$status = $config->statusCache();
221
-			$this->assertSame(true, $status['fastLoaded'], $msg);
222
-			$this->assertSame(false, $status['lazyLoaded'], $msg);
223
-
224
-			$apps = array_values(array_diff(array_keys(self::$baseStruct), ['only-lazy']));
225
-			$this->assertEqualsCanonicalizing($apps, array_keys($status['fastCache']), $msg);
226
-			$this->assertSame([], array_keys($status['lazyCache']), $msg);
227
-		}
228
-
229
-		return $config;
230
-	}
231
-
232
-	public function testGetApps(): void {
233
-		$config = $this->generateAppConfig(false);
234
-
235
-		$this->assertEqualsCanonicalizing(array_keys(self::$baseStruct), $config->getApps());
236
-	}
237
-
238
-	public function testGetAppInstalledVersions(): void {
239
-		$config = $this->generateAppConfig(false);
240
-
241
-		$this->assertEquals(
242
-			['testapp' => '1.2.3', 'anotherapp' => '3.2.1'],
243
-			$config->getAppInstalledVersions(false)
244
-		);
245
-		$this->assertEquals(
246
-			['testapp' => '1.2.3'],
247
-			$config->getAppInstalledVersions(true)
248
-		);
249
-	}
250
-
251
-	/**
252
-	 * returns list of app and their keys
253
-	 *
254
-	 * @return array<string, string[]> ['appId' => ['key1', 'key2', ]]
255
-	 * @see testGetKeys
256
-	 */
257
-	public static function providerGetAppKeys(): array {
258
-		$appKeys = [];
259
-		foreach (self::$baseStruct as $appId => $appData) {
260
-			$keys = [];
261
-			foreach ($appData as $row) {
262
-				$keys[] = $row[0];
263
-			}
264
-			$appKeys[] = [(string)$appId, $keys];
265
-		}
266
-
267
-		return $appKeys;
268
-	}
269
-
270
-	/**
271
-	 * returns list of config keys
272
-	 *
273
-	 * @return array<string, string, string, int, bool, bool> [appId, key, value, type, lazy, sensitive]
274
-	 * @see testIsSensitive
275
-	 * @see testIsLazy
276
-	 * @see testGetKeys
277
-	 */
278
-	public static function providerGetKeys(): array {
279
-		$appKeys = [];
280
-		foreach (self::$baseStruct as $appId => $appData) {
281
-			foreach ($appData as $row) {
282
-				$appKeys[] = [
283
-					(string)$appId, $row[0], $row[1], $row[2] ?? IAppConfig::VALUE_MIXED, $row[3] ?? false,
284
-					$row[4] ?? false
285
-				];
286
-			}
287
-		}
288
-
289
-		return $appKeys;
290
-	}
291
-
292
-	/**
293
-	 *
294
-	 * @param string $appId
295
-	 * @param array $expectedKeys
296
-	 */
297
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetAppKeys')]
298
-	public function testGetKeys(string $appId, array $expectedKeys): void {
299
-		$config = $this->generateAppConfig();
300
-		$this->assertEqualsCanonicalizing($expectedKeys, $config->getKeys($appId));
301
-	}
302
-
303
-	public function testGetKeysOnUnknownAppShouldReturnsEmptyArray(): void {
304
-		$config = $this->generateAppConfig();
305
-		$this->assertEqualsCanonicalizing([], $config->getKeys('unknown-app'));
306
-	}
307
-
308
-	/**
309
-	 *
310
-	 * @param string $appId
311
-	 * @param string $configKey
312
-	 * @param string $value
313
-	 * @param bool $lazy
314
-	 */
315
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetKeys')]
316
-	public function testHasKey(string $appId, string $configKey, string $value, int $type, bool $lazy): void {
317
-		$config = $this->generateAppConfig();
318
-		$this->assertEquals(true, $config->hasKey($appId, $configKey, $lazy));
319
-	}
320
-
321
-	public function testHasKeyOnNonExistentKeyReturnsFalse(): void {
322
-		$config = $this->generateAppConfig();
323
-		$this->assertEquals(false, $config->hasKey(array_keys(self::$baseStruct)[0], 'inexistant-key'));
324
-	}
325
-
326
-	public function testHasKeyOnUnknownAppReturnsFalse(): void {
327
-		$config = $this->generateAppConfig();
328
-		$this->assertEquals(false, $config->hasKey('inexistant-app', 'inexistant-key'));
329
-	}
330
-
331
-	public function testHasKeyOnMistypedAsLazyReturnsFalse(): void {
332
-		$config = $this->generateAppConfig();
333
-		$this->assertSame(false, $config->hasKey('non-sensitive-app', 'non-lazy-key', true));
334
-	}
335
-
336
-	public function testHasKeyOnMistypeAsNonLazyReturnsFalse(): void {
337
-		$config = $this->generateAppConfig();
338
-		$this->assertSame(false, $config->hasKey('non-sensitive-app', 'lazy-key', false));
339
-	}
340
-
341
-	public function testHasKeyOnMistypeAsNonLazyReturnsTrueWithLazyArgumentIsNull(): void {
342
-		$config = $this->generateAppConfig();
343
-		$this->assertSame(true, $config->hasKey('non-sensitive-app', 'lazy-key', null));
344
-	}
345
-
346
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetKeys')]
347
-	public function testIsSensitive(
348
-		string $appId, string $configKey, string $configValue, int $type, bool $lazy, bool $sensitive,
349
-	): void {
350
-		$config = $this->generateAppConfig();
351
-		$this->assertEquals($sensitive, $config->isSensitive($appId, $configKey, $lazy));
352
-	}
353
-
354
-	public function testIsSensitiveOnNonExistentKeyThrowsException(): void {
355
-		$config = $this->generateAppConfig();
356
-		$this->expectException(AppConfigUnknownKeyException::class);
357
-		$config->isSensitive(array_keys(self::$baseStruct)[0], 'inexistant-key');
358
-	}
359
-
360
-	public function testIsSensitiveOnUnknownAppThrowsException(): void {
361
-		$config = $this->generateAppConfig();
362
-		$this->expectException(AppConfigUnknownKeyException::class);
363
-		$config->isSensitive('unknown-app', 'inexistant-key');
364
-	}
365
-
366
-	public function testIsSensitiveOnSensitiveMistypedAsLazy(): void {
367
-		$config = $this->generateAppConfig();
368
-		$this->assertSame(true, $config->isSensitive('sensitive-app', 'non-lazy-key', true));
369
-	}
370
-
371
-	public function testIsSensitiveOnNonSensitiveMistypedAsLazy(): void {
372
-		$config = $this->generateAppConfig();
373
-		$this->assertSame(false, $config->isSensitive('non-sensitive-app', 'non-lazy-key', true));
374
-	}
375
-
376
-	public function testIsSensitiveOnSensitiveMistypedAsNonLazyThrowsException(): void {
377
-		$config = $this->generateAppConfig();
378
-		$this->expectException(AppConfigUnknownKeyException::class);
379
-		$config->isSensitive('sensitive-app', 'lazy-key', false);
380
-	}
381
-
382
-	public function testIsSensitiveOnNonSensitiveMistypedAsNonLazyThrowsException(): void {
383
-		$config = $this->generateAppConfig();
384
-		$this->expectException(AppConfigUnknownKeyException::class);
385
-		$config->isSensitive('non-sensitive-app', 'lazy-key', false);
386
-	}
387
-
388
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetKeys')]
389
-	public function testIsLazy(string $appId, string $configKey, string $configValue, int $type, bool $lazy,
390
-	): void {
391
-		$config = $this->generateAppConfig();
392
-		$this->assertEquals($lazy, $config->isLazy($appId, $configKey));
393
-	}
394
-
395
-	public function testIsLazyOnNonExistentKeyThrowsException(): void {
396
-		$config = $this->generateAppConfig();
397
-		$this->expectException(AppConfigUnknownKeyException::class);
398
-		$config->isLazy(array_keys(self::$baseStruct)[0], 'inexistant-key');
399
-	}
400
-
401
-	public function testIsLazyOnUnknownAppThrowsException(): void {
402
-		$config = $this->generateAppConfig();
403
-		$this->expectException(AppConfigUnknownKeyException::class);
404
-		$config->isLazy('unknown-app', 'inexistant-key');
405
-	}
406
-
407
-	public function testGetAllValues(): void {
408
-		$config = $this->generateAppConfig();
409
-		$this->assertEquals(
410
-			[
411
-				'array' => ['test' => 1],
412
-				'bool' => true,
413
-				'float' => 3.14,
414
-				'int' => 42,
415
-				'mixed' => 'mix',
416
-				'string' => 'value',
417
-			],
418
-			$config->getAllValues('typed')
419
-		);
420
-	}
421
-
422
-	public function testGetAllValuesWithEmptyApp(): void {
423
-		$config = $this->generateAppConfig();
424
-		$this->expectException(InvalidArgumentException::class);
425
-		$config->getAllValues('');
426
-	}
427
-
428
-	/**
429
-	 *
430
-	 * @param string $appId
431
-	 * @param array $keys
432
-	 */
433
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetAppKeys')]
434
-	public function testGetAllValuesWithEmptyKey(string $appId, array $keys): void {
435
-		$config = $this->generateAppConfig();
436
-		$this->assertEqualsCanonicalizing($keys, array_keys($config->getAllValues($appId, '')));
437
-	}
438
-
439
-	public function testGetAllValuesWithPrefix(): void {
440
-		$config = $this->generateAppConfig();
441
-		$this->assertEqualsCanonicalizing(['prefix1', 'prefix-2'], array_keys($config->getAllValues('prefix-app', 'prefix')));
442
-	}
443
-
444
-	public function testSearchValues(): void {
445
-		$config = $this->generateAppConfig();
446
-		$this->assertEqualsCanonicalizing(['testapp' => 'yes', '123456' => 'yes', 'anotherapp' => 'no'], $config->searchValues('enabled'));
447
-	}
448
-
449
-	public function testGetValueString(): void {
450
-		$config = $this->generateAppConfig();
451
-		$this->assertSame('value', $config->getValueString('typed', 'string', ''));
452
-	}
453
-
454
-	public function testGetValueStringOnUnknownAppReturnsDefault(): void {
455
-		$config = $this->generateAppConfig();
456
-		$this->assertSame('default-1', $config->getValueString('typed-1', 'string', 'default-1'));
457
-	}
458
-
459
-	public function testGetValueStringOnNonExistentKeyReturnsDefault(): void {
460
-		$config = $this->generateAppConfig();
461
-		$this->assertSame('default-2', $config->getValueString('typed', 'string-2', 'default-2'));
462
-	}
463
-
464
-	public function testGetValueStringOnWrongType(): void {
465
-		$config = $this->generateAppConfig();
466
-		$this->expectException(AppConfigTypeConflictException::class);
467
-		$config->getValueString('typed', 'int');
468
-	}
469
-
470
-	public function testGetNonLazyValueStringAsLazy(): void {
471
-		$config = $this->generateAppConfig();
472
-		$this->assertSame('value', $config->getValueString('non-sensitive-app', 'non-lazy-key', 'default', lazy: true));
473
-	}
474
-
475
-	public function testGetValueInt(): void {
476
-		$config = $this->generateAppConfig();
477
-		$this->assertSame(42, $config->getValueInt('typed', 'int', 0));
478
-	}
479
-
480
-	public function testGetValueIntOnUnknownAppReturnsDefault(): void {
481
-		$config = $this->generateAppConfig();
482
-		$this->assertSame(1, $config->getValueInt('typed-1', 'int', 1));
483
-	}
484
-
485
-	public function testGetValueIntOnNonExistentKeyReturnsDefault(): void {
486
-		$config = $this->generateAppConfig();
487
-		$this->assertSame(2, $config->getValueInt('typed', 'int-2', 2));
488
-	}
489
-
490
-	public function testGetValueIntOnWrongType(): void {
491
-		$config = $this->generateAppConfig();
492
-		$this->expectException(AppConfigTypeConflictException::class);
493
-		$config->getValueInt('typed', 'float');
494
-	}
495
-
496
-	public function testGetValueFloat(): void {
497
-		$config = $this->generateAppConfig();
498
-		$this->assertSame(3.14, $config->getValueFloat('typed', 'float', 0));
499
-	}
500
-
501
-	public function testGetValueFloatOnNonUnknownAppReturnsDefault(): void {
502
-		$config = $this->generateAppConfig();
503
-		$this->assertSame(1.11, $config->getValueFloat('typed-1', 'float', 1.11));
504
-	}
505
-
506
-	public function testGetValueFloatOnNonExistentKeyReturnsDefault(): void {
507
-		$config = $this->generateAppConfig();
508
-		$this->assertSame(2.22, $config->getValueFloat('typed', 'float-2', 2.22));
509
-	}
510
-
511
-	public function testGetValueFloatOnWrongType(): void {
512
-		$config = $this->generateAppConfig();
513
-		$this->expectException(AppConfigTypeConflictException::class);
514
-		$config->getValueFloat('typed', 'bool');
515
-	}
516
-
517
-	public function testGetValueBool(): void {
518
-		$config = $this->generateAppConfig();
519
-		$this->assertSame(true, $config->getValueBool('typed', 'bool'));
520
-	}
521
-
522
-	public function testGetValueBoolOnUnknownAppReturnsDefault(): void {
523
-		$config = $this->generateAppConfig();
524
-		$this->assertSame(false, $config->getValueBool('typed-1', 'bool', false));
525
-	}
526
-
527
-	public function testGetValueBoolOnNonExistentKeyReturnsDefault(): void {
528
-		$config = $this->generateAppConfig();
529
-		$this->assertSame(false, $config->getValueBool('typed', 'bool-2'));
530
-	}
531
-
532
-	public function testGetValueBoolOnWrongType(): void {
533
-		$config = $this->generateAppConfig();
534
-		$this->expectException(AppConfigTypeConflictException::class);
535
-		$config->getValueBool('typed', 'array');
536
-	}
537
-
538
-	public function testGetValueArray(): void {
539
-		$config = $this->generateAppConfig();
540
-		$this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('typed', 'array', []));
541
-	}
542
-
543
-	public function testGetValueArrayOnUnknownAppReturnsDefault(): void {
544
-		$config = $this->generateAppConfig();
545
-		$this->assertSame([1], $config->getValueArray('typed-1', 'array', [1]));
546
-	}
547
-
548
-	public function testGetValueArrayOnNonExistentKeyReturnsDefault(): void {
549
-		$config = $this->generateAppConfig();
550
-		$this->assertSame([1, 2], $config->getValueArray('typed', 'array-2', [1, 2]));
551
-	}
552
-
553
-	public function testGetValueArrayOnWrongType(): void {
554
-		$config = $this->generateAppConfig();
555
-		$this->expectException(AppConfigTypeConflictException::class);
556
-		$config->getValueArray('typed', 'string');
557
-	}
558
-
559
-
560
-	/**
561
-	 * @return array
562
-	 * @see testGetValueType
563
-	 *
564
-	 * @see testGetValueMixed
565
-	 */
566
-	public static function providerGetValueMixed(): array {
567
-		return [
568
-			// key, value, type
569
-			['mixed', 'mix', IAppConfig::VALUE_MIXED],
570
-			['string', 'value', IAppConfig::VALUE_STRING],
571
-			['int', '42', IAppConfig::VALUE_INT],
572
-			['float', '3.14', IAppConfig::VALUE_FLOAT],
573
-			['bool', '1', IAppConfig::VALUE_BOOL],
574
-			['array', '{"test": 1}', IAppConfig::VALUE_ARRAY],
575
-		];
576
-	}
577
-
578
-	/**
579
-	 *
580
-	 * @param string $key
581
-	 * @param string $value
582
-	 */
583
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueMixed')]
584
-	public function testGetValueMixed(string $key, string $value): void {
585
-		$config = $this->generateAppConfig();
586
-		$this->assertSame($value, $config->getValueMixed('typed', $key));
587
-	}
588
-
589
-	/**
590
-	 *
591
-	 * @param string $key
592
-	 * @param string $value
593
-	 * @param int $type
594
-	 */
595
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueMixed')]
596
-	public function testGetValueType(string $key, string $value, int $type): void {
597
-		$config = $this->generateAppConfig();
598
-		$this->assertSame($type, $config->getValueType('typed', $key));
599
-	}
600
-
601
-	public function testGetValueTypeOnUnknownApp(): void {
602
-		$config = $this->generateAppConfig();
603
-		$this->expectException(AppConfigUnknownKeyException::class);
604
-		$config->getValueType('typed-1', 'string');
605
-	}
606
-
607
-	public function testGetValueTypeOnNonExistentKey(): void {
608
-		$config = $this->generateAppConfig();
609
-		$this->expectException(AppConfigUnknownKeyException::class);
610
-		$config->getValueType('typed', 'string-2');
611
-	}
612
-
613
-	public function testSetValueString(): void {
614
-		$config = $this->generateAppConfig();
615
-		$config->setValueString('feed', 'string', 'value-1');
616
-		$this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
617
-	}
618
-
619
-	public function testSetValueStringCache(): void {
620
-		$config = $this->generateAppConfig();
621
-		$config->setValueString('feed', 'string', 'value-1');
622
-		$status = $config->statusCache();
623
-		$this->assertSame('value-1', $status['fastCache']['feed']['string']);
624
-	}
625
-
626
-	public function testSetValueStringDatabase(): void {
627
-		$config = $this->generateAppConfig();
628
-		$config->setValueString('feed', 'string', 'value-1');
629
-		$config->clearCache();
630
-		$this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
631
-	}
632
-
633
-	public function testSetValueStringIsUpdated(): void {
634
-		$config = $this->generateAppConfig();
635
-		$config->setValueString('feed', 'string', 'value-1');
636
-		$this->assertSame(true, $config->setValueString('feed', 'string', 'value-2'));
637
-	}
638
-
639
-	public function testSetValueStringIsNotUpdated(): void {
640
-		$config = $this->generateAppConfig();
641
-		$config->setValueString('feed', 'string', 'value-1');
642
-		$this->assertSame(false, $config->setValueString('feed', 'string', 'value-1'));
643
-	}
644
-
645
-	public function testSetValueStringIsUpdatedCache(): void {
646
-		$config = $this->generateAppConfig();
647
-		$config->setValueString('feed', 'string', 'value-1');
648
-		$config->setValueString('feed', 'string', 'value-2');
649
-		$status = $config->statusCache();
650
-		$this->assertSame('value-2', $status['fastCache']['feed']['string']);
651
-	}
652
-
653
-	public function testSetValueStringIsUpdatedDatabase(): void {
654
-		$config = $this->generateAppConfig();
655
-		$config->setValueString('feed', 'string', 'value-1');
656
-		$config->setValueString('feed', 'string', 'value-2');
657
-		$config->clearCache();
658
-		$this->assertSame('value-2', $config->getValueString('feed', 'string', ''));
659
-	}
660
-
661
-	public function testSetValueInt(): void {
662
-		$config = $this->generateAppConfig();
663
-		$config->setValueInt('feed', 'int', 42);
664
-		$this->assertSame(42, $config->getValueInt('feed', 'int', 0));
665
-	}
666
-
667
-	public function testSetValueIntCache(): void {
668
-		$config = $this->generateAppConfig();
669
-		$config->setValueInt('feed', 'int', 42);
670
-		$status = $config->statusCache();
671
-		$this->assertSame('42', $status['fastCache']['feed']['int']);
672
-	}
673
-
674
-	public function testSetValueIntDatabase(): void {
675
-		$config = $this->generateAppConfig();
676
-		$config->setValueInt('feed', 'int', 42);
677
-		$config->clearCache();
678
-		$this->assertSame(42, $config->getValueInt('feed', 'int', 0));
679
-	}
680
-
681
-	public function testSetValueIntIsUpdated(): void {
682
-		$config = $this->generateAppConfig();
683
-		$config->setValueInt('feed', 'int', 42);
684
-		$this->assertSame(true, $config->setValueInt('feed', 'int', 17));
685
-	}
686
-
687
-	public function testSetValueIntIsNotUpdated(): void {
688
-		$config = $this->generateAppConfig();
689
-		$config->setValueInt('feed', 'int', 42);
690
-		$this->assertSame(false, $config->setValueInt('feed', 'int', 42));
691
-	}
692
-
693
-	public function testSetValueIntIsUpdatedCache(): void {
694
-		$config = $this->generateAppConfig();
695
-		$config->setValueInt('feed', 'int', 42);
696
-		$config->setValueInt('feed', 'int', 17);
697
-		$status = $config->statusCache();
698
-		$this->assertSame('17', $status['fastCache']['feed']['int']);
699
-	}
700
-
701
-	public function testSetValueIntIsUpdatedDatabase(): void {
702
-		$config = $this->generateAppConfig();
703
-		$config->setValueInt('feed', 'int', 42);
704
-		$config->setValueInt('feed', 'int', 17);
705
-		$config->clearCache();
706
-		$this->assertSame(17, $config->getValueInt('feed', 'int', 0));
707
-	}
708
-
709
-	public function testSetValueFloat(): void {
710
-		$config = $this->generateAppConfig();
711
-		$config->setValueFloat('feed', 'float', 3.14);
712
-		$this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
713
-	}
714
-
715
-	public function testSetValueFloatCache(): void {
716
-		$config = $this->generateAppConfig();
717
-		$config->setValueFloat('feed', 'float', 3.14);
718
-		$status = $config->statusCache();
719
-		$this->assertSame('3.14', $status['fastCache']['feed']['float']);
720
-	}
721
-
722
-	public function testSetValueFloatDatabase(): void {
723
-		$config = $this->generateAppConfig();
724
-		$config->setValueFloat('feed', 'float', 3.14);
725
-		$config->clearCache();
726
-		$this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
727
-	}
728
-
729
-	public function testSetValueFloatIsUpdated(): void {
730
-		$config = $this->generateAppConfig();
731
-		$config->setValueFloat('feed', 'float', 3.14);
732
-		$this->assertSame(true, $config->setValueFloat('feed', 'float', 1.23));
733
-	}
734
-
735
-	public function testSetValueFloatIsNotUpdated(): void {
736
-		$config = $this->generateAppConfig();
737
-		$config->setValueFloat('feed', 'float', 3.14);
738
-		$this->assertSame(false, $config->setValueFloat('feed', 'float', 3.14));
739
-	}
740
-
741
-	public function testSetValueFloatIsUpdatedCache(): void {
742
-		$config = $this->generateAppConfig();
743
-		$config->setValueFloat('feed', 'float', 3.14);
744
-		$config->setValueFloat('feed', 'float', 1.23);
745
-		$status = $config->statusCache();
746
-		$this->assertSame('1.23', $status['fastCache']['feed']['float']);
747
-	}
748
-
749
-	public function testSetValueFloatIsUpdatedDatabase(): void {
750
-		$config = $this->generateAppConfig();
751
-		$config->setValueFloat('feed', 'float', 3.14);
752
-		$config->setValueFloat('feed', 'float', 1.23);
753
-		$config->clearCache();
754
-		$this->assertSame(1.23, $config->getValueFloat('feed', 'float', 0));
755
-	}
756
-
757
-	public function testSetValueBool(): void {
758
-		$config = $this->generateAppConfig();
759
-		$config->setValueBool('feed', 'bool', true);
760
-		$this->assertSame(true, $config->getValueBool('feed', 'bool', false));
761
-	}
762
-
763
-	public function testSetValueBoolCache(): void {
764
-		$config = $this->generateAppConfig();
765
-		$config->setValueBool('feed', 'bool', true);
766
-		$status = $config->statusCache();
767
-		$this->assertSame('1', $status['fastCache']['feed']['bool']);
768
-	}
769
-
770
-	public function testSetValueBoolDatabase(): void {
771
-		$config = $this->generateAppConfig();
772
-		$config->setValueBool('feed', 'bool', true);
773
-		$config->clearCache();
774
-		$this->assertSame(true, $config->getValueBool('feed', 'bool', false));
775
-	}
776
-
777
-	public function testSetValueBoolIsUpdated(): void {
778
-		$config = $this->generateAppConfig();
779
-		$config->setValueBool('feed', 'bool', true);
780
-		$this->assertSame(true, $config->setValueBool('feed', 'bool', false));
781
-	}
782
-
783
-	public function testSetValueBoolIsNotUpdated(): void {
784
-		$config = $this->generateAppConfig();
785
-		$config->setValueBool('feed', 'bool', true);
786
-		$this->assertSame(false, $config->setValueBool('feed', 'bool', true));
787
-	}
788
-
789
-	public function testSetValueBoolIsUpdatedCache(): void {
790
-		$config = $this->generateAppConfig();
791
-		$config->setValueBool('feed', 'bool', true);
792
-		$config->setValueBool('feed', 'bool', false);
793
-		$status = $config->statusCache();
794
-		$this->assertSame('0', $status['fastCache']['feed']['bool']);
795
-	}
796
-
797
-	public function testSetValueBoolIsUpdatedDatabase(): void {
798
-		$config = $this->generateAppConfig();
799
-		$config->setValueBool('feed', 'bool', true);
800
-		$config->setValueBool('feed', 'bool', false);
801
-		$config->clearCache();
802
-		$this->assertSame(false, $config->getValueBool('feed', 'bool', true));
803
-	}
804
-
805
-
806
-	public function testSetValueArray(): void {
807
-		$config = $this->generateAppConfig();
808
-		$config->setValueArray('feed', 'array', ['test' => 1]);
809
-		$this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
810
-	}
811
-
812
-	public function testSetValueArrayCache(): void {
813
-		$config = $this->generateAppConfig();
814
-		$config->setValueArray('feed', 'array', ['test' => 1]);
815
-		$status = $config->statusCache();
816
-		$this->assertSame('{"test":1}', $status['fastCache']['feed']['array']);
817
-	}
818
-
819
-	public function testSetValueArrayDatabase(): void {
820
-		$config = $this->generateAppConfig();
821
-		$config->setValueArray('feed', 'array', ['test' => 1]);
822
-		$config->clearCache();
823
-		$this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
824
-	}
825
-
826
-	public function testSetValueArrayIsUpdated(): void {
827
-		$config = $this->generateAppConfig();
828
-		$config->setValueArray('feed', 'array', ['test' => 1]);
829
-		$this->assertSame(true, $config->setValueArray('feed', 'array', ['test' => 2]));
830
-	}
831
-
832
-	public function testSetValueArrayIsNotUpdated(): void {
833
-		$config = $this->generateAppConfig();
834
-		$config->setValueArray('feed', 'array', ['test' => 1]);
835
-		$this->assertSame(false, $config->setValueArray('feed', 'array', ['test' => 1]));
836
-	}
837
-
838
-	public function testSetValueArrayIsUpdatedCache(): void {
839
-		$config = $this->generateAppConfig();
840
-		$config->setValueArray('feed', 'array', ['test' => 1]);
841
-		$config->setValueArray('feed', 'array', ['test' => 2]);
842
-		$status = $config->statusCache();
843
-		$this->assertSame('{"test":2}', $status['fastCache']['feed']['array']);
844
-	}
845
-
846
-	public function testSetValueArrayIsUpdatedDatabase(): void {
847
-		$config = $this->generateAppConfig();
848
-		$config->setValueArray('feed', 'array', ['test' => 1]);
849
-		$config->setValueArray('feed', 'array', ['test' => 2]);
850
-		$config->clearCache();
851
-		$this->assertSame(['test' => 2], $config->getValueArray('feed', 'array', []));
852
-	}
853
-
854
-	public function testSetLazyValueString(): void {
855
-		$config = $this->generateAppConfig();
856
-		$config->setValueString('feed', 'string', 'value-1', true);
857
-		$this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
858
-	}
859
-
860
-	public function testSetLazyValueStringCache(): void {
861
-		$config = $this->generateAppConfig();
862
-		$config->setValueString('feed', 'string', 'value-1', true);
863
-		$status = $config->statusCache();
864
-		$this->assertSame('value-1', $status['lazyCache']['feed']['string']);
865
-	}
866
-
867
-	public function testSetLazyValueStringDatabase(): void {
868
-		$config = $this->generateAppConfig();
869
-		$config->setValueString('feed', 'string', 'value-1', true);
870
-		$config->clearCache();
871
-		$this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
872
-	}
873
-
874
-	public function testSetLazyValueStringAsNonLazy(): void {
875
-		$config = $this->generateAppConfig();
876
-		$config->setValueString('feed', 'string', 'value-1', true);
877
-		$config->setValueString('feed', 'string', 'value-1', false);
878
-		$this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
879
-	}
880
-
881
-	public function testSetNonLazyValueStringAsLazy(): void {
882
-		$config = $this->generateAppConfig();
883
-		$config->setValueString('feed', 'string', 'value-1', false);
884
-		$config->setValueString('feed', 'string', 'value-1', true);
885
-		$this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
886
-	}
887
-
888
-	public function testSetSensitiveValueString(): void {
889
-		$config = $this->generateAppConfig();
890
-		$config->setValueString('feed', 'string', 'value-1', sensitive: true);
891
-		$this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
892
-	}
893
-
894
-	public function testSetSensitiveValueStringCache(): void {
895
-		$config = $this->generateAppConfig();
896
-		$config->setValueString('feed', 'string', 'value-1', sensitive: true);
897
-		$status = $config->statusCache();
898
-		$this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['string']);
899
-	}
900
-
901
-	public function testSetSensitiveValueStringDatabase(): void {
902
-		$config = $this->generateAppConfig();
903
-		$config->setValueString('feed', 'string', 'value-1', sensitive: true);
904
-		$config->clearCache();
905
-		$this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
906
-	}
907
-
908
-	public function testSetNonSensitiveValueStringAsSensitive(): void {
909
-		$config = $this->generateAppConfig();
910
-		$config->setValueString('feed', 'string', 'value-1', sensitive: false);
911
-		$config->setValueString('feed', 'string', 'value-1', sensitive: true);
912
-		$this->assertSame(true, $config->isSensitive('feed', 'string'));
913
-
914
-		$this->assertConfigValueNotEquals('feed', 'string', 'value-1');
915
-		$this->assertConfigValueNotEquals('feed', 'string', 'value-2');
916
-	}
917
-
918
-	public function testSetSensitiveValueStringAsNonSensitiveStaysSensitive(): void {
919
-		$config = $this->generateAppConfig();
920
-		$config->setValueString('feed', 'string', 'value-1', sensitive: true);
921
-		$config->setValueString('feed', 'string', 'value-2', sensitive: false);
922
-		$this->assertSame(true, $config->isSensitive('feed', 'string'));
923
-
924
-		$this->assertConfigValueNotEquals('feed', 'string', 'value-1');
925
-		$this->assertConfigValueNotEquals('feed', 'string', 'value-2');
926
-	}
927
-
928
-	public function testSetSensitiveValueStringAsNonSensitiveAreStillUpdated(): void {
929
-		$config = $this->generateAppConfig();
930
-		$config->setValueString('feed', 'string', 'value-1', sensitive: true);
931
-		$config->setValueString('feed', 'string', 'value-2', sensitive: false);
932
-		$this->assertSame('value-2', $config->getValueString('feed', 'string', ''));
933
-
934
-		$this->assertConfigValueNotEquals('feed', 'string', 'value-1');
935
-		$this->assertConfigValueNotEquals('feed', 'string', 'value-2');
936
-	}
937
-
938
-	public function testSetLazyValueInt(): void {
939
-		$config = $this->generateAppConfig();
940
-		$config->setValueInt('feed', 'int', 42, true);
941
-		$this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
942
-	}
943
-
944
-	public function testSetLazyValueIntCache(): void {
945
-		$config = $this->generateAppConfig();
946
-		$config->setValueInt('feed', 'int', 42, true);
947
-		$status = $config->statusCache();
948
-		$this->assertSame('42', $status['lazyCache']['feed']['int']);
949
-	}
950
-
951
-	public function testSetLazyValueIntDatabase(): void {
952
-		$config = $this->generateAppConfig();
953
-		$config->setValueInt('feed', 'int', 42, true);
954
-		$config->clearCache();
955
-		$this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
956
-	}
957
-
958
-	public function testSetLazyValueIntAsNonLazy(): void {
959
-		$config = $this->generateAppConfig();
960
-		$config->setValueInt('feed', 'int', 42, true);
961
-		$config->setValueInt('feed', 'int', 42, false);
962
-		$this->assertSame(42, $config->getValueInt('feed', 'int', 0));
963
-	}
964
-
965
-	public function testSetNonLazyValueIntAsLazy(): void {
966
-		$config = $this->generateAppConfig();
967
-		$config->setValueInt('feed', 'int', 42, false);
968
-		$config->setValueInt('feed', 'int', 42, true);
969
-		$this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
970
-	}
971
-
972
-	public function testSetSensitiveValueInt(): void {
973
-		$config = $this->generateAppConfig();
974
-		$config->setValueInt('feed', 'int', 42, sensitive: true);
975
-		$this->assertSame(42, $config->getValueInt('feed', 'int', 0));
976
-	}
977
-
978
-	public function testSetSensitiveValueIntCache(): void {
979
-		$config = $this->generateAppConfig();
980
-		$config->setValueInt('feed', 'int', 42, sensitive: true);
981
-		$status = $config->statusCache();
982
-		$this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['int']);
983
-	}
984
-
985
-	public function testSetSensitiveValueIntDatabase(): void {
986
-		$config = $this->generateAppConfig();
987
-		$config->setValueInt('feed', 'int', 42, sensitive: true);
988
-		$config->clearCache();
989
-		$this->assertSame(42, $config->getValueInt('feed', 'int', 0));
990
-	}
991
-
992
-	public function testSetNonSensitiveValueIntAsSensitive(): void {
993
-		$config = $this->generateAppConfig();
994
-		$config->setValueInt('feed', 'int', 42);
995
-		$config->setValueInt('feed', 'int', 42, sensitive: true);
996
-		$this->assertSame(true, $config->isSensitive('feed', 'int'));
997
-	}
998
-
999
-	public function testSetSensitiveValueIntAsNonSensitiveStaysSensitive(): void {
1000
-		$config = $this->generateAppConfig();
1001
-		$config->setValueInt('feed', 'int', 42, sensitive: true);
1002
-		$config->setValueInt('feed', 'int', 17);
1003
-		$this->assertSame(true, $config->isSensitive('feed', 'int'));
1004
-	}
1005
-
1006
-	public function testSetSensitiveValueIntAsNonSensitiveAreStillUpdated(): void {
1007
-		$config = $this->generateAppConfig();
1008
-		$config->setValueInt('feed', 'int', 42, sensitive: true);
1009
-		$config->setValueInt('feed', 'int', 17);
1010
-		$this->assertSame(17, $config->getValueInt('feed', 'int', 0));
1011
-	}
1012
-
1013
-	public function testSetLazyValueFloat(): void {
1014
-		$config = $this->generateAppConfig();
1015
-		$config->setValueFloat('feed', 'float', 3.14, true);
1016
-		$this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
1017
-	}
1018
-
1019
-	public function testSetLazyValueFloatCache(): void {
1020
-		$config = $this->generateAppConfig();
1021
-		$config->setValueFloat('feed', 'float', 3.14, true);
1022
-		$status = $config->statusCache();
1023
-		$this->assertSame('3.14', $status['lazyCache']['feed']['float']);
1024
-	}
1025
-
1026
-	public function testSetLazyValueFloatDatabase(): void {
1027
-		$config = $this->generateAppConfig();
1028
-		$config->setValueFloat('feed', 'float', 3.14, true);
1029
-		$config->clearCache();
1030
-		$this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
1031
-	}
1032
-
1033
-	public function testSetLazyValueFloatAsNonLazy(): void {
1034
-		$config = $this->generateAppConfig();
1035
-		$config->setValueFloat('feed', 'float', 3.14, true);
1036
-		$config->setValueFloat('feed', 'float', 3.14, false);
1037
-		$this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
1038
-	}
1039
-
1040
-	public function testSetNonLazyValueFloatAsLazy(): void {
1041
-		$config = $this->generateAppConfig();
1042
-		$config->setValueFloat('feed', 'float', 3.14, false);
1043
-		$config->setValueFloat('feed', 'float', 3.14, true);
1044
-		$this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
1045
-	}
1046
-
1047
-	public function testSetSensitiveValueFloat(): void {
1048
-		$config = $this->generateAppConfig();
1049
-		$config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1050
-		$this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
1051
-	}
1052
-
1053
-	public function testSetSensitiveValueFloatCache(): void {
1054
-		$config = $this->generateAppConfig();
1055
-		$config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1056
-		$status = $config->statusCache();
1057
-		$this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['float']);
1058
-	}
1059
-
1060
-	public function testSetSensitiveValueFloatDatabase(): void {
1061
-		$config = $this->generateAppConfig();
1062
-		$config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1063
-		$config->clearCache();
1064
-		$this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
1065
-	}
1066
-
1067
-	public function testSetNonSensitiveValueFloatAsSensitive(): void {
1068
-		$config = $this->generateAppConfig();
1069
-		$config->setValueFloat('feed', 'float', 3.14);
1070
-		$config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1071
-		$this->assertSame(true, $config->isSensitive('feed', 'float'));
1072
-	}
1073
-
1074
-	public function testSetSensitiveValueFloatAsNonSensitiveStaysSensitive(): void {
1075
-		$config = $this->generateAppConfig();
1076
-		$config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1077
-		$config->setValueFloat('feed', 'float', 1.23);
1078
-		$this->assertSame(true, $config->isSensitive('feed', 'float'));
1079
-	}
1080
-
1081
-	public function testSetSensitiveValueFloatAsNonSensitiveAreStillUpdated(): void {
1082
-		$config = $this->generateAppConfig();
1083
-		$config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1084
-		$config->setValueFloat('feed', 'float', 1.23);
1085
-		$this->assertSame(1.23, $config->getValueFloat('feed', 'float', 0));
1086
-	}
1087
-
1088
-	public function testSetLazyValueBool(): void {
1089
-		$config = $this->generateAppConfig();
1090
-		$config->setValueBool('feed', 'bool', true, true);
1091
-		$this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
1092
-	}
1093
-
1094
-	public function testSetLazyValueBoolCache(): void {
1095
-		$config = $this->generateAppConfig();
1096
-		$config->setValueBool('feed', 'bool', true, true);
1097
-		$status = $config->statusCache();
1098
-		$this->assertSame('1', $status['lazyCache']['feed']['bool']);
1099
-	}
1100
-
1101
-	public function testSetLazyValueBoolDatabase(): void {
1102
-		$config = $this->generateAppConfig();
1103
-		$config->setValueBool('feed', 'bool', true, true);
1104
-		$config->clearCache();
1105
-		$this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
1106
-	}
1107
-
1108
-	public function testSetLazyValueBoolAsNonLazy(): void {
1109
-		$config = $this->generateAppConfig();
1110
-		$config->setValueBool('feed', 'bool', true, true);
1111
-		$config->setValueBool('feed', 'bool', true, false);
1112
-		$this->assertSame(true, $config->getValueBool('feed', 'bool', false));
1113
-	}
1114
-
1115
-	public function testSetNonLazyValueBoolAsLazy(): void {
1116
-		$config = $this->generateAppConfig();
1117
-		$config->setValueBool('feed', 'bool', true, false);
1118
-		$config->setValueBool('feed', 'bool', true, true);
1119
-		$this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
1120
-	}
1121
-
1122
-	public function testSetLazyValueArray(): void {
1123
-		$config = $this->generateAppConfig();
1124
-		$config->setValueArray('feed', 'array', ['test' => 1], true);
1125
-		$this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
1126
-	}
1127
-
1128
-	public function testSetLazyValueArrayCache(): void {
1129
-		$config = $this->generateAppConfig();
1130
-		$config->setValueArray('feed', 'array', ['test' => 1], true);
1131
-		$status = $config->statusCache();
1132
-		$this->assertSame('{"test":1}', $status['lazyCache']['feed']['array']);
1133
-	}
1134
-
1135
-	public function testSetLazyValueArrayDatabase(): void {
1136
-		$config = $this->generateAppConfig();
1137
-		$config->setValueArray('feed', 'array', ['test' => 1], true);
1138
-		$config->clearCache();
1139
-		$this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
1140
-	}
1141
-
1142
-	public function testSetLazyValueArrayAsNonLazy(): void {
1143
-		$config = $this->generateAppConfig();
1144
-		$config->setValueArray('feed', 'array', ['test' => 1], true);
1145
-		$config->setValueArray('feed', 'array', ['test' => 1], false);
1146
-		$this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
1147
-	}
1148
-
1149
-	public function testSetNonLazyValueArrayAsLazy(): void {
1150
-		$config = $this->generateAppConfig();
1151
-		$config->setValueArray('feed', 'array', ['test' => 1], false);
1152
-		$config->setValueArray('feed', 'array', ['test' => 1], true);
1153
-		$this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
1154
-	}
1155
-
1156
-
1157
-	public function testSetSensitiveValueArray(): void {
1158
-		$config = $this->generateAppConfig();
1159
-		$config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1160
-		$this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('feed', 'array', []));
1161
-	}
1162
-
1163
-	public function testSetSensitiveValueArrayCache(): void {
1164
-		$config = $this->generateAppConfig();
1165
-		$config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1166
-		$status = $config->statusCache();
1167
-		$this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['array']);
1168
-	}
1169
-
1170
-	public function testSetSensitiveValueArrayDatabase(): void {
1171
-		$config = $this->generateAppConfig();
1172
-		$config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1173
-		$config->clearCache();
1174
-		$this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('feed', 'array', []));
1175
-	}
1176
-
1177
-	public function testSetNonSensitiveValueArrayAsSensitive(): void {
1178
-		$config = $this->generateAppConfig();
1179
-		$config->setValueArray('feed', 'array', ['test' => 1]);
1180
-		$config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1181
-		$this->assertSame(true, $config->isSensitive('feed', 'array'));
1182
-	}
1183
-
1184
-	public function testSetSensitiveValueArrayAsNonSensitiveStaysSensitive(): void {
1185
-		$config = $this->generateAppConfig();
1186
-		$config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1187
-		$config->setValueArray('feed', 'array', ['test' => 2]);
1188
-		$this->assertSame(true, $config->isSensitive('feed', 'array'));
1189
-	}
1190
-
1191
-	public function testSetSensitiveValueArrayAsNonSensitiveAreStillUpdated(): void {
1192
-		$config = $this->generateAppConfig();
1193
-		$config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1194
-		$config->setValueArray('feed', 'array', ['test' => 2]);
1195
-		$this->assertEqualsCanonicalizing(['test' => 2], $config->getValueArray('feed', 'array', []));
1196
-	}
1197
-
1198
-	public function testUpdateNotSensitiveToSensitive(): void {
1199
-		$config = $this->generateAppConfig();
1200
-		$config->updateSensitive('non-sensitive-app', 'lazy-key', true);
1201
-		$this->assertSame(true, $config->isSensitive('non-sensitive-app', 'lazy-key', true));
1202
-	}
1203
-
1204
-	public function testUpdateSensitiveToNotSensitive(): void {
1205
-		$config = $this->generateAppConfig();
1206
-		$config->updateSensitive('sensitive-app', 'lazy-key', false);
1207
-		$this->assertSame(false, $config->isSensitive('sensitive-app', 'lazy-key', true));
1208
-	}
1209
-
1210
-	public function testUpdateSensitiveToSensitiveReturnsFalse(): void {
1211
-		$config = $this->generateAppConfig();
1212
-		$this->assertSame(false, $config->updateSensitive('sensitive-app', 'lazy-key', true));
1213
-	}
1214
-
1215
-	public function testUpdateNotSensitiveToNotSensitiveReturnsFalse(): void {
1216
-		$config = $this->generateAppConfig();
1217
-		$this->assertSame(false, $config->updateSensitive('non-sensitive-app', 'lazy-key', false));
1218
-	}
1219
-
1220
-	public function testUpdateSensitiveOnUnknownKeyReturnsFalse(): void {
1221
-		$config = $this->generateAppConfig();
1222
-		$this->assertSame(false, $config->updateSensitive('non-sensitive-app', 'unknown-key', true));
1223
-	}
1224
-
1225
-	public function testUpdateNotLazyToLazy(): void {
1226
-		$config = $this->generateAppConfig();
1227
-		$config->updateLazy('non-sensitive-app', 'non-lazy-key', true);
1228
-		$this->assertSame(true, $config->isLazy('non-sensitive-app', 'non-lazy-key'));
1229
-	}
1230
-
1231
-	public function testUpdateLazyToNotLazy(): void {
1232
-		$config = $this->generateAppConfig();
1233
-		$config->updateLazy('non-sensitive-app', 'lazy-key', false);
1234
-		$this->assertSame(false, $config->isLazy('non-sensitive-app', 'lazy-key'));
1235
-	}
1236
-
1237
-	public function testUpdateLazyToLazyReturnsFalse(): void {
1238
-		$config = $this->generateAppConfig();
1239
-		$this->assertSame(false, $config->updateLazy('non-sensitive-app', 'lazy-key', true));
1240
-	}
1241
-
1242
-	public function testUpdateNotLazyToNotLazyReturnsFalse(): void {
1243
-		$config = $this->generateAppConfig();
1244
-		$this->assertSame(false, $config->updateLazy('non-sensitive-app', 'non-lazy-key', false));
1245
-	}
1246
-
1247
-	public function testUpdateLazyOnUnknownKeyReturnsFalse(): void {
1248
-		$config = $this->generateAppConfig();
1249
-		$this->assertSame(false, $config->updateLazy('non-sensitive-app', 'unknown-key', true));
1250
-	}
1251
-
1252
-	public function testGetDetails(): void {
1253
-		$config = $this->generateAppConfig();
1254
-		$this->assertEquals(
1255
-			[
1256
-				'app' => 'non-sensitive-app',
1257
-				'key' => 'lazy-key',
1258
-				'value' => 'value',
1259
-				'type' => 4,
1260
-				'lazy' => true,
1261
-				'typeString' => 'string',
1262
-				'sensitive' => false,
1263
-			],
1264
-			$config->getDetails('non-sensitive-app', 'lazy-key')
1265
-		);
1266
-	}
1267
-
1268
-	public function testGetDetailsSensitive(): void {
1269
-		$config = $this->generateAppConfig();
1270
-		$this->assertEquals(
1271
-			[
1272
-				'app' => 'sensitive-app',
1273
-				'key' => 'lazy-key',
1274
-				'value' => 'value',
1275
-				'type' => 4,
1276
-				'lazy' => true,
1277
-				'typeString' => 'string',
1278
-				'sensitive' => true,
1279
-			],
1280
-			$config->getDetails('sensitive-app', 'lazy-key')
1281
-		);
1282
-	}
1283
-
1284
-	public function testGetDetailsInt(): void {
1285
-		$config = $this->generateAppConfig();
1286
-		$this->assertEquals(
1287
-			[
1288
-				'app' => 'typed',
1289
-				'key' => 'int',
1290
-				'value' => '42',
1291
-				'type' => 8,
1292
-				'lazy' => false,
1293
-				'typeString' => 'integer',
1294
-				'sensitive' => false
1295
-			],
1296
-			$config->getDetails('typed', 'int')
1297
-		);
1298
-	}
1299
-
1300
-	public function testGetDetailsFloat(): void {
1301
-		$config = $this->generateAppConfig();
1302
-		$this->assertEquals(
1303
-			[
1304
-				'app' => 'typed',
1305
-				'key' => 'float',
1306
-				'value' => '3.14',
1307
-				'type' => 16,
1308
-				'lazy' => false,
1309
-				'typeString' => 'float',
1310
-				'sensitive' => false
1311
-			],
1312
-			$config->getDetails('typed', 'float')
1313
-		);
1314
-	}
1315
-
1316
-	public function testGetDetailsBool(): void {
1317
-		$config = $this->generateAppConfig();
1318
-		$this->assertEquals(
1319
-			[
1320
-				'app' => 'typed',
1321
-				'key' => 'bool',
1322
-				'value' => '1',
1323
-				'type' => 32,
1324
-				'lazy' => false,
1325
-				'typeString' => 'boolean',
1326
-				'sensitive' => false
1327
-			],
1328
-			$config->getDetails('typed', 'bool')
1329
-		);
1330
-	}
1331
-
1332
-	public function testGetDetailsArray(): void {
1333
-		$config = $this->generateAppConfig();
1334
-		$this->assertEquals(
1335
-			[
1336
-				'app' => 'typed',
1337
-				'key' => 'array',
1338
-				'value' => '{"test": 1}',
1339
-				'type' => 64,
1340
-				'lazy' => false,
1341
-				'typeString' => 'array',
1342
-				'sensitive' => false
1343
-			],
1344
-			$config->getDetails('typed', 'array')
1345
-		);
1346
-	}
1347
-
1348
-	public function testDeleteKey(): void {
1349
-		$config = $this->generateAppConfig();
1350
-		$config->deleteKey('anotherapp', 'key');
1351
-		$this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
1352
-	}
1353
-
1354
-	public function testDeleteKeyCache(): void {
1355
-		$config = $this->generateAppConfig();
1356
-		$config->deleteKey('anotherapp', 'key');
1357
-		$status = $config->statusCache();
1358
-		$this->assertEqualsCanonicalizing(['enabled' => 'no', 'installed_version' => '3.2.1'], $status['fastCache']['anotherapp']);
1359
-	}
1360
-
1361
-	public function testDeleteKeyDatabase(): void {
1362
-		$config = $this->generateAppConfig();
1363
-		$config->deleteKey('anotherapp', 'key');
1364
-		$config->clearCache();
1365
-		$this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
1366
-	}
1367
-
1368
-	public function testDeleteApp(): void {
1369
-		$config = $this->generateAppConfig();
1370
-		$config->deleteApp('anotherapp');
1371
-		$this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
1372
-		$this->assertSame('default', $config->getValueString('anotherapp', 'enabled', 'default'));
1373
-	}
1374
-
1375
-	public function testDeleteAppCache(): void {
1376
-		$config = $this->generateAppConfig();
1377
-		$status = $config->statusCache();
1378
-		$this->assertSame(true, isset($status['fastCache']['anotherapp']));
1379
-		$config->deleteApp('anotherapp');
1380
-		$status = $config->statusCache();
1381
-		$this->assertSame(false, isset($status['fastCache']['anotherapp']));
1382
-	}
1383
-
1384
-	public function testDeleteAppDatabase(): void {
1385
-		$config = $this->generateAppConfig();
1386
-		$config->deleteApp('anotherapp');
1387
-		$config->clearCache();
1388
-		$this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
1389
-		$this->assertSame('default', $config->getValueString('anotherapp', 'enabled', 'default'));
1390
-	}
1391
-
1392
-	public function testClearCache(): void {
1393
-		$config = $this->generateAppConfig();
1394
-		$config->setValueString('feed', 'string', '123454');
1395
-		$config->clearCache();
1396
-		$status = $config->statusCache();
1397
-		$this->assertSame([], $status['fastCache']);
1398
-	}
1399
-
1400
-	public function testSensitiveValuesAreEncrypted(): void {
1401
-		$key = self::getUniqueID('secret');
1402
-
1403
-		$appConfig = $this->generateAppConfig();
1404
-		$secret = md5((string)time());
1405
-		$appConfig->setValueString('testapp', $key, $secret, sensitive: true);
1406
-
1407
-		$this->assertConfigValueNotEquals('testapp', $key, $secret);
1408
-
1409
-		// Can get in same run
1410
-		$actualSecret = $appConfig->getValueString('testapp', $key);
1411
-		$this->assertEquals($secret, $actualSecret);
1412
-
1413
-		// Can get freshly decrypted from DB
1414
-		$newAppConfig = $this->generateAppConfig();
1415
-		$actualSecret = $newAppConfig->getValueString('testapp', $key);
1416
-		$this->assertEquals($secret, $actualSecret);
1417
-	}
1418
-
1419
-	public function testMigratingNonSensitiveValueToSensitiveWithSetValue(): void {
1420
-		$key = self::getUniqueID('secret');
1421
-		$appConfig = $this->generateAppConfig();
1422
-		$secret = sha1((string)time());
1423
-
1424
-		// Unencrypted
1425
-		$appConfig->setValueString('testapp', $key, $secret);
1426
-		$this->assertConfigKey('testapp', $key, $secret);
1427
-
1428
-		// Can get freshly decrypted from DB
1429
-		$newAppConfig = $this->generateAppConfig();
1430
-		$actualSecret = $newAppConfig->getValueString('testapp', $key);
1431
-		$this->assertEquals($secret, $actualSecret);
1432
-
1433
-		// Encrypting on change
1434
-		$appConfig->setValueString('testapp', $key, $secret, sensitive: true);
1435
-		$this->assertConfigValueNotEquals('testapp', $key, $secret);
1436
-
1437
-		// Can get in same run
1438
-		$actualSecret = $appConfig->getValueString('testapp', $key);
1439
-		$this->assertEquals($secret, $actualSecret);
1440
-
1441
-		// Can get freshly decrypted from DB
1442
-		$newAppConfig = $this->generateAppConfig();
1443
-		$actualSecret = $newAppConfig->getValueString('testapp', $key);
1444
-		$this->assertEquals($secret, $actualSecret);
1445
-	}
1446
-
1447
-	public function testUpdateSensitiveValueToNonSensitiveWithUpdateSensitive(): void {
1448
-		$key = self::getUniqueID('secret');
1449
-		$appConfig = $this->generateAppConfig();
1450
-		$secret = sha1((string)time());
1451
-
1452
-		// Encrypted
1453
-		$appConfig->setValueString('testapp', $key, $secret, sensitive: true);
1454
-		$this->assertConfigValueNotEquals('testapp', $key, $secret);
1455
-
1456
-		// Migrate to non-sensitive / non-encrypted
1457
-		$appConfig->updateSensitive('testapp', $key, false);
1458
-		$this->assertConfigKey('testapp', $key, $secret);
1459
-	}
1460
-
1461
-	public function testUpdateNonSensitiveValueToSensitiveWithUpdateSensitive(): void {
1462
-		$key = self::getUniqueID('secret');
1463
-		$appConfig = $this->generateAppConfig();
1464
-		$secret = sha1((string)time());
1465
-
1466
-		// Unencrypted
1467
-		$appConfig->setValueString('testapp', $key, $secret);
1468
-		$this->assertConfigKey('testapp', $key, $secret);
1469
-
1470
-		// Migrate to sensitive / encrypted
1471
-		$appConfig->updateSensitive('testapp', $key, true);
1472
-		$this->assertConfigValueNotEquals('testapp', $key, $secret);
1473
-	}
1474
-
1475
-	public function testSearchKeyNoLazyLoading(): void {
1476
-		$appConfig = $this->generateAppConfig();
1477
-		$appConfig->searchKeys('searchtest', 'search_');
1478
-		$status = $appConfig->statusCache();
1479
-		$this->assertFalse($status['lazyLoaded'], 'searchKeys() loaded lazy config');
1480
-	}
1481
-
1482
-	public function testSearchKeyFast(): void {
1483
-		$appConfig = $this->generateAppConfig();
1484
-		$this->assertEquals(['search_key1', 'search_key2', 'search_key3'], $appConfig->searchKeys('searchtest', 'search_'));
1485
-	}
1486
-
1487
-	public function testSearchKeyLazy(): void {
1488
-		$appConfig = $this->generateAppConfig();
1489
-		$this->assertEquals(['search_key5_lazy'], $appConfig->searchKeys('searchtest', 'search_', true));
1490
-	}
1491
-
1492
-	protected function loadConfigValueFromDatabase(string $app, string $key): string|false {
1493
-		$sql = $this->connection->getQueryBuilder();
1494
-		$sql->select('configvalue')
1495
-			->from('appconfig')
1496
-			->where($sql->expr()->eq('appid', $sql->createParameter('appid')))
1497
-			->andWhere($sql->expr()->eq('configkey', $sql->createParameter('configkey')))
1498
-			->setParameter('appid', $app)
1499
-			->setParameter('configkey', $key);
1500
-		$query = $sql->executeQuery();
1501
-		$actual = $query->fetchOne();
1502
-		$query->closeCursor();
1503
-
1504
-		return $actual;
1505
-	}
1506
-
1507
-	protected function assertConfigKey(string $app, string $key, string|false $expected): void {
1508
-		$this->assertEquals($expected, $this->loadConfigValueFromDatabase($app, $key));
1509
-	}
1510
-
1511
-	protected function assertConfigValueNotEquals(string $app, string $key, string|false $expected): void {
1512
-		$this->assertNotEquals($expected, $this->loadConfigValueFromDatabase($app, $key));
1513
-	}
30
+    protected IAppConfig $appConfig;
31
+    protected IDBConnection $connection;
32
+    private IConfig $config;
33
+    private ConfigManager $configManager;
34
+    private PresetManager $presetManager;
35
+    private LoggerInterface $logger;
36
+    private ICrypto $crypto;
37
+    private CacheFactory&MockObject $cacheFactory;
38
+
39
+    private array $originalConfig;
40
+
41
+    /**
42
+     * @var array<string, array<string, array<string, string, int, bool, bool>>>
43
+     *                                                                           [appId => [configKey, configValue, valueType, lazy, sensitive]]
44
+     */
45
+    private static array $baseStruct
46
+        = [
47
+            'testapp' => [
48
+                'enabled' => ['enabled', 'yes'],
49
+                'installed_version' => ['installed_version', '1.2.3'],
50
+                'depends_on' => ['depends_on', 'someapp'],
51
+                'deletethis' => ['deletethis', 'deletethis'],
52
+                'key' => ['key', 'value']
53
+            ],
54
+            'searchtest' => [
55
+                'search_key1' => ['search_key1', 'key1', IAppConfig::VALUE_STRING],
56
+                'search_key2' => ['search_key2', 'key2', IAppConfig::VALUE_STRING],
57
+                'search_key3' => ['search_key3', 'key3', IAppConfig::VALUE_STRING],
58
+                'searchnot_key4' => ['searchnot_key4', 'key4', IAppConfig::VALUE_STRING],
59
+                'search_key5_lazy' => ['search_key5_lazy', 'key5', IAppConfig::VALUE_STRING, true],
60
+            ],
61
+            'someapp' => [
62
+                'key' => ['key', 'value'],
63
+                'otherkey' => ['otherkey', 'othervalue']
64
+            ],
65
+            '123456' => [
66
+                'enabled' => ['enabled', 'yes'],
67
+                'key' => ['key', 'value']
68
+            ],
69
+            'anotherapp' => [
70
+                'enabled' => ['enabled', 'no'],
71
+                'installed_version' => ['installed_version', '3.2.1'],
72
+                'key' => ['key', 'value']
73
+            ],
74
+            'non-sensitive-app' => [
75
+                'lazy-key' => ['lazy-key', 'value', IAppConfig::VALUE_STRING, true, false],
76
+                'non-lazy-key' => ['non-lazy-key', 'value', IAppConfig::VALUE_STRING, false, false],
77
+            ],
78
+            'sensitive-app' => [
79
+                'lazy-key' => ['lazy-key', 'value', IAppConfig::VALUE_STRING, true, true],
80
+                'non-lazy-key' => ['non-lazy-key', 'value', IAppConfig::VALUE_STRING, false, true],
81
+            ],
82
+            'only-lazy' => [
83
+                'lazy-key' => ['lazy-key', 'value', IAppConfig::VALUE_STRING, true]
84
+            ],
85
+            'typed' => [
86
+                'mixed' => ['mixed', 'mix', IAppConfig::VALUE_MIXED],
87
+                'string' => ['string', 'value', IAppConfig::VALUE_STRING],
88
+                'int' => ['int', '42', IAppConfig::VALUE_INT],
89
+                'float' => ['float', '3.14', IAppConfig::VALUE_FLOAT],
90
+                'bool' => ['bool', '1', IAppConfig::VALUE_BOOL],
91
+                'array' => ['array', '{"test": 1}', IAppConfig::VALUE_ARRAY],
92
+            ],
93
+            'prefix-app' => [
94
+                'key1' => ['key1', 'value'],
95
+                'prefix1' => ['prefix1', 'value'],
96
+                'prefix-2' => ['prefix-2', 'value'],
97
+                'key-2' => ['key-2', 'value'],
98
+            ]
99
+        ];
100
+
101
+    protected function setUp(): void {
102
+        parent::setUp();
103
+
104
+        $this->connection = Server::get(IDBConnection::class);
105
+        $this->config = Server::get(IConfig::class);
106
+        $this->configManager = Server::get(ConfigManager::class);
107
+        $this->presetManager = Server::get(PresetManager::class);
108
+        $this->logger = Server::get(LoggerInterface::class);
109
+        $this->crypto = Server::get(ICrypto::class);
110
+        $this->cacheFactory = $this->createMock(CacheFactory::class);
111
+        $this->cacheFactory->method('isLocalCacheAvailable')->willReturn(false);
112
+
113
+        // storing current config and emptying the data table
114
+        $sql = $this->connection->getQueryBuilder();
115
+        $sql->select('*')
116
+            ->from('appconfig');
117
+        $result = $sql->executeQuery();
118
+        $this->originalConfig = $result->fetchAllAssociative();
119
+        $result->closeCursor();
120
+
121
+        $sql = $this->connection->getQueryBuilder();
122
+        $sql->delete('appconfig');
123
+        $sql->executeStatement();
124
+
125
+        $sql = $this->connection->getQueryBuilder();
126
+        $sql->insert('appconfig')
127
+            ->values(
128
+                [
129
+                    'appid' => $sql->createParameter('appid'),
130
+                    'configkey' => $sql->createParameter('configkey'),
131
+                    'configvalue' => $sql->createParameter('configvalue'),
132
+                    'type' => $sql->createParameter('type'),
133
+                    'lazy' => $sql->createParameter('lazy')
134
+                ]
135
+            );
136
+
137
+        foreach (self::$baseStruct as $appId => $appData) {
138
+            foreach ($appData as $key => $row) {
139
+                $value = $row[1];
140
+                $type = $row[2] ?? IAppConfig::VALUE_MIXED;
141
+                if (($row[4] ?? false) === true) {
142
+                    $type |= IAppConfig::VALUE_SENSITIVE;
143
+                    $value = self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX') . $this->crypto->encrypt($value);
144
+                    self::$baseStruct[$appId][$key]['encrypted'] = $value;
145
+                }
146
+
147
+                $sql->setParameters(
148
+                    [
149
+                        'appid' => $appId,
150
+                        'configkey' => $row[0],
151
+                        'configvalue' => $value,
152
+                        'type' => $type,
153
+                        'lazy' => (($row[3] ?? false) === true) ? 1 : 0
154
+                    ]
155
+                )->executeStatement();
156
+            }
157
+        }
158
+    }
159
+
160
+    protected function tearDown(): void {
161
+        $sql = $this->connection->getQueryBuilder();
162
+        $sql->delete('appconfig');
163
+        $sql->executeStatement();
164
+
165
+        $sql = $this->connection->getQueryBuilder();
166
+        $sql->insert('appconfig')
167
+            ->values(
168
+                [
169
+                    'appid' => $sql->createParameter('appid'),
170
+                    'configkey' => $sql->createParameter('configkey'),
171
+                    'configvalue' => $sql->createParameter('configvalue'),
172
+                    'lazy' => $sql->createParameter('lazy'),
173
+                    'type' => $sql->createParameter('type'),
174
+                ]
175
+            );
176
+
177
+        foreach ($this->originalConfig as $key => $configs) {
178
+            $sql->setParameter('appid', $configs['appid'])
179
+                ->setParameter('configkey', $configs['configkey'])
180
+                ->setParameter('configvalue', $configs['configvalue'])
181
+                ->setParameter('lazy', ($configs['lazy'] === '1') ? '1' : '0')
182
+                ->setParameter('type', $configs['type']);
183
+            $sql->executeStatement();
184
+        }
185
+
186
+        //		$this->restoreService(AppConfig::class);
187
+        parent::tearDown();
188
+    }
189
+
190
+    /**
191
+     * @param bool $preLoading TRUE will preload the 'fast' cache, which is the normal behavior of usual
192
+     *                         IAppConfig
193
+     *
194
+     * @return IAppConfig
195
+     */
196
+    private function generateAppConfig(bool $preLoading = true): IAppConfig {
197
+        /** @var AppConfig $config */
198
+        $config = new AppConfig(
199
+            $this->connection,
200
+            $this->config,
201
+            $this->configManager,
202
+            $this->presetManager,
203
+            $this->logger,
204
+            $this->crypto,
205
+            $this->cacheFactory,
206
+        );
207
+        $msg = ' generateAppConfig() failed to confirm cache status';
208
+
209
+        // confirm cache status
210
+        $status = $config->statusCache();
211
+        $this->assertSame(false, $status['fastLoaded'], $msg);
212
+        $this->assertSame(false, $status['lazyLoaded'], $msg);
213
+        $this->assertSame([], $status['fastCache'], $msg);
214
+        $this->assertSame([], $status['lazyCache'], $msg);
215
+        if ($preLoading) {
216
+            // simple way to initiate the load of non-lazy config values in cache
217
+            $config->getValueString('core', 'preload', '');
218
+
219
+            // confirm cache status
220
+            $status = $config->statusCache();
221
+            $this->assertSame(true, $status['fastLoaded'], $msg);
222
+            $this->assertSame(false, $status['lazyLoaded'], $msg);
223
+
224
+            $apps = array_values(array_diff(array_keys(self::$baseStruct), ['only-lazy']));
225
+            $this->assertEqualsCanonicalizing($apps, array_keys($status['fastCache']), $msg);
226
+            $this->assertSame([], array_keys($status['lazyCache']), $msg);
227
+        }
228
+
229
+        return $config;
230
+    }
231
+
232
+    public function testGetApps(): void {
233
+        $config = $this->generateAppConfig(false);
234
+
235
+        $this->assertEqualsCanonicalizing(array_keys(self::$baseStruct), $config->getApps());
236
+    }
237
+
238
+    public function testGetAppInstalledVersions(): void {
239
+        $config = $this->generateAppConfig(false);
240
+
241
+        $this->assertEquals(
242
+            ['testapp' => '1.2.3', 'anotherapp' => '3.2.1'],
243
+            $config->getAppInstalledVersions(false)
244
+        );
245
+        $this->assertEquals(
246
+            ['testapp' => '1.2.3'],
247
+            $config->getAppInstalledVersions(true)
248
+        );
249
+    }
250
+
251
+    /**
252
+     * returns list of app and their keys
253
+     *
254
+     * @return array<string, string[]> ['appId' => ['key1', 'key2', ]]
255
+     * @see testGetKeys
256
+     */
257
+    public static function providerGetAppKeys(): array {
258
+        $appKeys = [];
259
+        foreach (self::$baseStruct as $appId => $appData) {
260
+            $keys = [];
261
+            foreach ($appData as $row) {
262
+                $keys[] = $row[0];
263
+            }
264
+            $appKeys[] = [(string)$appId, $keys];
265
+        }
266
+
267
+        return $appKeys;
268
+    }
269
+
270
+    /**
271
+     * returns list of config keys
272
+     *
273
+     * @return array<string, string, string, int, bool, bool> [appId, key, value, type, lazy, sensitive]
274
+     * @see testIsSensitive
275
+     * @see testIsLazy
276
+     * @see testGetKeys
277
+     */
278
+    public static function providerGetKeys(): array {
279
+        $appKeys = [];
280
+        foreach (self::$baseStruct as $appId => $appData) {
281
+            foreach ($appData as $row) {
282
+                $appKeys[] = [
283
+                    (string)$appId, $row[0], $row[1], $row[2] ?? IAppConfig::VALUE_MIXED, $row[3] ?? false,
284
+                    $row[4] ?? false
285
+                ];
286
+            }
287
+        }
288
+
289
+        return $appKeys;
290
+    }
291
+
292
+    /**
293
+     *
294
+     * @param string $appId
295
+     * @param array $expectedKeys
296
+     */
297
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetAppKeys')]
298
+    public function testGetKeys(string $appId, array $expectedKeys): void {
299
+        $config = $this->generateAppConfig();
300
+        $this->assertEqualsCanonicalizing($expectedKeys, $config->getKeys($appId));
301
+    }
302
+
303
+    public function testGetKeysOnUnknownAppShouldReturnsEmptyArray(): void {
304
+        $config = $this->generateAppConfig();
305
+        $this->assertEqualsCanonicalizing([], $config->getKeys('unknown-app'));
306
+    }
307
+
308
+    /**
309
+     *
310
+     * @param string $appId
311
+     * @param string $configKey
312
+     * @param string $value
313
+     * @param bool $lazy
314
+     */
315
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetKeys')]
316
+    public function testHasKey(string $appId, string $configKey, string $value, int $type, bool $lazy): void {
317
+        $config = $this->generateAppConfig();
318
+        $this->assertEquals(true, $config->hasKey($appId, $configKey, $lazy));
319
+    }
320
+
321
+    public function testHasKeyOnNonExistentKeyReturnsFalse(): void {
322
+        $config = $this->generateAppConfig();
323
+        $this->assertEquals(false, $config->hasKey(array_keys(self::$baseStruct)[0], 'inexistant-key'));
324
+    }
325
+
326
+    public function testHasKeyOnUnknownAppReturnsFalse(): void {
327
+        $config = $this->generateAppConfig();
328
+        $this->assertEquals(false, $config->hasKey('inexistant-app', 'inexistant-key'));
329
+    }
330
+
331
+    public function testHasKeyOnMistypedAsLazyReturnsFalse(): void {
332
+        $config = $this->generateAppConfig();
333
+        $this->assertSame(false, $config->hasKey('non-sensitive-app', 'non-lazy-key', true));
334
+    }
335
+
336
+    public function testHasKeyOnMistypeAsNonLazyReturnsFalse(): void {
337
+        $config = $this->generateAppConfig();
338
+        $this->assertSame(false, $config->hasKey('non-sensitive-app', 'lazy-key', false));
339
+    }
340
+
341
+    public function testHasKeyOnMistypeAsNonLazyReturnsTrueWithLazyArgumentIsNull(): void {
342
+        $config = $this->generateAppConfig();
343
+        $this->assertSame(true, $config->hasKey('non-sensitive-app', 'lazy-key', null));
344
+    }
345
+
346
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetKeys')]
347
+    public function testIsSensitive(
348
+        string $appId, string $configKey, string $configValue, int $type, bool $lazy, bool $sensitive,
349
+    ): void {
350
+        $config = $this->generateAppConfig();
351
+        $this->assertEquals($sensitive, $config->isSensitive($appId, $configKey, $lazy));
352
+    }
353
+
354
+    public function testIsSensitiveOnNonExistentKeyThrowsException(): void {
355
+        $config = $this->generateAppConfig();
356
+        $this->expectException(AppConfigUnknownKeyException::class);
357
+        $config->isSensitive(array_keys(self::$baseStruct)[0], 'inexistant-key');
358
+    }
359
+
360
+    public function testIsSensitiveOnUnknownAppThrowsException(): void {
361
+        $config = $this->generateAppConfig();
362
+        $this->expectException(AppConfigUnknownKeyException::class);
363
+        $config->isSensitive('unknown-app', 'inexistant-key');
364
+    }
365
+
366
+    public function testIsSensitiveOnSensitiveMistypedAsLazy(): void {
367
+        $config = $this->generateAppConfig();
368
+        $this->assertSame(true, $config->isSensitive('sensitive-app', 'non-lazy-key', true));
369
+    }
370
+
371
+    public function testIsSensitiveOnNonSensitiveMistypedAsLazy(): void {
372
+        $config = $this->generateAppConfig();
373
+        $this->assertSame(false, $config->isSensitive('non-sensitive-app', 'non-lazy-key', true));
374
+    }
375
+
376
+    public function testIsSensitiveOnSensitiveMistypedAsNonLazyThrowsException(): void {
377
+        $config = $this->generateAppConfig();
378
+        $this->expectException(AppConfigUnknownKeyException::class);
379
+        $config->isSensitive('sensitive-app', 'lazy-key', false);
380
+    }
381
+
382
+    public function testIsSensitiveOnNonSensitiveMistypedAsNonLazyThrowsException(): void {
383
+        $config = $this->generateAppConfig();
384
+        $this->expectException(AppConfigUnknownKeyException::class);
385
+        $config->isSensitive('non-sensitive-app', 'lazy-key', false);
386
+    }
387
+
388
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetKeys')]
389
+    public function testIsLazy(string $appId, string $configKey, string $configValue, int $type, bool $lazy,
390
+    ): void {
391
+        $config = $this->generateAppConfig();
392
+        $this->assertEquals($lazy, $config->isLazy($appId, $configKey));
393
+    }
394
+
395
+    public function testIsLazyOnNonExistentKeyThrowsException(): void {
396
+        $config = $this->generateAppConfig();
397
+        $this->expectException(AppConfigUnknownKeyException::class);
398
+        $config->isLazy(array_keys(self::$baseStruct)[0], 'inexistant-key');
399
+    }
400
+
401
+    public function testIsLazyOnUnknownAppThrowsException(): void {
402
+        $config = $this->generateAppConfig();
403
+        $this->expectException(AppConfigUnknownKeyException::class);
404
+        $config->isLazy('unknown-app', 'inexistant-key');
405
+    }
406
+
407
+    public function testGetAllValues(): void {
408
+        $config = $this->generateAppConfig();
409
+        $this->assertEquals(
410
+            [
411
+                'array' => ['test' => 1],
412
+                'bool' => true,
413
+                'float' => 3.14,
414
+                'int' => 42,
415
+                'mixed' => 'mix',
416
+                'string' => 'value',
417
+            ],
418
+            $config->getAllValues('typed')
419
+        );
420
+    }
421
+
422
+    public function testGetAllValuesWithEmptyApp(): void {
423
+        $config = $this->generateAppConfig();
424
+        $this->expectException(InvalidArgumentException::class);
425
+        $config->getAllValues('');
426
+    }
427
+
428
+    /**
429
+     *
430
+     * @param string $appId
431
+     * @param array $keys
432
+     */
433
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetAppKeys')]
434
+    public function testGetAllValuesWithEmptyKey(string $appId, array $keys): void {
435
+        $config = $this->generateAppConfig();
436
+        $this->assertEqualsCanonicalizing($keys, array_keys($config->getAllValues($appId, '')));
437
+    }
438
+
439
+    public function testGetAllValuesWithPrefix(): void {
440
+        $config = $this->generateAppConfig();
441
+        $this->assertEqualsCanonicalizing(['prefix1', 'prefix-2'], array_keys($config->getAllValues('prefix-app', 'prefix')));
442
+    }
443
+
444
+    public function testSearchValues(): void {
445
+        $config = $this->generateAppConfig();
446
+        $this->assertEqualsCanonicalizing(['testapp' => 'yes', '123456' => 'yes', 'anotherapp' => 'no'], $config->searchValues('enabled'));
447
+    }
448
+
449
+    public function testGetValueString(): void {
450
+        $config = $this->generateAppConfig();
451
+        $this->assertSame('value', $config->getValueString('typed', 'string', ''));
452
+    }
453
+
454
+    public function testGetValueStringOnUnknownAppReturnsDefault(): void {
455
+        $config = $this->generateAppConfig();
456
+        $this->assertSame('default-1', $config->getValueString('typed-1', 'string', 'default-1'));
457
+    }
458
+
459
+    public function testGetValueStringOnNonExistentKeyReturnsDefault(): void {
460
+        $config = $this->generateAppConfig();
461
+        $this->assertSame('default-2', $config->getValueString('typed', 'string-2', 'default-2'));
462
+    }
463
+
464
+    public function testGetValueStringOnWrongType(): void {
465
+        $config = $this->generateAppConfig();
466
+        $this->expectException(AppConfigTypeConflictException::class);
467
+        $config->getValueString('typed', 'int');
468
+    }
469
+
470
+    public function testGetNonLazyValueStringAsLazy(): void {
471
+        $config = $this->generateAppConfig();
472
+        $this->assertSame('value', $config->getValueString('non-sensitive-app', 'non-lazy-key', 'default', lazy: true));
473
+    }
474
+
475
+    public function testGetValueInt(): void {
476
+        $config = $this->generateAppConfig();
477
+        $this->assertSame(42, $config->getValueInt('typed', 'int', 0));
478
+    }
479
+
480
+    public function testGetValueIntOnUnknownAppReturnsDefault(): void {
481
+        $config = $this->generateAppConfig();
482
+        $this->assertSame(1, $config->getValueInt('typed-1', 'int', 1));
483
+    }
484
+
485
+    public function testGetValueIntOnNonExistentKeyReturnsDefault(): void {
486
+        $config = $this->generateAppConfig();
487
+        $this->assertSame(2, $config->getValueInt('typed', 'int-2', 2));
488
+    }
489
+
490
+    public function testGetValueIntOnWrongType(): void {
491
+        $config = $this->generateAppConfig();
492
+        $this->expectException(AppConfigTypeConflictException::class);
493
+        $config->getValueInt('typed', 'float');
494
+    }
495
+
496
+    public function testGetValueFloat(): void {
497
+        $config = $this->generateAppConfig();
498
+        $this->assertSame(3.14, $config->getValueFloat('typed', 'float', 0));
499
+    }
500
+
501
+    public function testGetValueFloatOnNonUnknownAppReturnsDefault(): void {
502
+        $config = $this->generateAppConfig();
503
+        $this->assertSame(1.11, $config->getValueFloat('typed-1', 'float', 1.11));
504
+    }
505
+
506
+    public function testGetValueFloatOnNonExistentKeyReturnsDefault(): void {
507
+        $config = $this->generateAppConfig();
508
+        $this->assertSame(2.22, $config->getValueFloat('typed', 'float-2', 2.22));
509
+    }
510
+
511
+    public function testGetValueFloatOnWrongType(): void {
512
+        $config = $this->generateAppConfig();
513
+        $this->expectException(AppConfigTypeConflictException::class);
514
+        $config->getValueFloat('typed', 'bool');
515
+    }
516
+
517
+    public function testGetValueBool(): void {
518
+        $config = $this->generateAppConfig();
519
+        $this->assertSame(true, $config->getValueBool('typed', 'bool'));
520
+    }
521
+
522
+    public function testGetValueBoolOnUnknownAppReturnsDefault(): void {
523
+        $config = $this->generateAppConfig();
524
+        $this->assertSame(false, $config->getValueBool('typed-1', 'bool', false));
525
+    }
526
+
527
+    public function testGetValueBoolOnNonExistentKeyReturnsDefault(): void {
528
+        $config = $this->generateAppConfig();
529
+        $this->assertSame(false, $config->getValueBool('typed', 'bool-2'));
530
+    }
531
+
532
+    public function testGetValueBoolOnWrongType(): void {
533
+        $config = $this->generateAppConfig();
534
+        $this->expectException(AppConfigTypeConflictException::class);
535
+        $config->getValueBool('typed', 'array');
536
+    }
537
+
538
+    public function testGetValueArray(): void {
539
+        $config = $this->generateAppConfig();
540
+        $this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('typed', 'array', []));
541
+    }
542
+
543
+    public function testGetValueArrayOnUnknownAppReturnsDefault(): void {
544
+        $config = $this->generateAppConfig();
545
+        $this->assertSame([1], $config->getValueArray('typed-1', 'array', [1]));
546
+    }
547
+
548
+    public function testGetValueArrayOnNonExistentKeyReturnsDefault(): void {
549
+        $config = $this->generateAppConfig();
550
+        $this->assertSame([1, 2], $config->getValueArray('typed', 'array-2', [1, 2]));
551
+    }
552
+
553
+    public function testGetValueArrayOnWrongType(): void {
554
+        $config = $this->generateAppConfig();
555
+        $this->expectException(AppConfigTypeConflictException::class);
556
+        $config->getValueArray('typed', 'string');
557
+    }
558
+
559
+
560
+    /**
561
+     * @return array
562
+     * @see testGetValueType
563
+     *
564
+     * @see testGetValueMixed
565
+     */
566
+    public static function providerGetValueMixed(): array {
567
+        return [
568
+            // key, value, type
569
+            ['mixed', 'mix', IAppConfig::VALUE_MIXED],
570
+            ['string', 'value', IAppConfig::VALUE_STRING],
571
+            ['int', '42', IAppConfig::VALUE_INT],
572
+            ['float', '3.14', IAppConfig::VALUE_FLOAT],
573
+            ['bool', '1', IAppConfig::VALUE_BOOL],
574
+            ['array', '{"test": 1}', IAppConfig::VALUE_ARRAY],
575
+        ];
576
+    }
577
+
578
+    /**
579
+     *
580
+     * @param string $key
581
+     * @param string $value
582
+     */
583
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueMixed')]
584
+    public function testGetValueMixed(string $key, string $value): void {
585
+        $config = $this->generateAppConfig();
586
+        $this->assertSame($value, $config->getValueMixed('typed', $key));
587
+    }
588
+
589
+    /**
590
+     *
591
+     * @param string $key
592
+     * @param string $value
593
+     * @param int $type
594
+     */
595
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueMixed')]
596
+    public function testGetValueType(string $key, string $value, int $type): void {
597
+        $config = $this->generateAppConfig();
598
+        $this->assertSame($type, $config->getValueType('typed', $key));
599
+    }
600
+
601
+    public function testGetValueTypeOnUnknownApp(): void {
602
+        $config = $this->generateAppConfig();
603
+        $this->expectException(AppConfigUnknownKeyException::class);
604
+        $config->getValueType('typed-1', 'string');
605
+    }
606
+
607
+    public function testGetValueTypeOnNonExistentKey(): void {
608
+        $config = $this->generateAppConfig();
609
+        $this->expectException(AppConfigUnknownKeyException::class);
610
+        $config->getValueType('typed', 'string-2');
611
+    }
612
+
613
+    public function testSetValueString(): void {
614
+        $config = $this->generateAppConfig();
615
+        $config->setValueString('feed', 'string', 'value-1');
616
+        $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
617
+    }
618
+
619
+    public function testSetValueStringCache(): void {
620
+        $config = $this->generateAppConfig();
621
+        $config->setValueString('feed', 'string', 'value-1');
622
+        $status = $config->statusCache();
623
+        $this->assertSame('value-1', $status['fastCache']['feed']['string']);
624
+    }
625
+
626
+    public function testSetValueStringDatabase(): void {
627
+        $config = $this->generateAppConfig();
628
+        $config->setValueString('feed', 'string', 'value-1');
629
+        $config->clearCache();
630
+        $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
631
+    }
632
+
633
+    public function testSetValueStringIsUpdated(): void {
634
+        $config = $this->generateAppConfig();
635
+        $config->setValueString('feed', 'string', 'value-1');
636
+        $this->assertSame(true, $config->setValueString('feed', 'string', 'value-2'));
637
+    }
638
+
639
+    public function testSetValueStringIsNotUpdated(): void {
640
+        $config = $this->generateAppConfig();
641
+        $config->setValueString('feed', 'string', 'value-1');
642
+        $this->assertSame(false, $config->setValueString('feed', 'string', 'value-1'));
643
+    }
644
+
645
+    public function testSetValueStringIsUpdatedCache(): void {
646
+        $config = $this->generateAppConfig();
647
+        $config->setValueString('feed', 'string', 'value-1');
648
+        $config->setValueString('feed', 'string', 'value-2');
649
+        $status = $config->statusCache();
650
+        $this->assertSame('value-2', $status['fastCache']['feed']['string']);
651
+    }
652
+
653
+    public function testSetValueStringIsUpdatedDatabase(): void {
654
+        $config = $this->generateAppConfig();
655
+        $config->setValueString('feed', 'string', 'value-1');
656
+        $config->setValueString('feed', 'string', 'value-2');
657
+        $config->clearCache();
658
+        $this->assertSame('value-2', $config->getValueString('feed', 'string', ''));
659
+    }
660
+
661
+    public function testSetValueInt(): void {
662
+        $config = $this->generateAppConfig();
663
+        $config->setValueInt('feed', 'int', 42);
664
+        $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
665
+    }
666
+
667
+    public function testSetValueIntCache(): void {
668
+        $config = $this->generateAppConfig();
669
+        $config->setValueInt('feed', 'int', 42);
670
+        $status = $config->statusCache();
671
+        $this->assertSame('42', $status['fastCache']['feed']['int']);
672
+    }
673
+
674
+    public function testSetValueIntDatabase(): void {
675
+        $config = $this->generateAppConfig();
676
+        $config->setValueInt('feed', 'int', 42);
677
+        $config->clearCache();
678
+        $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
679
+    }
680
+
681
+    public function testSetValueIntIsUpdated(): void {
682
+        $config = $this->generateAppConfig();
683
+        $config->setValueInt('feed', 'int', 42);
684
+        $this->assertSame(true, $config->setValueInt('feed', 'int', 17));
685
+    }
686
+
687
+    public function testSetValueIntIsNotUpdated(): void {
688
+        $config = $this->generateAppConfig();
689
+        $config->setValueInt('feed', 'int', 42);
690
+        $this->assertSame(false, $config->setValueInt('feed', 'int', 42));
691
+    }
692
+
693
+    public function testSetValueIntIsUpdatedCache(): void {
694
+        $config = $this->generateAppConfig();
695
+        $config->setValueInt('feed', 'int', 42);
696
+        $config->setValueInt('feed', 'int', 17);
697
+        $status = $config->statusCache();
698
+        $this->assertSame('17', $status['fastCache']['feed']['int']);
699
+    }
700
+
701
+    public function testSetValueIntIsUpdatedDatabase(): void {
702
+        $config = $this->generateAppConfig();
703
+        $config->setValueInt('feed', 'int', 42);
704
+        $config->setValueInt('feed', 'int', 17);
705
+        $config->clearCache();
706
+        $this->assertSame(17, $config->getValueInt('feed', 'int', 0));
707
+    }
708
+
709
+    public function testSetValueFloat(): void {
710
+        $config = $this->generateAppConfig();
711
+        $config->setValueFloat('feed', 'float', 3.14);
712
+        $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
713
+    }
714
+
715
+    public function testSetValueFloatCache(): void {
716
+        $config = $this->generateAppConfig();
717
+        $config->setValueFloat('feed', 'float', 3.14);
718
+        $status = $config->statusCache();
719
+        $this->assertSame('3.14', $status['fastCache']['feed']['float']);
720
+    }
721
+
722
+    public function testSetValueFloatDatabase(): void {
723
+        $config = $this->generateAppConfig();
724
+        $config->setValueFloat('feed', 'float', 3.14);
725
+        $config->clearCache();
726
+        $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
727
+    }
728
+
729
+    public function testSetValueFloatIsUpdated(): void {
730
+        $config = $this->generateAppConfig();
731
+        $config->setValueFloat('feed', 'float', 3.14);
732
+        $this->assertSame(true, $config->setValueFloat('feed', 'float', 1.23));
733
+    }
734
+
735
+    public function testSetValueFloatIsNotUpdated(): void {
736
+        $config = $this->generateAppConfig();
737
+        $config->setValueFloat('feed', 'float', 3.14);
738
+        $this->assertSame(false, $config->setValueFloat('feed', 'float', 3.14));
739
+    }
740
+
741
+    public function testSetValueFloatIsUpdatedCache(): void {
742
+        $config = $this->generateAppConfig();
743
+        $config->setValueFloat('feed', 'float', 3.14);
744
+        $config->setValueFloat('feed', 'float', 1.23);
745
+        $status = $config->statusCache();
746
+        $this->assertSame('1.23', $status['fastCache']['feed']['float']);
747
+    }
748
+
749
+    public function testSetValueFloatIsUpdatedDatabase(): void {
750
+        $config = $this->generateAppConfig();
751
+        $config->setValueFloat('feed', 'float', 3.14);
752
+        $config->setValueFloat('feed', 'float', 1.23);
753
+        $config->clearCache();
754
+        $this->assertSame(1.23, $config->getValueFloat('feed', 'float', 0));
755
+    }
756
+
757
+    public function testSetValueBool(): void {
758
+        $config = $this->generateAppConfig();
759
+        $config->setValueBool('feed', 'bool', true);
760
+        $this->assertSame(true, $config->getValueBool('feed', 'bool', false));
761
+    }
762
+
763
+    public function testSetValueBoolCache(): void {
764
+        $config = $this->generateAppConfig();
765
+        $config->setValueBool('feed', 'bool', true);
766
+        $status = $config->statusCache();
767
+        $this->assertSame('1', $status['fastCache']['feed']['bool']);
768
+    }
769
+
770
+    public function testSetValueBoolDatabase(): void {
771
+        $config = $this->generateAppConfig();
772
+        $config->setValueBool('feed', 'bool', true);
773
+        $config->clearCache();
774
+        $this->assertSame(true, $config->getValueBool('feed', 'bool', false));
775
+    }
776
+
777
+    public function testSetValueBoolIsUpdated(): void {
778
+        $config = $this->generateAppConfig();
779
+        $config->setValueBool('feed', 'bool', true);
780
+        $this->assertSame(true, $config->setValueBool('feed', 'bool', false));
781
+    }
782
+
783
+    public function testSetValueBoolIsNotUpdated(): void {
784
+        $config = $this->generateAppConfig();
785
+        $config->setValueBool('feed', 'bool', true);
786
+        $this->assertSame(false, $config->setValueBool('feed', 'bool', true));
787
+    }
788
+
789
+    public function testSetValueBoolIsUpdatedCache(): void {
790
+        $config = $this->generateAppConfig();
791
+        $config->setValueBool('feed', 'bool', true);
792
+        $config->setValueBool('feed', 'bool', false);
793
+        $status = $config->statusCache();
794
+        $this->assertSame('0', $status['fastCache']['feed']['bool']);
795
+    }
796
+
797
+    public function testSetValueBoolIsUpdatedDatabase(): void {
798
+        $config = $this->generateAppConfig();
799
+        $config->setValueBool('feed', 'bool', true);
800
+        $config->setValueBool('feed', 'bool', false);
801
+        $config->clearCache();
802
+        $this->assertSame(false, $config->getValueBool('feed', 'bool', true));
803
+    }
804
+
805
+
806
+    public function testSetValueArray(): void {
807
+        $config = $this->generateAppConfig();
808
+        $config->setValueArray('feed', 'array', ['test' => 1]);
809
+        $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
810
+    }
811
+
812
+    public function testSetValueArrayCache(): void {
813
+        $config = $this->generateAppConfig();
814
+        $config->setValueArray('feed', 'array', ['test' => 1]);
815
+        $status = $config->statusCache();
816
+        $this->assertSame('{"test":1}', $status['fastCache']['feed']['array']);
817
+    }
818
+
819
+    public function testSetValueArrayDatabase(): void {
820
+        $config = $this->generateAppConfig();
821
+        $config->setValueArray('feed', 'array', ['test' => 1]);
822
+        $config->clearCache();
823
+        $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
824
+    }
825
+
826
+    public function testSetValueArrayIsUpdated(): void {
827
+        $config = $this->generateAppConfig();
828
+        $config->setValueArray('feed', 'array', ['test' => 1]);
829
+        $this->assertSame(true, $config->setValueArray('feed', 'array', ['test' => 2]));
830
+    }
831
+
832
+    public function testSetValueArrayIsNotUpdated(): void {
833
+        $config = $this->generateAppConfig();
834
+        $config->setValueArray('feed', 'array', ['test' => 1]);
835
+        $this->assertSame(false, $config->setValueArray('feed', 'array', ['test' => 1]));
836
+    }
837
+
838
+    public function testSetValueArrayIsUpdatedCache(): void {
839
+        $config = $this->generateAppConfig();
840
+        $config->setValueArray('feed', 'array', ['test' => 1]);
841
+        $config->setValueArray('feed', 'array', ['test' => 2]);
842
+        $status = $config->statusCache();
843
+        $this->assertSame('{"test":2}', $status['fastCache']['feed']['array']);
844
+    }
845
+
846
+    public function testSetValueArrayIsUpdatedDatabase(): void {
847
+        $config = $this->generateAppConfig();
848
+        $config->setValueArray('feed', 'array', ['test' => 1]);
849
+        $config->setValueArray('feed', 'array', ['test' => 2]);
850
+        $config->clearCache();
851
+        $this->assertSame(['test' => 2], $config->getValueArray('feed', 'array', []));
852
+    }
853
+
854
+    public function testSetLazyValueString(): void {
855
+        $config = $this->generateAppConfig();
856
+        $config->setValueString('feed', 'string', 'value-1', true);
857
+        $this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
858
+    }
859
+
860
+    public function testSetLazyValueStringCache(): void {
861
+        $config = $this->generateAppConfig();
862
+        $config->setValueString('feed', 'string', 'value-1', true);
863
+        $status = $config->statusCache();
864
+        $this->assertSame('value-1', $status['lazyCache']['feed']['string']);
865
+    }
866
+
867
+    public function testSetLazyValueStringDatabase(): void {
868
+        $config = $this->generateAppConfig();
869
+        $config->setValueString('feed', 'string', 'value-1', true);
870
+        $config->clearCache();
871
+        $this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
872
+    }
873
+
874
+    public function testSetLazyValueStringAsNonLazy(): void {
875
+        $config = $this->generateAppConfig();
876
+        $config->setValueString('feed', 'string', 'value-1', true);
877
+        $config->setValueString('feed', 'string', 'value-1', false);
878
+        $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
879
+    }
880
+
881
+    public function testSetNonLazyValueStringAsLazy(): void {
882
+        $config = $this->generateAppConfig();
883
+        $config->setValueString('feed', 'string', 'value-1', false);
884
+        $config->setValueString('feed', 'string', 'value-1', true);
885
+        $this->assertSame('value-1', $config->getValueString('feed', 'string', '', true));
886
+    }
887
+
888
+    public function testSetSensitiveValueString(): void {
889
+        $config = $this->generateAppConfig();
890
+        $config->setValueString('feed', 'string', 'value-1', sensitive: true);
891
+        $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
892
+    }
893
+
894
+    public function testSetSensitiveValueStringCache(): void {
895
+        $config = $this->generateAppConfig();
896
+        $config->setValueString('feed', 'string', 'value-1', sensitive: true);
897
+        $status = $config->statusCache();
898
+        $this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['string']);
899
+    }
900
+
901
+    public function testSetSensitiveValueStringDatabase(): void {
902
+        $config = $this->generateAppConfig();
903
+        $config->setValueString('feed', 'string', 'value-1', sensitive: true);
904
+        $config->clearCache();
905
+        $this->assertSame('value-1', $config->getValueString('feed', 'string', ''));
906
+    }
907
+
908
+    public function testSetNonSensitiveValueStringAsSensitive(): void {
909
+        $config = $this->generateAppConfig();
910
+        $config->setValueString('feed', 'string', 'value-1', sensitive: false);
911
+        $config->setValueString('feed', 'string', 'value-1', sensitive: true);
912
+        $this->assertSame(true, $config->isSensitive('feed', 'string'));
913
+
914
+        $this->assertConfigValueNotEquals('feed', 'string', 'value-1');
915
+        $this->assertConfigValueNotEquals('feed', 'string', 'value-2');
916
+    }
917
+
918
+    public function testSetSensitiveValueStringAsNonSensitiveStaysSensitive(): void {
919
+        $config = $this->generateAppConfig();
920
+        $config->setValueString('feed', 'string', 'value-1', sensitive: true);
921
+        $config->setValueString('feed', 'string', 'value-2', sensitive: false);
922
+        $this->assertSame(true, $config->isSensitive('feed', 'string'));
923
+
924
+        $this->assertConfigValueNotEquals('feed', 'string', 'value-1');
925
+        $this->assertConfigValueNotEquals('feed', 'string', 'value-2');
926
+    }
927
+
928
+    public function testSetSensitiveValueStringAsNonSensitiveAreStillUpdated(): void {
929
+        $config = $this->generateAppConfig();
930
+        $config->setValueString('feed', 'string', 'value-1', sensitive: true);
931
+        $config->setValueString('feed', 'string', 'value-2', sensitive: false);
932
+        $this->assertSame('value-2', $config->getValueString('feed', 'string', ''));
933
+
934
+        $this->assertConfigValueNotEquals('feed', 'string', 'value-1');
935
+        $this->assertConfigValueNotEquals('feed', 'string', 'value-2');
936
+    }
937
+
938
+    public function testSetLazyValueInt(): void {
939
+        $config = $this->generateAppConfig();
940
+        $config->setValueInt('feed', 'int', 42, true);
941
+        $this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
942
+    }
943
+
944
+    public function testSetLazyValueIntCache(): void {
945
+        $config = $this->generateAppConfig();
946
+        $config->setValueInt('feed', 'int', 42, true);
947
+        $status = $config->statusCache();
948
+        $this->assertSame('42', $status['lazyCache']['feed']['int']);
949
+    }
950
+
951
+    public function testSetLazyValueIntDatabase(): void {
952
+        $config = $this->generateAppConfig();
953
+        $config->setValueInt('feed', 'int', 42, true);
954
+        $config->clearCache();
955
+        $this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
956
+    }
957
+
958
+    public function testSetLazyValueIntAsNonLazy(): void {
959
+        $config = $this->generateAppConfig();
960
+        $config->setValueInt('feed', 'int', 42, true);
961
+        $config->setValueInt('feed', 'int', 42, false);
962
+        $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
963
+    }
964
+
965
+    public function testSetNonLazyValueIntAsLazy(): void {
966
+        $config = $this->generateAppConfig();
967
+        $config->setValueInt('feed', 'int', 42, false);
968
+        $config->setValueInt('feed', 'int', 42, true);
969
+        $this->assertSame(42, $config->getValueInt('feed', 'int', 0, true));
970
+    }
971
+
972
+    public function testSetSensitiveValueInt(): void {
973
+        $config = $this->generateAppConfig();
974
+        $config->setValueInt('feed', 'int', 42, sensitive: true);
975
+        $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
976
+    }
977
+
978
+    public function testSetSensitiveValueIntCache(): void {
979
+        $config = $this->generateAppConfig();
980
+        $config->setValueInt('feed', 'int', 42, sensitive: true);
981
+        $status = $config->statusCache();
982
+        $this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['int']);
983
+    }
984
+
985
+    public function testSetSensitiveValueIntDatabase(): void {
986
+        $config = $this->generateAppConfig();
987
+        $config->setValueInt('feed', 'int', 42, sensitive: true);
988
+        $config->clearCache();
989
+        $this->assertSame(42, $config->getValueInt('feed', 'int', 0));
990
+    }
991
+
992
+    public function testSetNonSensitiveValueIntAsSensitive(): void {
993
+        $config = $this->generateAppConfig();
994
+        $config->setValueInt('feed', 'int', 42);
995
+        $config->setValueInt('feed', 'int', 42, sensitive: true);
996
+        $this->assertSame(true, $config->isSensitive('feed', 'int'));
997
+    }
998
+
999
+    public function testSetSensitiveValueIntAsNonSensitiveStaysSensitive(): void {
1000
+        $config = $this->generateAppConfig();
1001
+        $config->setValueInt('feed', 'int', 42, sensitive: true);
1002
+        $config->setValueInt('feed', 'int', 17);
1003
+        $this->assertSame(true, $config->isSensitive('feed', 'int'));
1004
+    }
1005
+
1006
+    public function testSetSensitiveValueIntAsNonSensitiveAreStillUpdated(): void {
1007
+        $config = $this->generateAppConfig();
1008
+        $config->setValueInt('feed', 'int', 42, sensitive: true);
1009
+        $config->setValueInt('feed', 'int', 17);
1010
+        $this->assertSame(17, $config->getValueInt('feed', 'int', 0));
1011
+    }
1012
+
1013
+    public function testSetLazyValueFloat(): void {
1014
+        $config = $this->generateAppConfig();
1015
+        $config->setValueFloat('feed', 'float', 3.14, true);
1016
+        $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
1017
+    }
1018
+
1019
+    public function testSetLazyValueFloatCache(): void {
1020
+        $config = $this->generateAppConfig();
1021
+        $config->setValueFloat('feed', 'float', 3.14, true);
1022
+        $status = $config->statusCache();
1023
+        $this->assertSame('3.14', $status['lazyCache']['feed']['float']);
1024
+    }
1025
+
1026
+    public function testSetLazyValueFloatDatabase(): void {
1027
+        $config = $this->generateAppConfig();
1028
+        $config->setValueFloat('feed', 'float', 3.14, true);
1029
+        $config->clearCache();
1030
+        $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
1031
+    }
1032
+
1033
+    public function testSetLazyValueFloatAsNonLazy(): void {
1034
+        $config = $this->generateAppConfig();
1035
+        $config->setValueFloat('feed', 'float', 3.14, true);
1036
+        $config->setValueFloat('feed', 'float', 3.14, false);
1037
+        $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
1038
+    }
1039
+
1040
+    public function testSetNonLazyValueFloatAsLazy(): void {
1041
+        $config = $this->generateAppConfig();
1042
+        $config->setValueFloat('feed', 'float', 3.14, false);
1043
+        $config->setValueFloat('feed', 'float', 3.14, true);
1044
+        $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0, true));
1045
+    }
1046
+
1047
+    public function testSetSensitiveValueFloat(): void {
1048
+        $config = $this->generateAppConfig();
1049
+        $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1050
+        $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
1051
+    }
1052
+
1053
+    public function testSetSensitiveValueFloatCache(): void {
1054
+        $config = $this->generateAppConfig();
1055
+        $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1056
+        $status = $config->statusCache();
1057
+        $this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['float']);
1058
+    }
1059
+
1060
+    public function testSetSensitiveValueFloatDatabase(): void {
1061
+        $config = $this->generateAppConfig();
1062
+        $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1063
+        $config->clearCache();
1064
+        $this->assertSame(3.14, $config->getValueFloat('feed', 'float', 0));
1065
+    }
1066
+
1067
+    public function testSetNonSensitiveValueFloatAsSensitive(): void {
1068
+        $config = $this->generateAppConfig();
1069
+        $config->setValueFloat('feed', 'float', 3.14);
1070
+        $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1071
+        $this->assertSame(true, $config->isSensitive('feed', 'float'));
1072
+    }
1073
+
1074
+    public function testSetSensitiveValueFloatAsNonSensitiveStaysSensitive(): void {
1075
+        $config = $this->generateAppConfig();
1076
+        $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1077
+        $config->setValueFloat('feed', 'float', 1.23);
1078
+        $this->assertSame(true, $config->isSensitive('feed', 'float'));
1079
+    }
1080
+
1081
+    public function testSetSensitiveValueFloatAsNonSensitiveAreStillUpdated(): void {
1082
+        $config = $this->generateAppConfig();
1083
+        $config->setValueFloat('feed', 'float', 3.14, sensitive: true);
1084
+        $config->setValueFloat('feed', 'float', 1.23);
1085
+        $this->assertSame(1.23, $config->getValueFloat('feed', 'float', 0));
1086
+    }
1087
+
1088
+    public function testSetLazyValueBool(): void {
1089
+        $config = $this->generateAppConfig();
1090
+        $config->setValueBool('feed', 'bool', true, true);
1091
+        $this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
1092
+    }
1093
+
1094
+    public function testSetLazyValueBoolCache(): void {
1095
+        $config = $this->generateAppConfig();
1096
+        $config->setValueBool('feed', 'bool', true, true);
1097
+        $status = $config->statusCache();
1098
+        $this->assertSame('1', $status['lazyCache']['feed']['bool']);
1099
+    }
1100
+
1101
+    public function testSetLazyValueBoolDatabase(): void {
1102
+        $config = $this->generateAppConfig();
1103
+        $config->setValueBool('feed', 'bool', true, true);
1104
+        $config->clearCache();
1105
+        $this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
1106
+    }
1107
+
1108
+    public function testSetLazyValueBoolAsNonLazy(): void {
1109
+        $config = $this->generateAppConfig();
1110
+        $config->setValueBool('feed', 'bool', true, true);
1111
+        $config->setValueBool('feed', 'bool', true, false);
1112
+        $this->assertSame(true, $config->getValueBool('feed', 'bool', false));
1113
+    }
1114
+
1115
+    public function testSetNonLazyValueBoolAsLazy(): void {
1116
+        $config = $this->generateAppConfig();
1117
+        $config->setValueBool('feed', 'bool', true, false);
1118
+        $config->setValueBool('feed', 'bool', true, true);
1119
+        $this->assertSame(true, $config->getValueBool('feed', 'bool', false, true));
1120
+    }
1121
+
1122
+    public function testSetLazyValueArray(): void {
1123
+        $config = $this->generateAppConfig();
1124
+        $config->setValueArray('feed', 'array', ['test' => 1], true);
1125
+        $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
1126
+    }
1127
+
1128
+    public function testSetLazyValueArrayCache(): void {
1129
+        $config = $this->generateAppConfig();
1130
+        $config->setValueArray('feed', 'array', ['test' => 1], true);
1131
+        $status = $config->statusCache();
1132
+        $this->assertSame('{"test":1}', $status['lazyCache']['feed']['array']);
1133
+    }
1134
+
1135
+    public function testSetLazyValueArrayDatabase(): void {
1136
+        $config = $this->generateAppConfig();
1137
+        $config->setValueArray('feed', 'array', ['test' => 1], true);
1138
+        $config->clearCache();
1139
+        $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
1140
+    }
1141
+
1142
+    public function testSetLazyValueArrayAsNonLazy(): void {
1143
+        $config = $this->generateAppConfig();
1144
+        $config->setValueArray('feed', 'array', ['test' => 1], true);
1145
+        $config->setValueArray('feed', 'array', ['test' => 1], false);
1146
+        $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', []));
1147
+    }
1148
+
1149
+    public function testSetNonLazyValueArrayAsLazy(): void {
1150
+        $config = $this->generateAppConfig();
1151
+        $config->setValueArray('feed', 'array', ['test' => 1], false);
1152
+        $config->setValueArray('feed', 'array', ['test' => 1], true);
1153
+        $this->assertSame(['test' => 1], $config->getValueArray('feed', 'array', [], true));
1154
+    }
1155
+
1156
+
1157
+    public function testSetSensitiveValueArray(): void {
1158
+        $config = $this->generateAppConfig();
1159
+        $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1160
+        $this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('feed', 'array', []));
1161
+    }
1162
+
1163
+    public function testSetSensitiveValueArrayCache(): void {
1164
+        $config = $this->generateAppConfig();
1165
+        $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1166
+        $status = $config->statusCache();
1167
+        $this->assertStringStartsWith(self::invokePrivate(AppConfig::class, 'ENCRYPTION_PREFIX'), $status['fastCache']['feed']['array']);
1168
+    }
1169
+
1170
+    public function testSetSensitiveValueArrayDatabase(): void {
1171
+        $config = $this->generateAppConfig();
1172
+        $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1173
+        $config->clearCache();
1174
+        $this->assertEqualsCanonicalizing(['test' => 1], $config->getValueArray('feed', 'array', []));
1175
+    }
1176
+
1177
+    public function testSetNonSensitiveValueArrayAsSensitive(): void {
1178
+        $config = $this->generateAppConfig();
1179
+        $config->setValueArray('feed', 'array', ['test' => 1]);
1180
+        $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1181
+        $this->assertSame(true, $config->isSensitive('feed', 'array'));
1182
+    }
1183
+
1184
+    public function testSetSensitiveValueArrayAsNonSensitiveStaysSensitive(): void {
1185
+        $config = $this->generateAppConfig();
1186
+        $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1187
+        $config->setValueArray('feed', 'array', ['test' => 2]);
1188
+        $this->assertSame(true, $config->isSensitive('feed', 'array'));
1189
+    }
1190
+
1191
+    public function testSetSensitiveValueArrayAsNonSensitiveAreStillUpdated(): void {
1192
+        $config = $this->generateAppConfig();
1193
+        $config->setValueArray('feed', 'array', ['test' => 1], sensitive: true);
1194
+        $config->setValueArray('feed', 'array', ['test' => 2]);
1195
+        $this->assertEqualsCanonicalizing(['test' => 2], $config->getValueArray('feed', 'array', []));
1196
+    }
1197
+
1198
+    public function testUpdateNotSensitiveToSensitive(): void {
1199
+        $config = $this->generateAppConfig();
1200
+        $config->updateSensitive('non-sensitive-app', 'lazy-key', true);
1201
+        $this->assertSame(true, $config->isSensitive('non-sensitive-app', 'lazy-key', true));
1202
+    }
1203
+
1204
+    public function testUpdateSensitiveToNotSensitive(): void {
1205
+        $config = $this->generateAppConfig();
1206
+        $config->updateSensitive('sensitive-app', 'lazy-key', false);
1207
+        $this->assertSame(false, $config->isSensitive('sensitive-app', 'lazy-key', true));
1208
+    }
1209
+
1210
+    public function testUpdateSensitiveToSensitiveReturnsFalse(): void {
1211
+        $config = $this->generateAppConfig();
1212
+        $this->assertSame(false, $config->updateSensitive('sensitive-app', 'lazy-key', true));
1213
+    }
1214
+
1215
+    public function testUpdateNotSensitiveToNotSensitiveReturnsFalse(): void {
1216
+        $config = $this->generateAppConfig();
1217
+        $this->assertSame(false, $config->updateSensitive('non-sensitive-app', 'lazy-key', false));
1218
+    }
1219
+
1220
+    public function testUpdateSensitiveOnUnknownKeyReturnsFalse(): void {
1221
+        $config = $this->generateAppConfig();
1222
+        $this->assertSame(false, $config->updateSensitive('non-sensitive-app', 'unknown-key', true));
1223
+    }
1224
+
1225
+    public function testUpdateNotLazyToLazy(): void {
1226
+        $config = $this->generateAppConfig();
1227
+        $config->updateLazy('non-sensitive-app', 'non-lazy-key', true);
1228
+        $this->assertSame(true, $config->isLazy('non-sensitive-app', 'non-lazy-key'));
1229
+    }
1230
+
1231
+    public function testUpdateLazyToNotLazy(): void {
1232
+        $config = $this->generateAppConfig();
1233
+        $config->updateLazy('non-sensitive-app', 'lazy-key', false);
1234
+        $this->assertSame(false, $config->isLazy('non-sensitive-app', 'lazy-key'));
1235
+    }
1236
+
1237
+    public function testUpdateLazyToLazyReturnsFalse(): void {
1238
+        $config = $this->generateAppConfig();
1239
+        $this->assertSame(false, $config->updateLazy('non-sensitive-app', 'lazy-key', true));
1240
+    }
1241
+
1242
+    public function testUpdateNotLazyToNotLazyReturnsFalse(): void {
1243
+        $config = $this->generateAppConfig();
1244
+        $this->assertSame(false, $config->updateLazy('non-sensitive-app', 'non-lazy-key', false));
1245
+    }
1246
+
1247
+    public function testUpdateLazyOnUnknownKeyReturnsFalse(): void {
1248
+        $config = $this->generateAppConfig();
1249
+        $this->assertSame(false, $config->updateLazy('non-sensitive-app', 'unknown-key', true));
1250
+    }
1251
+
1252
+    public function testGetDetails(): void {
1253
+        $config = $this->generateAppConfig();
1254
+        $this->assertEquals(
1255
+            [
1256
+                'app' => 'non-sensitive-app',
1257
+                'key' => 'lazy-key',
1258
+                'value' => 'value',
1259
+                'type' => 4,
1260
+                'lazy' => true,
1261
+                'typeString' => 'string',
1262
+                'sensitive' => false,
1263
+            ],
1264
+            $config->getDetails('non-sensitive-app', 'lazy-key')
1265
+        );
1266
+    }
1267
+
1268
+    public function testGetDetailsSensitive(): void {
1269
+        $config = $this->generateAppConfig();
1270
+        $this->assertEquals(
1271
+            [
1272
+                'app' => 'sensitive-app',
1273
+                'key' => 'lazy-key',
1274
+                'value' => 'value',
1275
+                'type' => 4,
1276
+                'lazy' => true,
1277
+                'typeString' => 'string',
1278
+                'sensitive' => true,
1279
+            ],
1280
+            $config->getDetails('sensitive-app', 'lazy-key')
1281
+        );
1282
+    }
1283
+
1284
+    public function testGetDetailsInt(): void {
1285
+        $config = $this->generateAppConfig();
1286
+        $this->assertEquals(
1287
+            [
1288
+                'app' => 'typed',
1289
+                'key' => 'int',
1290
+                'value' => '42',
1291
+                'type' => 8,
1292
+                'lazy' => false,
1293
+                'typeString' => 'integer',
1294
+                'sensitive' => false
1295
+            ],
1296
+            $config->getDetails('typed', 'int')
1297
+        );
1298
+    }
1299
+
1300
+    public function testGetDetailsFloat(): void {
1301
+        $config = $this->generateAppConfig();
1302
+        $this->assertEquals(
1303
+            [
1304
+                'app' => 'typed',
1305
+                'key' => 'float',
1306
+                'value' => '3.14',
1307
+                'type' => 16,
1308
+                'lazy' => false,
1309
+                'typeString' => 'float',
1310
+                'sensitive' => false
1311
+            ],
1312
+            $config->getDetails('typed', 'float')
1313
+        );
1314
+    }
1315
+
1316
+    public function testGetDetailsBool(): void {
1317
+        $config = $this->generateAppConfig();
1318
+        $this->assertEquals(
1319
+            [
1320
+                'app' => 'typed',
1321
+                'key' => 'bool',
1322
+                'value' => '1',
1323
+                'type' => 32,
1324
+                'lazy' => false,
1325
+                'typeString' => 'boolean',
1326
+                'sensitive' => false
1327
+            ],
1328
+            $config->getDetails('typed', 'bool')
1329
+        );
1330
+    }
1331
+
1332
+    public function testGetDetailsArray(): void {
1333
+        $config = $this->generateAppConfig();
1334
+        $this->assertEquals(
1335
+            [
1336
+                'app' => 'typed',
1337
+                'key' => 'array',
1338
+                'value' => '{"test": 1}',
1339
+                'type' => 64,
1340
+                'lazy' => false,
1341
+                'typeString' => 'array',
1342
+                'sensitive' => false
1343
+            ],
1344
+            $config->getDetails('typed', 'array')
1345
+        );
1346
+    }
1347
+
1348
+    public function testDeleteKey(): void {
1349
+        $config = $this->generateAppConfig();
1350
+        $config->deleteKey('anotherapp', 'key');
1351
+        $this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
1352
+    }
1353
+
1354
+    public function testDeleteKeyCache(): void {
1355
+        $config = $this->generateAppConfig();
1356
+        $config->deleteKey('anotherapp', 'key');
1357
+        $status = $config->statusCache();
1358
+        $this->assertEqualsCanonicalizing(['enabled' => 'no', 'installed_version' => '3.2.1'], $status['fastCache']['anotherapp']);
1359
+    }
1360
+
1361
+    public function testDeleteKeyDatabase(): void {
1362
+        $config = $this->generateAppConfig();
1363
+        $config->deleteKey('anotherapp', 'key');
1364
+        $config->clearCache();
1365
+        $this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
1366
+    }
1367
+
1368
+    public function testDeleteApp(): void {
1369
+        $config = $this->generateAppConfig();
1370
+        $config->deleteApp('anotherapp');
1371
+        $this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
1372
+        $this->assertSame('default', $config->getValueString('anotherapp', 'enabled', 'default'));
1373
+    }
1374
+
1375
+    public function testDeleteAppCache(): void {
1376
+        $config = $this->generateAppConfig();
1377
+        $status = $config->statusCache();
1378
+        $this->assertSame(true, isset($status['fastCache']['anotherapp']));
1379
+        $config->deleteApp('anotherapp');
1380
+        $status = $config->statusCache();
1381
+        $this->assertSame(false, isset($status['fastCache']['anotherapp']));
1382
+    }
1383
+
1384
+    public function testDeleteAppDatabase(): void {
1385
+        $config = $this->generateAppConfig();
1386
+        $config->deleteApp('anotherapp');
1387
+        $config->clearCache();
1388
+        $this->assertSame('default', $config->getValueString('anotherapp', 'key', 'default'));
1389
+        $this->assertSame('default', $config->getValueString('anotherapp', 'enabled', 'default'));
1390
+    }
1391
+
1392
+    public function testClearCache(): void {
1393
+        $config = $this->generateAppConfig();
1394
+        $config->setValueString('feed', 'string', '123454');
1395
+        $config->clearCache();
1396
+        $status = $config->statusCache();
1397
+        $this->assertSame([], $status['fastCache']);
1398
+    }
1399
+
1400
+    public function testSensitiveValuesAreEncrypted(): void {
1401
+        $key = self::getUniqueID('secret');
1402
+
1403
+        $appConfig = $this->generateAppConfig();
1404
+        $secret = md5((string)time());
1405
+        $appConfig->setValueString('testapp', $key, $secret, sensitive: true);
1406
+
1407
+        $this->assertConfigValueNotEquals('testapp', $key, $secret);
1408
+
1409
+        // Can get in same run
1410
+        $actualSecret = $appConfig->getValueString('testapp', $key);
1411
+        $this->assertEquals($secret, $actualSecret);
1412
+
1413
+        // Can get freshly decrypted from DB
1414
+        $newAppConfig = $this->generateAppConfig();
1415
+        $actualSecret = $newAppConfig->getValueString('testapp', $key);
1416
+        $this->assertEquals($secret, $actualSecret);
1417
+    }
1418
+
1419
+    public function testMigratingNonSensitiveValueToSensitiveWithSetValue(): void {
1420
+        $key = self::getUniqueID('secret');
1421
+        $appConfig = $this->generateAppConfig();
1422
+        $secret = sha1((string)time());
1423
+
1424
+        // Unencrypted
1425
+        $appConfig->setValueString('testapp', $key, $secret);
1426
+        $this->assertConfigKey('testapp', $key, $secret);
1427
+
1428
+        // Can get freshly decrypted from DB
1429
+        $newAppConfig = $this->generateAppConfig();
1430
+        $actualSecret = $newAppConfig->getValueString('testapp', $key);
1431
+        $this->assertEquals($secret, $actualSecret);
1432
+
1433
+        // Encrypting on change
1434
+        $appConfig->setValueString('testapp', $key, $secret, sensitive: true);
1435
+        $this->assertConfigValueNotEquals('testapp', $key, $secret);
1436
+
1437
+        // Can get in same run
1438
+        $actualSecret = $appConfig->getValueString('testapp', $key);
1439
+        $this->assertEquals($secret, $actualSecret);
1440
+
1441
+        // Can get freshly decrypted from DB
1442
+        $newAppConfig = $this->generateAppConfig();
1443
+        $actualSecret = $newAppConfig->getValueString('testapp', $key);
1444
+        $this->assertEquals($secret, $actualSecret);
1445
+    }
1446
+
1447
+    public function testUpdateSensitiveValueToNonSensitiveWithUpdateSensitive(): void {
1448
+        $key = self::getUniqueID('secret');
1449
+        $appConfig = $this->generateAppConfig();
1450
+        $secret = sha1((string)time());
1451
+
1452
+        // Encrypted
1453
+        $appConfig->setValueString('testapp', $key, $secret, sensitive: true);
1454
+        $this->assertConfigValueNotEquals('testapp', $key, $secret);
1455
+
1456
+        // Migrate to non-sensitive / non-encrypted
1457
+        $appConfig->updateSensitive('testapp', $key, false);
1458
+        $this->assertConfigKey('testapp', $key, $secret);
1459
+    }
1460
+
1461
+    public function testUpdateNonSensitiveValueToSensitiveWithUpdateSensitive(): void {
1462
+        $key = self::getUniqueID('secret');
1463
+        $appConfig = $this->generateAppConfig();
1464
+        $secret = sha1((string)time());
1465
+
1466
+        // Unencrypted
1467
+        $appConfig->setValueString('testapp', $key, $secret);
1468
+        $this->assertConfigKey('testapp', $key, $secret);
1469
+
1470
+        // Migrate to sensitive / encrypted
1471
+        $appConfig->updateSensitive('testapp', $key, true);
1472
+        $this->assertConfigValueNotEquals('testapp', $key, $secret);
1473
+    }
1474
+
1475
+    public function testSearchKeyNoLazyLoading(): void {
1476
+        $appConfig = $this->generateAppConfig();
1477
+        $appConfig->searchKeys('searchtest', 'search_');
1478
+        $status = $appConfig->statusCache();
1479
+        $this->assertFalse($status['lazyLoaded'], 'searchKeys() loaded lazy config');
1480
+    }
1481
+
1482
+    public function testSearchKeyFast(): void {
1483
+        $appConfig = $this->generateAppConfig();
1484
+        $this->assertEquals(['search_key1', 'search_key2', 'search_key3'], $appConfig->searchKeys('searchtest', 'search_'));
1485
+    }
1486
+
1487
+    public function testSearchKeyLazy(): void {
1488
+        $appConfig = $this->generateAppConfig();
1489
+        $this->assertEquals(['search_key5_lazy'], $appConfig->searchKeys('searchtest', 'search_', true));
1490
+    }
1491
+
1492
+    protected function loadConfigValueFromDatabase(string $app, string $key): string|false {
1493
+        $sql = $this->connection->getQueryBuilder();
1494
+        $sql->select('configvalue')
1495
+            ->from('appconfig')
1496
+            ->where($sql->expr()->eq('appid', $sql->createParameter('appid')))
1497
+            ->andWhere($sql->expr()->eq('configkey', $sql->createParameter('configkey')))
1498
+            ->setParameter('appid', $app)
1499
+            ->setParameter('configkey', $key);
1500
+        $query = $sql->executeQuery();
1501
+        $actual = $query->fetchOne();
1502
+        $query->closeCursor();
1503
+
1504
+        return $actual;
1505
+    }
1506
+
1507
+    protected function assertConfigKey(string $app, string $key, string|false $expected): void {
1508
+        $this->assertEquals($expected, $this->loadConfigValueFromDatabase($app, $key));
1509
+    }
1510
+
1511
+    protected function assertConfigValueNotEquals(string $app, string $key, string|false $expected): void {
1512
+        $this->assertNotEquals($expected, $this->loadConfigValueFromDatabase($app, $key));
1513
+    }
1514 1514
 }
Please login to merge, or discard this patch.
tests/lib/Config/UserConfigTest.php 1 patch
Indentation   +1764 added lines, -1764 removed lines patch added patch discarded remove patch
@@ -30,1768 +30,1768 @@
 block discarded – undo
30 30
  */
31 31
 #[\PHPUnit\Framework\Attributes\Group('DB')]
32 32
 class UserConfigTest extends TestCase {
33
-	protected IDBConnection $connection;
34
-	private IConfig $config;
35
-	private ConfigManager $configManager;
36
-	private PresetManager $presetManager;
37
-	private LoggerInterface $logger;
38
-	private ICrypto $crypto;
39
-	private IEventDispatcher $dispatcher;
40
-	private array $originalPreferences;
41
-
42
-	/**
43
-	 * @var array<string, array<string, array<array<string, string, int, bool, bool>>> [userId => [appId => prefKey, prefValue, valueType, lazy, sensitive]]]
44
-	 */
45
-	private array $basePreferences
46
-		= [
47
-			'user1'
48
-				=> [
49
-					'app1' => [
50
-						'key1' => ['key1', 'value1'],
51
-						'key22' => ['key22', '31'],
52
-						'fast_string' => ['fast_string', 'f_value', ValueType::STRING],
53
-						'lazy_string' => ['lazy_string', 'l_value', ValueType::STRING, true],
54
-						'fast_string_sensitive' => [
55
-							'fast_string_sensitive', 'fs_value', ValueType::STRING, false, UserConfig::FLAG_SENSITIVE
56
-						],
57
-						'lazy_string_sensitive' => [
58
-							'lazy_string_sensitive', 'ls_value', ValueType::STRING, true, UserConfig::FLAG_SENSITIVE
59
-						],
60
-						'fast_int' => ['fast_int', 11, ValueType::INT],
61
-						'lazy_int' => ['lazy_int', 12, ValueType::INT, true],
62
-						'fast_int_sensitive' => ['fast_int_sensitive', 2024, ValueType::INT, false, UserConfig::FLAG_SENSITIVE],
63
-						'lazy_int_sensitive' => ['lazy_int_sensitive', 2048, ValueType::INT, true, UserConfig::FLAG_SENSITIVE],
64
-						'fast_float' => ['fast_float', 3.14, ValueType::FLOAT],
65
-						'lazy_float' => ['lazy_float', 3.14159, ValueType::FLOAT, true],
66
-						'fast_float_sensitive' => [
67
-							'fast_float_sensitive', 1.41, ValueType::FLOAT, false, UserConfig::FLAG_SENSITIVE
68
-						],
69
-						'lazy_float_sensitive' => [
70
-							'lazy_float_sensitive', 1.4142, ValueType::FLOAT, true, UserConfig::FLAG_SENSITIVE
71
-						],
72
-						'fast_array' => ['fast_array', ['year' => 2024], ValueType::ARRAY],
73
-						'lazy_array' => ['lazy_array', ['month' => 'October'], ValueType::ARRAY, true],
74
-						'fast_array_sensitive' => [
75
-							'fast_array_sensitive', ['password' => 'pwd'], ValueType::ARRAY, false, UserConfig::FLAG_SENSITIVE
76
-						],
77
-						'lazy_array_sensitive' => [
78
-							'lazy_array_sensitive', ['password' => 'qwerty'], ValueType::ARRAY, true, UserConfig::FLAG_SENSITIVE
79
-						],
80
-						'fast_boolean' => ['fast_boolean', true, ValueType::BOOL],
81
-						'fast_boolean_0' => ['fast_boolean_0', false, ValueType::BOOL],
82
-						'lazy_boolean' => ['lazy_boolean', true, ValueType::BOOL, true],
83
-						'lazy_boolean_0' => ['lazy_boolean_0', false, ValueType::BOOL, true],
84
-					],
85
-					'app2' => [
86
-						'key2' => ['key2', 'value2a', ValueType::STRING, false, 0, true],
87
-						'key3' => ['key3', 'value3', ValueType::STRING, true],
88
-						'key4' => ['key4', 'value4', ValueType::STRING, false, UserConfig::FLAG_SENSITIVE],
89
-						'key8' => ['key8', 11, ValueType::INT, false, 0, true],
90
-						'key9' => ['key9', 'value9a', ValueType::STRING],
91
-					],
92
-					'app3' => [
93
-						'key1' => ['key1', 'value123'],
94
-						'key3' => ['key3', 'value3'],
95
-						'key8' => ['key8', 12, ValueType::INT, false, UserConfig::FLAG_SENSITIVE, true],
96
-						'key9' => ['key9', 'value9b', ValueType::STRING, false, UserConfig::FLAG_SENSITIVE],
97
-						'key10' => ['key10', true, ValueType::BOOL, false, 0, true],
98
-					],
99
-					'only-lazy' => [
100
-						'key1' => ['key1', 'value456', ValueType::STRING, true, 0, true],
101
-						'key2' => ['key2', 'value2c', ValueType::STRING, true, UserConfig::FLAG_SENSITIVE],
102
-						'key3' => ['key3', 42, ValueType::INT, true],
103
-						'key4' => ['key4', 17.42, ValueType::FLOAT, true],
104
-						'key5' => ['key5', true, ValueType::BOOL, true],
105
-					]
106
-				],
107
-			'user2'
108
-				=> [
109
-					'app1' => [
110
-						'1' => ['1', 'value1'],
111
-						'2' => ['2', 'value2', ValueType::STRING, true, UserConfig::FLAG_SENSITIVE],
112
-						'3' => ['3', 17, ValueType::INT, true],
113
-						'4' => ['4', 42, ValueType::INT, false, UserConfig::FLAG_SENSITIVE],
114
-						'5' => ['5', 17.42, ValueType::FLOAT, false],
115
-						'6' => ['6', true, ValueType::BOOL, false],
116
-					],
117
-					'app2' => [
118
-						'key2' => ['key2', 'value2b', ValueType::STRING, false, 0, true],
119
-						'key3' => ['key3', 'value3', ValueType::STRING, true],
120
-						'key4' => ['key4', 'value4', ValueType::STRING, false, UserConfig::FLAG_SENSITIVE],
121
-						'key8' => ['key8', 12, ValueType::INT, false, 0, true],
122
-					],
123
-					'app3' => [
124
-						'key10' => ['key10', false, ValueType::BOOL, false, 0, true],
125
-					],
126
-					'only-lazy' => [
127
-						'key1' => ['key1', 'value1', ValueType::STRING, true, 0, true]
128
-					]
129
-				],
130
-			'user3'
131
-				=> [
132
-					'app2' => [
133
-						'key2' => ['key2', 'value2c', ValueType::MIXED, false, 0, true],
134
-						'key3' => ['key3', 'value3', ValueType::STRING, true, ],
135
-						'key4' => ['key4', 'value4', ValueType::STRING, false, UserConfig::FLAG_SENSITIVE],
136
-						'fast_string_sensitive' => [
137
-							'fast_string_sensitive', 'fs_value', ValueType::STRING, false, UserConfig::FLAG_SENSITIVE
138
-						],
139
-						'lazy_string_sensitive' => [
140
-							'lazy_string_sensitive', 'ls_value', ValueType::STRING, true, UserConfig::FLAG_SENSITIVE
141
-						],
142
-					],
143
-					'only-lazy' => [
144
-						'key3' => ['key3', 'value3', ValueType::STRING, true]
145
-					]
146
-				],
147
-			'user4'
148
-				=> [
149
-					'app2' => [
150
-						'key1' => ['key1', 'value1'],
151
-						'key2' => ['key2', 'value2A', ValueType::MIXED, false, 0, true],
152
-						'key3' => ['key3', 'value3', ValueType::STRING, true,],
153
-						'key4' => ['key4', 'value4', ValueType::STRING, false, UserConfig::FLAG_SENSITIVE],
154
-					],
155
-					'app3' => [
156
-						'key10' => ['key10', true, ValueType::BOOL, false, 0, true],
157
-					],
158
-					'only-lazy' => [
159
-						'key1' => ['key1', 123, ValueType::INT, true, 0, true]
160
-					]
161
-				],
162
-			'user5'
163
-				=> [
164
-					'app1' => [
165
-						'key1' => ['key1', 'value1']
166
-					],
167
-					'app2' => [
168
-						'key8' => ['key8', 12, ValueType::INT, false, 0, true]
169
-					],
170
-					'only-lazy' => [
171
-						'key1' => ['key1', 'value1', ValueType::STRING, true, 0, true]
172
-					]
173
-				],
174
-
175
-		];
176
-
177
-	protected function setUp(): void {
178
-		parent::setUp();
179
-
180
-		$this->connection = Server::get(IDBConnection::class);
181
-		$this->config = Server::get(IConfig::class);
182
-		$this->configManager = Server::get(ConfigManager::class);
183
-		$this->presetManager = Server::get(PresetManager::class);
184
-		$this->logger = Server::get(LoggerInterface::class);
185
-		$this->crypto = Server::get(ICrypto::class);
186
-		$this->dispatcher = Server::get(IEventDispatcher::class);
187
-
188
-		// storing current preferences and emptying the data table
189
-		$sql = $this->connection->getQueryBuilder();
190
-		$sql->select('*')
191
-			->from('preferences');
192
-		$result = $sql->executeQuery();
193
-		$this->originalPreferences = $result->fetchAllAssociative();
194
-		$result->closeCursor();
195
-
196
-		$sql = $this->connection->getQueryBuilder();
197
-		$sql->delete('preferences');
198
-		$sql->executeStatement();
199
-
200
-		$sql = $this->connection->getQueryBuilder();
201
-		$sql->insert('preferences')
202
-			->values(
203
-				[
204
-					'userid' => $sql->createParameter('userid'),
205
-					'appid' => $sql->createParameter('appid'),
206
-					'configkey' => $sql->createParameter('configkey'),
207
-					'configvalue' => $sql->createParameter('configvalue'),
208
-					'type' => $sql->createParameter('type'),
209
-					'lazy' => $sql->createParameter('lazy'),
210
-					'flags' => $sql->createParameter('flags'),
211
-					'indexed' => $sql->createParameter('indexed')
212
-				]
213
-			);
214
-
215
-		foreach ($this->basePreferences as $userId => $userData) {
216
-			foreach ($userData as $appId => $appData) {
217
-				foreach ($appData as $key => $row) {
218
-					$value = $row[1];
219
-					$type = ($row[2] ?? ValueType::MIXED)->value;
220
-
221
-					if ($type === ValueType::ARRAY->value) {
222
-						$value = json_encode($value);
223
-					}
224
-
225
-					if ($type === ValueType::BOOL->value && $value === false) {
226
-						$value = '0';
227
-					}
228
-
229
-					$flags = $row[4] ?? 0;
230
-					if ((UserConfig::FLAG_SENSITIVE & $flags) !== 0) {
231
-						$value = self::invokePrivate(UserConfig::class, 'ENCRYPTION_PREFIX')
232
-								 . $this->crypto->encrypt((string)$value);
233
-					} else {
234
-						$indexed = (($row[5] ?? false) === true) ? $value : '';
235
-					}
236
-
237
-					$sql->setParameters(
238
-						[
239
-							'userid' => $userId,
240
-							'appid' => $appId,
241
-							'configkey' => $row[0],
242
-							'configvalue' => $value,
243
-							'type' => $type,
244
-							'lazy' => (($row[3] ?? false) === true) ? 1 : 0,
245
-							'flags' => $flags,
246
-							'indexed' => $indexed ?? ''
247
-						]
248
-					)->executeStatement();
249
-				}
250
-			}
251
-		}
252
-	}
253
-
254
-	protected function tearDown(): void {
255
-		$sql = $this->connection->getQueryBuilder();
256
-		$sql->delete('preferences');
257
-		$sql->executeStatement();
258
-
259
-		$sql = $this->connection->getQueryBuilder();
260
-		$sql->insert('preferences')
261
-			->values(
262
-				[
263
-					'userid' => $sql->createParameter('userid'),
264
-					'appid' => $sql->createParameter('appid'),
265
-					'configkey' => $sql->createParameter('configkey'),
266
-					'configvalue' => $sql->createParameter('configvalue'),
267
-					'lazy' => $sql->createParameter('lazy'),
268
-					'type' => $sql->createParameter('type'),
269
-				]
270
-			);
271
-
272
-		foreach ($this->originalPreferences as $key => $configs) {
273
-			$sql->setParameter('userid', $configs['userid'])
274
-				->setParameter('appid', $configs['appid'])
275
-				->setParameter('configkey', $configs['configkey'])
276
-				->setParameter('configvalue', $configs['configvalue'])
277
-				->setParameter('lazy', ($configs['lazy'] === '1') ? '1' : '0')
278
-				->setParameter('type', $configs['type']);
279
-			$sql->executeStatement();
280
-		}
281
-
282
-		parent::tearDown();
283
-	}
284
-
285
-	/**
286
-	 * @param array $preLoading preload the 'fast' cache for a list of users)
287
-	 *
288
-	 * @return IUserConfig
289
-	 */
290
-	private function generateUserConfig(array $preLoading = []): IUserConfig {
291
-		$userConfig = new UserConfig(
292
-			$this->connection,
293
-			$this->config,
294
-			$this->configManager,
295
-			$this->presetManager,
296
-			$this->logger,
297
-			$this->crypto,
298
-			$this->dispatcher
299
-		);
300
-		$msg = ' generateUserConfig() failed to confirm cache status';
301
-
302
-		// confirm cache status
303
-		$status = $userConfig->statusCache();
304
-		$this->assertSame([], $status['fastLoaded'], $msg);
305
-		$this->assertSame([], $status['lazyLoaded'], $msg);
306
-		$this->assertSame([], $status['fastCache'], $msg);
307
-		$this->assertSame([], $status['lazyCache'], $msg);
308
-		foreach ($preLoading as $preLoadUser) {
309
-			// simple way to initiate the load of non-lazy preferences values in cache
310
-			$userConfig->getValueString($preLoadUser, 'core', 'preload');
311
-
312
-			// confirm cache status
313
-			$status = $userConfig->statusCache();
314
-			$this->assertSame(true, $status['fastLoaded'][$preLoadUser], $msg);
315
-			$this->assertSame(false, $status['lazyLoaded'][$preLoadUser], $msg);
316
-
317
-			$apps = array_values(array_diff(array_keys($this->basePreferences[$preLoadUser]), ['only-lazy']));
318
-			$this->assertEqualsCanonicalizing($apps, array_keys($status['fastCache'][$preLoadUser]), $msg);
319
-			$this->assertSame([], array_keys($status['lazyCache'][$preLoadUser]), $msg);
320
-		}
321
-
322
-		return $userConfig;
323
-	}
324
-
325
-	public function testGetUserIdsEmpty(): void {
326
-		$userConfig = $this->generateUserConfig();
327
-		$this->assertEqualsCanonicalizing(array_keys($this->basePreferences), $userConfig->getUserIds());
328
-	}
329
-
330
-	public function testGetUserIds(): void {
331
-		$userConfig = $this->generateUserConfig();
332
-		$this->assertEqualsCanonicalizing(['user1', 'user2', 'user5'], $userConfig->getUserIds('app1'));
333
-	}
334
-
335
-	public function testGetApps(): void {
336
-		$userConfig = $this->generateUserConfig();
337
-		$this->assertEqualsCanonicalizing(
338
-			array_keys($this->basePreferences['user1']), $userConfig->getApps('user1')
339
-		);
340
-	}
341
-
342
-	public function testGetKeys(): void {
343
-		$userConfig = $this->generateUserConfig(['user1']);
344
-		$this->assertEqualsCanonicalizing(
345
-			array_keys($this->basePreferences['user1']['app1']), $userConfig->getKeys('user1', 'app1')
346
-		);
347
-	}
348
-
349
-	public static function providerHasKey(): array {
350
-		return [
351
-			['user1', 'app1', 'key1', false, true],
352
-			['user0', 'app1', 'key1', false, false],
353
-			['user1', 'app1', 'key1', true, false],
354
-			['user1', 'app1', 'key0', false, false],
355
-			['user1', 'app1', 'key0', true, false],
356
-			['user1', 'app1', 'fast_string_sensitive', false, true],
357
-			['user1', 'app1', 'lazy_string_sensitive', true, true],
358
-			['user2', 'only-lazy', 'key1', false, false],
359
-			['user2', 'only-lazy', 'key1', true, true],
360
-		];
361
-	}
362
-
363
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerHasKey')]
364
-	public function testHasKey(string $userId, string $appId, string $key, ?bool $lazy, bool $result): void {
365
-		$userConfig = $this->generateUserConfig();
366
-		$this->assertEquals($result, $userConfig->hasKey($userId, $appId, $key, $lazy));
367
-	}
368
-
369
-	public static function providerIsSensitive(): array {
370
-		return [
371
-			['user1', 'app1', 'key1', false, false, false],
372
-			['user0', 'app1', 'key1', false, false, true],
373
-			['user1', 'app1', 'key1', true, false, true],
374
-			['user1', 'app1', 'key1', null, false, false],
375
-			['user1', 'app1', 'key0', false, false, true],
376
-			['user1', 'app1', 'key0', true, false, true],
377
-			['user1', 'app1', 'fast_string_sensitive', false, true, false],
378
-			['user1', 'app1', 'lazy_string_sensitive', true, true, false],
379
-			['user1', 'app1', 'fast_string_sensitive', true, true, true],
380
-			['user1', 'app1', 'lazy_string_sensitive', false, true, true],
381
-			['user1', 'app1', 'lazy_string_sensitive', null, true, false],
382
-			['user2', 'only-lazy', 'key1', false, false, true],
383
-			['user2', 'only-lazy', 'key1', true, false, false],
384
-			['user2', 'only-lazy', 'key1', null, false, false],
385
-		];
386
-	}
387
-
388
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerIsSensitive')]
389
-	public function testIsSensitive(
390
-		string $userId,
391
-		string $appId,
392
-		string $key,
393
-		?bool $lazy,
394
-		bool $result,
395
-		bool $exception,
396
-	): void {
397
-		$userConfig = $this->generateUserConfig();
398
-		if ($exception) {
399
-			$this->expectException(UnknownKeyException::class);
400
-		}
401
-
402
-		$this->assertEquals($result, $userConfig->isSensitive($userId, $appId, $key, $lazy));
403
-	}
404
-
405
-	public static function providerIsLazy(): array {
406
-		return [
407
-			['user1', 'app1', 'key1', false, false],
408
-			['user0', 'app1', 'key1', false, true],
409
-			['user1', 'app1', 'key0', false, true],
410
-			['user1', 'app1', 'key0', false, true],
411
-			['user1', 'app1', 'fast_string_sensitive', false, false],
412
-			['user1', 'app1', 'lazy_string_sensitive', true, false],
413
-			['user2', 'only-lazy', 'key1', true, false],
414
-		];
415
-	}
416
-
417
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerIsLazy')]
418
-	public function testIsLazy(
419
-		string $userId,
420
-		string $appId,
421
-		string $key,
422
-		bool $result,
423
-		bool $exception,
424
-	): void {
425
-		$userConfig = $this->generateUserConfig();
426
-		if ($exception) {
427
-			$this->expectException(UnknownKeyException::class);
428
-		}
429
-
430
-		$this->assertEquals($result, $userConfig->isLazy($userId, $appId, $key));
431
-	}
432
-
433
-	public static function providerGetValues(): array {
434
-		return [
435
-			[
436
-				'user1', 'app1', '', true,
437
-				[
438
-					'fast_array' => ['year' => 2024],
439
-					'fast_array_sensitive' => '***REMOVED SENSITIVE VALUE***',
440
-					'fast_boolean' => true,
441
-					'fast_boolean_0' => false,
442
-					'fast_float' => 3.14,
443
-					'fast_float_sensitive' => '***REMOVED SENSITIVE VALUE***',
444
-					'fast_int' => 11,
445
-					'fast_int_sensitive' => '***REMOVED SENSITIVE VALUE***',
446
-					'fast_string' => 'f_value',
447
-					'fast_string_sensitive' => '***REMOVED SENSITIVE VALUE***',
448
-					'key1' => 'value1',
449
-					'key22' => '31',
450
-					'lazy_array' => ['month' => 'October'],
451
-					'lazy_array_sensitive' => '***REMOVED SENSITIVE VALUE***',
452
-					'lazy_boolean' => true,
453
-					'lazy_boolean_0' => false,
454
-					'lazy_float' => 3.14159,
455
-					'lazy_float_sensitive' => '***REMOVED SENSITIVE VALUE***',
456
-					'lazy_int' => 12,
457
-					'lazy_int_sensitive' => '***REMOVED SENSITIVE VALUE***',
458
-					'lazy_string' => 'l_value',
459
-					'lazy_string_sensitive' => '***REMOVED SENSITIVE VALUE***',
460
-				]
461
-			],
462
-			[
463
-				'user1', 'app1', '', false,
464
-				[
465
-					'fast_array' => ['year' => 2024],
466
-					'fast_array_sensitive' => ['password' => 'pwd'],
467
-					'fast_boolean' => true,
468
-					'fast_boolean_0' => false,
469
-					'fast_float' => 3.14,
470
-					'fast_float_sensitive' => 1.41,
471
-					'fast_int' => 11,
472
-					'fast_int_sensitive' => 2024,
473
-					'fast_string' => 'f_value',
474
-					'fast_string_sensitive' => 'fs_value',
475
-					'key1' => 'value1',
476
-					'key22' => '31',
477
-					'lazy_array' => ['month' => 'October'],
478
-					'lazy_array_sensitive' => ['password' => 'qwerty'],
479
-					'lazy_boolean' => true,
480
-					'lazy_boolean_0' => false,
481
-					'lazy_float' => 3.14159,
482
-					'lazy_float_sensitive' => 1.4142,
483
-					'lazy_int' => 12,
484
-					'lazy_int_sensitive' => 2048,
485
-					'lazy_string' => 'l_value',
486
-					'lazy_string_sensitive' => 'ls_value'
487
-				]
488
-			],
489
-			[
490
-				'user1', 'app1', 'fast_', true,
491
-				[
492
-					'fast_array' => ['year' => 2024],
493
-					'fast_array_sensitive' => '***REMOVED SENSITIVE VALUE***',
494
-					'fast_boolean' => true,
495
-					'fast_boolean_0' => false,
496
-					'fast_float' => 3.14,
497
-					'fast_float_sensitive' => '***REMOVED SENSITIVE VALUE***',
498
-					'fast_int' => 11,
499
-					'fast_int_sensitive' => '***REMOVED SENSITIVE VALUE***',
500
-					'fast_string' => 'f_value',
501
-					'fast_string_sensitive' => '***REMOVED SENSITIVE VALUE***',
502
-				]
503
-			],
504
-			[
505
-				'user1', 'app1', 'fast_', false,
506
-				[
507
-					'fast_array' => ['year' => 2024],
508
-					'fast_array_sensitive' => ['password' => 'pwd'],
509
-					'fast_boolean' => true,
510
-					'fast_boolean_0' => false,
511
-					'fast_float' => 3.14,
512
-					'fast_float_sensitive' => 1.41,
513
-					'fast_int' => 11,
514
-					'fast_int_sensitive' => 2024,
515
-					'fast_string' => 'f_value',
516
-					'fast_string_sensitive' => 'fs_value',
517
-				]
518
-			],
519
-			[
520
-				'user1', 'app1', 'key1', true,
521
-				[
522
-					'key1' => 'value1',
523
-				]
524
-			],
525
-			[
526
-				'user2', 'app1', '', false,
527
-				[
528
-					'1' => 'value1',
529
-					'4' => 42,
530
-					'5' => 17.42,
531
-					'6' => true,
532
-					'2' => 'value2',
533
-					'3' => 17,
534
-				]
535
-			],
536
-			[
537
-				'user2', 'app1', '', true,
538
-				[
539
-					'1' => 'value1',
540
-					'4' => '***REMOVED SENSITIVE VALUE***',
541
-					'5' => 17.42,
542
-					'6' => true,
543
-					'2' => '***REMOVED SENSITIVE VALUE***',
544
-					'3' => 17,
545
-				]
546
-			],
547
-		];
548
-	}
549
-
550
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetValues')]
551
-	public function testGetValues(
552
-		string $userId,
553
-		string $appId,
554
-		string $prefix,
555
-		bool $filtered,
556
-		array $result,
557
-	): void {
558
-		$userConfig = $this->generateUserConfig();
559
-		$this->assertJsonStringEqualsJsonString(
560
-			json_encode($result), json_encode($userConfig->getValues($userId, $appId, $prefix, $filtered))
561
-		);
562
-	}
563
-
564
-	public static function providerGetAllValues(): array {
565
-		return [
566
-			[
567
-				'user2', false,
568
-				[
569
-					'app1' => [
570
-						'1' => 'value1',
571
-						'4' => 42,
572
-						'5' => 17.42,
573
-						'6' => true,
574
-						'2' => 'value2',
575
-						'3' => 17,
576
-					],
577
-					'app2' => [
578
-						'key2' => 'value2b',
579
-						'key3' => 'value3',
580
-						'key4' => 'value4',
581
-						'key8' => 12,
582
-					],
583
-					'app3' => [
584
-						'key10' => false,
585
-					],
586
-					'only-lazy' => [
587
-						'key1' => 'value1',
588
-					]
589
-				],
590
-			],
591
-			[
592
-				'user2', true,
593
-				[
594
-					'app1' => [
595
-						'1' => 'value1',
596
-						'4' => '***REMOVED SENSITIVE VALUE***',
597
-						'5' => 17.42,
598
-						'6' => true,
599
-						'2' => '***REMOVED SENSITIVE VALUE***',
600
-						'3' => 17,
601
-					],
602
-					'app2' => [
603
-						'key2' => 'value2b',
604
-						'key3' => 'value3',
605
-						'key4' => '***REMOVED SENSITIVE VALUE***',
606
-						'key8' => 12,
607
-					],
608
-					'app3' => [
609
-						'key10' => false,
610
-					],
611
-					'only-lazy' => [
612
-						'key1' => 'value1',
613
-					]
614
-				],
615
-			],
616
-			[
617
-				'user3', true,
618
-				[
619
-					'app2' => [
620
-						'key2' => 'value2c',
621
-						'key3' => 'value3',
622
-						'key4' => '***REMOVED SENSITIVE VALUE***',
623
-						'fast_string_sensitive' => '***REMOVED SENSITIVE VALUE***',
624
-						'lazy_string_sensitive' => '***REMOVED SENSITIVE VALUE***',
625
-					],
626
-					'only-lazy' => [
627
-						'key3' => 'value3',
628
-					]
629
-				],
630
-			],
631
-			[
632
-				'user3', false,
633
-				[
634
-					'app2' => [
635
-						'key2' => 'value2c',
636
-						'key3' => 'value3',
637
-						'key4' => 'value4',
638
-						'fast_string_sensitive' => 'fs_value',
639
-						'lazy_string_sensitive' => 'ls_value',
640
-					],
641
-					'only-lazy' => [
642
-						'key3' => 'value3',
643
-					]
644
-				],
645
-			],
646
-		];
647
-	}
648
-
649
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetAllValues')]
650
-	public function testGetAllValues(
651
-		string $userId,
652
-		bool $filtered,
653
-		array $result,
654
-	): void {
655
-		$userConfig = $this->generateUserConfig();
656
-		$this->assertEqualsCanonicalizing($result, $userConfig->getAllValues($userId, $filtered));
657
-	}
658
-
659
-	public static function providerSearchValuesByApps(): array {
660
-		return [
661
-			[
662
-				'user1', 'key1', false, null,
663
-				[
664
-					'app1' => 'value1',
665
-					'app3' => 'value123'
666
-				]
667
-			],
668
-			[
669
-				'user1', 'key1', true, null,
670
-				[
671
-					'only-lazy' => 'value456'
672
-				]
673
-			],
674
-			[
675
-				'user1', 'key8', false, null,
676
-				[
677
-					'app2' => 11,
678
-					'app3' => 12,
679
-				]
680
-			],
681
-			[
682
-				'user1', 'key9', false, ValueType::INT,
683
-				[
684
-					'app2' => 0,
685
-					'app3' => 0,
686
-				]
687
-			]
688
-		];
689
-	}
690
-
691
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerSearchValuesByApps')]
692
-	public function testSearchValuesByApps(
693
-		string $userId,
694
-		string $key,
695
-		bool $lazy,
696
-		?ValueType $typedAs,
697
-		array $result,
698
-	): void {
699
-		$userConfig = $this->generateUserConfig();
700
-		$this->assertEquals($result, $userConfig->getValuesByApps($userId, $key, $lazy, $typedAs));
701
-	}
702
-
703
-	public static function providerSearchValuesByUsers(): array {
704
-		return [
705
-			[
706
-				'app2', 'key2', null, null,
707
-				[
708
-					'user1' => 'value2a',
709
-					'user2' => 'value2b',
710
-					'user3' => 'value2c',
711
-					'user4' => 'value2A'
712
-				]
713
-			],
714
-			[
715
-				'app2', 'key2', null, ['user1', 'user3'],
716
-				[
717
-					'user1' => 'value2a',
718
-					'user3' => 'value2c',
719
-				]
720
-			],
721
-			[
722
-				'app2', 'key2', ValueType::INT, ['user1', 'user3'],
723
-				[
724
-					'user1' => 0,
725
-					'user3' => 0,
726
-				]
727
-			],
728
-			[
729
-				'app2', 'key8', ValueType::INT, null,
730
-				[
731
-					'user1' => 11,
732
-					'user2' => 12,
733
-					'user5' => 12,
734
-				]
735
-			],
736
-		];
737
-	}
738
-
739
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerSearchValuesByUsers')]
740
-	public function testSearchValuesByUsers(
741
-		string $app,
742
-		string $key,
743
-		?ValueType $typedAs,
744
-		?array $userIds,
745
-		array $result,
746
-	): void {
747
-		$userConfig = $this->generateUserConfig();
748
-		$this->assertEqualsCanonicalizing(
749
-			$result, $userConfig->getValuesByUsers($app, $key, $typedAs, $userIds)
750
-		);
751
-	}
752
-
753
-	public static function providerSearchValuesByValueString(): array {
754
-		return [
755
-			['app2', 'key2', 'value2a', false, ['user1']],
756
-			['app2', 'key2', 'value2A', false, ['user4']],
757
-			['app2', 'key2', 'value2A', true, ['user1', 'user4']]
758
-		];
759
-	}
760
-
761
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerSearchValuesByValueString')]
762
-	public function testSearchUsersByValueString(
763
-		string $app,
764
-		string $key,
765
-		string|array $value,
766
-		bool $ci,
767
-		array $result,
768
-	): void {
769
-		$userConfig = $this->generateUserConfig();
770
-		$this->assertEqualsCanonicalizing($result, iterator_to_array($userConfig->searchUsersByValueString($app, $key, $value, $ci)));
771
-	}
772
-
773
-	public static function providerSearchValuesByValueInt(): array {
774
-		return [
775
-			['app3', 'key8', 12, []], // sensitive value, cannot search
776
-			['app2', 'key8', 12, ['user2', 'user5']], // sensitive value, cannot search
777
-			['only-lazy', 'key1', 123, ['user4']],
778
-		];
779
-	}
780
-
781
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerSearchValuesByValueInt')]
782
-	public function testSearchUsersByValueInt(
783
-		string $app,
784
-		string $key,
785
-		int $value,
786
-		array $result,
787
-	): void {
788
-		$userConfig = $this->generateUserConfig();
789
-		$this->assertEqualsCanonicalizing($result, iterator_to_array($userConfig->searchUsersByValueInt($app, $key, $value)));
790
-	}
791
-
792
-	public static function providerSearchValuesByValues(): array {
793
-		return [
794
-			['app2', 'key2', ['value2a', 'value2b'], ['user1', 'user2']],
795
-			['app2', 'key2', ['value2a', 'value2c'], ['user1', 'user3']],
796
-		];
797
-	}
798
-
799
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerSearchValuesByValues')]
800
-	public function testSearchUsersByValues(
801
-		string $app,
802
-		string $key,
803
-		array $values,
804
-		array $result,
805
-	): void {
806
-		$userConfig = $this->generateUserConfig();
807
-		$this->assertEqualsCanonicalizing($result, iterator_to_array($userConfig->searchUsersByValues($app, $key, $values)));
808
-	}
809
-
810
-	public static function providerSearchValuesByValueBool(): array {
811
-		return [
812
-			['app3', 'key10', true, ['user1', 'user4']],
813
-			['app3', 'key10', false, ['user2']],
814
-		];
815
-	}
816
-
817
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerSearchValuesByValueBool')]
818
-	public function testSearchUsersByValueBool(
819
-		string $app,
820
-		string $key,
821
-		bool $value,
822
-		array $result,
823
-	): void {
824
-		$userConfig = $this->generateUserConfig();
825
-		$this->assertEqualsCanonicalizing($result, iterator_to_array($userConfig->searchUsersByValueBool($app, $key, $value)));
826
-	}
827
-
828
-	public static function providerGetValueMixed(): array {
829
-		return [
830
-			[
831
-				['user1'], 'user1', 'app1', 'key0', 'default_because_unknown_key', true,
832
-				'default_because_unknown_key'
833
-			],
834
-			[
835
-				null, 'user1', 'app1', 'key0', 'default_because_unknown_key', true,
836
-				'default_because_unknown_key'
837
-			],
838
-			[
839
-				['user1'], 'user1', 'app1', 'key0', 'default_because_unknown_key', false,
840
-				'default_because_unknown_key'
841
-			],
842
-			[
843
-				null, 'user1', 'app1', 'key0', 'default_because_unknown_key', false,
844
-				'default_because_unknown_key'
845
-			],
846
-			[['user1'], 'user1', 'app1', 'fast_string', 'default_because_unknown_key', false, 'f_value'],
847
-			[null, 'user1', 'app1', 'fast_string', 'default_because_unknown_key', false, 'f_value'],
848
-			[['user1'], 'user1', 'app1', 'fast_string', 'default_because_unknown_key', true, 'f_value'],
849
-			// because non-lazy are already loaded
850
-			[
851
-				null, 'user1', 'app1', 'fast_string', 'default_because_unknown_key', true,
852
-				'default_because_unknown_key'
853
-			],
854
-			[
855
-				['user1'], 'user1', 'app1', 'lazy_string', 'default_because_unknown_key', false,
856
-				'default_because_unknown_key'
857
-			],
858
-			[
859
-				null, 'user1', 'app1', 'lazy_string', 'default_because_unknown_key', false,
860
-				'default_because_unknown_key'
861
-			],
862
-			[['user1'], 'user1', 'app1', 'lazy_string', 'default_because_unknown_key', true, 'l_value'],
863
-			[null, 'user1', 'app1', 'lazy_string', 'default_because_unknown_key', true, 'l_value'],
864
-			[
865
-				['user1'], 'user1', 'app1', 'fast_string_sensitive', 'default_because_unknown_key', false,
866
-				'fs_value'
867
-			],
868
-			[
869
-				null, 'user1', 'app1', 'fast_string_sensitive', 'default_because_unknown_key', false,
870
-				'fs_value'
871
-			],
872
-			[
873
-				['user1'], 'user1', 'app1', 'fast_string_sensitive', 'default_because_unknown_key', true,
874
-				'fs_value'
875
-			],
876
-			[
877
-				null, 'user1', 'app1', 'fast_string_sensitive', 'default_because_unknown_key', true,
878
-				'default_because_unknown_key'
879
-			],
880
-			[
881
-				['user1'], 'user1', 'app1', 'lazy_string_sensitive', 'default_because_unknown_key', false,
882
-				'default_because_unknown_key'
883
-			],
884
-			[
885
-				null, 'user1', 'app1', 'lazy_string_sensitive', 'default_because_unknown_key', false,
886
-				'default_because_unknown_key'
887
-			],
888
-			[
889
-				['user1'], 'user1', 'app1', 'lazy_string_sensitive', 'default_because_unknown_key', true,
890
-				'ls_value'
891
-			],
892
-			[null, 'user1', 'app1', 'lazy_string_sensitive', 'default_because_unknown_key', true, 'ls_value'],
893
-		];
894
-	}
895
-
896
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueMixed')]
897
-	public function testGetValueMixed(
898
-		?array $preload,
899
-		string $userId,
900
-		string $app,
901
-		string $key,
902
-		string $default,
903
-		bool $lazy,
904
-		string $result,
905
-	): void {
906
-		$userConfig = $this->generateUserConfig($preload ?? []);
907
-		$this->assertEquals($result, $userConfig->getValueMixed($userId, $app, $key, $default, $lazy));
908
-	}
909
-
910
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueMixed')]
911
-	public function testGetValueString(
912
-		?array $preload,
913
-		string $userId,
914
-		string $app,
915
-		string $key,
916
-		string $default,
917
-		bool $lazy,
918
-		string $result,
919
-	): void {
920
-		$userConfig = $this->generateUserConfig($preload ?? []);
921
-		$this->assertEquals($result, $userConfig->getValueString($userId, $app, $key, $default, $lazy));
922
-	}
923
-
924
-	public static function providerGetValueInt(): array {
925
-		return [
926
-			[['user1'], 'user1', 'app1', 'key0', 54321, true, 54321],
927
-			[null, 'user1', 'app1', 'key0', 54321, true, 54321],
928
-			[['user1'], 'user1', 'app1', 'key0', 54321, false, 54321],
929
-			[null, 'user1', 'app1', 'key0', 54321, false, 54321],
930
-			[null, 'user1', 'app1', 'key22', 54321, false, 31],
931
-			[['user1'], 'user1', 'app1', 'fast_int', 54321, false, 11],
932
-			[null, 'user1', 'app1', 'fast_int', 54321, false, 11],
933
-			[['user1'], 'user1', 'app1', 'fast_int', 54321, true, 11],
934
-			[null, 'user1', 'app1', 'fast_int', 54321, true, 54321],
935
-			[['user1'], 'user1', 'app1', 'fast_int_sensitive', 54321, false, 2024],
936
-			[null, 'user1', 'app1', 'fast_int_sensitive', 54321, false, 2024],
937
-			[['user1'], 'user1', 'app1', 'fast_int_sensitive', 54321, true, 2024],
938
-			[null, 'user1', 'app1', 'fast_int_sensitive', 54321, true, 54321],
939
-			[['user1'], 'user1', 'app1', 'lazy_int', 54321, false, 54321],
940
-			[null, 'user1', 'app1', 'lazy_int', 54321, false, 54321],
941
-			[['user1'], 'user1', 'app1', 'lazy_int', 54321, true, 12],
942
-			[null, 'user1', 'app1', 'lazy_int', 54321, true, 12],
943
-			[['user1'], 'user1', 'app1', 'lazy_int_sensitive', 54321, false, 54321],
944
-			[null, 'user1', 'app1', 'lazy_int_sensitive', 54321, false, 54321],
945
-			[['user1'], 'user1', 'app1', 'lazy_int_sensitive', 54321, true, 2048],
946
-			[null, 'user1', 'app1', 'lazy_int_sensitive', 54321, true, 2048],
947
-		];
948
-	}
949
-
950
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueInt')]
951
-	public function testGetValueInt(
952
-		?array $preload,
953
-		string $userId,
954
-		string $app,
955
-		string $key,
956
-		int $default,
957
-		bool $lazy,
958
-		int $result,
959
-	): void {
960
-		$userConfig = $this->generateUserConfig($preload ?? []);
961
-		$this->assertEquals($result, $userConfig->getValueInt($userId, $app, $key, $default, $lazy));
962
-	}
963
-
964
-	public static function providerGetValueFloat(): array {
965
-		return [
966
-			[['user1'], 'user1', 'app1', 'key0', 54.321, true, 54.321],
967
-			[null, 'user1', 'app1', 'key0', 54.321, true, 54.321],
968
-			[['user1'], 'user1', 'app1', 'key0', 54.321, false, 54.321],
969
-			[null, 'user1', 'app1', 'key0', 54.321, false, 54.321],
970
-			[['user1'], 'user1', 'app1', 'fast_float', 54.321, false, 3.14],
971
-			[null, 'user1', 'app1', 'fast_float', 54.321, false, 3.14],
972
-			[['user1'], 'user1', 'app1', 'fast_float', 54.321, true, 3.14],
973
-			[null, 'user1', 'app1', 'fast_float', 54.321, true, 54.321],
974
-			[['user1'], 'user1', 'app1', 'fast_float_sensitive', 54.321, false, 1.41],
975
-			[null, 'user1', 'app1', 'fast_float_sensitive', 54.321, false, 1.41],
976
-			[['user1'], 'user1', 'app1', 'fast_float_sensitive', 54.321, true, 1.41],
977
-			[null, 'user1', 'app1', 'fast_float_sensitive', 54.321, true, 54.321],
978
-			[['user1'], 'user1', 'app1', 'lazy_float', 54.321, false, 54.321],
979
-			[null, 'user1', 'app1', 'lazy_float', 54.321, false, 54.321],
980
-			[['user1'], 'user1', 'app1', 'lazy_float', 54.321, true, 3.14159],
981
-			[null, 'user1', 'app1', 'lazy_float', 54.321, true, 3.14159],
982
-			[['user1'], 'user1', 'app1', 'lazy_float_sensitive', 54.321, false, 54.321],
983
-			[null, 'user1', 'app1', 'lazy_float_sensitive', 54.321, false, 54.321],
984
-			[['user1'], 'user1', 'app1', 'lazy_float_sensitive', 54.321, true, 1.4142],
985
-			[null, 'user1', 'app1', 'lazy_float_sensitive', 54.321, true, 1.4142],
986
-		];
987
-	}
988
-
989
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueFloat')]
990
-	public function testGetValueFloat(
991
-		?array $preload,
992
-		string $userId,
993
-		string $app,
994
-		string $key,
995
-		float $default,
996
-		bool $lazy,
997
-		float $result,
998
-	): void {
999
-		$userConfig = $this->generateUserConfig($preload ?? []);
1000
-		$this->assertEquals($result, $userConfig->getValueFloat($userId, $app, $key, $default, $lazy));
1001
-	}
1002
-
1003
-	public static function providerGetValueBool(): array {
1004
-		return [
1005
-			[['user1'], 'user1', 'app1', 'key0', false, true, false],
1006
-			[null, 'user1', 'app1', 'key0', false, true, false],
1007
-			[['user1'], 'user1', 'app1', 'key0', true, true, true],
1008
-			[null, 'user1', 'app1', 'key0', true, true, true],
1009
-			[['user1'], 'user1', 'app1', 'key0', false, false, false],
1010
-			[null, 'user1', 'app1', 'key0', false, false, false],
1011
-			[['user1'], 'user1', 'app1', 'key0', true, false, true],
1012
-			[null, 'user1', 'app1', 'key0', true, false, true],
1013
-			[['user1'], 'user1', 'app1', 'fast_boolean', false, false, true],
1014
-			[null, 'user1', 'app1', 'fast_boolean', false, false, true],
1015
-			[['user1'], 'user1', 'app1', 'fast_boolean_0', false, false, false],
1016
-			[null, 'user1', 'app1', 'fast_boolean_0', false, false, false],
1017
-			[['user1'], 'user1', 'app1', 'fast_boolean', true, false, true],
1018
-			[null, 'user1', 'app1', 'fast_boolean', true, false, true],
1019
-			[['user1'], 'user1', 'app1', 'fast_boolean_0', true, false, false],
1020
-			[null, 'user1', 'app1', 'fast_boolean_0', true, false, false],
1021
-			[['user1'], 'user1', 'app1', 'fast_boolean', false, true, true],
1022
-			[null, 'user1', 'app1', 'fast_boolean', false, true, false],
1023
-			[['user1'], 'user1', 'app1', 'fast_boolean_0', false, true, false],
1024
-			[null, 'user1', 'app1', 'fast_boolean_0', false, true, false],
1025
-			[['user1'], 'user1', 'app1', 'fast_boolean', true, true, true],
1026
-			[null, 'user1', 'app1', 'fast_boolean', true, true, true],
1027
-			[['user1'], 'user1', 'app1', 'fast_boolean_0', true, true, false],
1028
-			[null, 'user1', 'app1', 'fast_boolean_0', true, true, true],
1029
-			[['user1'], 'user1', 'app1', 'lazy_boolean', false, false, false],
1030
-			[null, 'user1', 'app1', 'lazy_boolean', false, false, false],
1031
-			[['user1'], 'user1', 'app1', 'lazy_boolean_0', false, false, false],
1032
-			[null, 'user1', 'app1', 'lazy_boolean_0', false, false, false],
1033
-			[['user1'], 'user1', 'app1', 'lazy_boolean', true, false, true],
1034
-			[null, 'user1', 'app1', 'lazy_boolean', true, false, true],
1035
-			[['user1'], 'user1', 'app1', 'lazy_boolean_0', true, false, true],
1036
-			[null, 'user1', 'app1', 'lazy_boolean_0', true, false, true],
1037
-			[['user1'], 'user1', 'app1', 'lazy_boolean', false, true, true],
1038
-			[null, 'user1', 'app1', 'lazy_boolean', false, true, true],
1039
-			[['user1'], 'user1', 'app1', 'lazy_boolean_0', false, true, false],
1040
-			[null, 'user1', 'app1', 'lazy_boolean_0', false, true, false],
1041
-			[['user1'], 'user1', 'app1', 'lazy_boolean', true, true, true],
1042
-			[null, 'user1', 'app1', 'lazy_boolean', true, true, true],
1043
-			[['user1'], 'user1', 'app1', 'lazy_boolean_0', true, true, false],
1044
-			[null, 'user1', 'app1', 'lazy_boolean_0', true, true, false],
1045
-		];
1046
-	}
1047
-
1048
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueBool')]
1049
-	public function testGetValueBool(
1050
-		?array $preload,
1051
-		string $userId,
1052
-		string $app,
1053
-		string $key,
1054
-		bool $default,
1055
-		bool $lazy,
1056
-		bool $result,
1057
-	): void {
1058
-		$userConfig = $this->generateUserConfig($preload ?? []);
1059
-		$this->assertEquals($result, $userConfig->getValueBool($userId, $app, $key, $default, $lazy));
1060
-	}
1061
-
1062
-	public static function providerGetValueArray(): array {
1063
-		return [
1064
-			[
1065
-				['user1'], 'user1', 'app1', 'key0', ['default_because_unknown_key'], true,
1066
-				['default_because_unknown_key']
1067
-			],
1068
-			[
1069
-				null, 'user1', 'app1', 'key0', ['default_because_unknown_key'], true,
1070
-				['default_because_unknown_key']
1071
-			],
1072
-			[
1073
-				['user1'], 'user1', 'app1', 'key0', ['default_because_unknown_key'], false,
1074
-				['default_because_unknown_key']
1075
-			],
1076
-			[
1077
-				null, 'user1', 'app1', 'key0', ['default_because_unknown_key'], false,
1078
-				['default_because_unknown_key']
1079
-			],
1080
-		];
1081
-	}
1082
-
1083
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueArray')]
1084
-	public function testGetValueArray(
1085
-		?array $preload,
1086
-		string $userId,
1087
-		string $app,
1088
-		string $key,
1089
-		array $default,
1090
-		bool $lazy,
1091
-		array $result,
1092
-	): void {
1093
-		$userConfig = $this->generateUserConfig($preload ?? []);
1094
-		$this->assertEqualsCanonicalizing(
1095
-			$result, $userConfig->getValueArray($userId, $app, $key, $default, $lazy)
1096
-		);
1097
-	}
1098
-
1099
-	public static function providerGetValueType(): array {
1100
-		return [
1101
-			[null, 'user1', 'app1', 'key1', false, ValueType::MIXED],
1102
-			[null, 'user1', 'app1', 'key1', true, null, UnknownKeyException::class],
1103
-			[null, 'user1', 'app1', 'fast_string', true, ValueType::STRING, UnknownKeyException::class],
1104
-			[['user1'], 'user1', 'app1', 'fast_string', true, ValueType::STRING],
1105
-			[null, 'user1', 'app1', 'fast_string', false, ValueType::STRING],
1106
-			[null, 'user1', 'app1', 'lazy_string', true, ValueType::STRING],
1107
-			[null, 'user1', 'app1', 'lazy_string', false, ValueType::STRING, UnknownKeyException::class],
1108
-			[
1109
-				null, 'user1', 'app1', 'fast_string_sensitive', true, ValueType::STRING,
1110
-				UnknownKeyException::class
1111
-			],
1112
-			[['user1'], 'user1', 'app1', 'fast_string_sensitive', true, ValueType::STRING],
1113
-			[null, 'user1', 'app1', 'fast_string_sensitive', false, ValueType::STRING],
1114
-			[null, 'user1', 'app1', 'lazy_string_sensitive', true, ValueType::STRING],
1115
-			[
1116
-				null, 'user1', 'app1', 'lazy_string_sensitive', false, ValueType::STRING,
1117
-				UnknownKeyException::class
1118
-			],
1119
-			[null, 'user1', 'app1', 'fast_int', true, ValueType::INT, UnknownKeyException::class],
1120
-			[['user1'], 'user1', 'app1', 'fast_int', true, ValueType::INT],
1121
-			[null, 'user1', 'app1', 'fast_int', false, ValueType::INT],
1122
-			[null, 'user1', 'app1', 'lazy_int', true, ValueType::INT],
1123
-			[null, 'user1', 'app1', 'lazy_int', false, ValueType::INT, UnknownKeyException::class],
1124
-			[null, 'user1', 'app1', 'fast_float', true, ValueType::FLOAT, UnknownKeyException::class],
1125
-			[['user1'], 'user1', 'app1', 'fast_float', true, ValueType::FLOAT],
1126
-			[null, 'user1', 'app1', 'fast_float', false, ValueType::FLOAT],
1127
-			[null, 'user1', 'app1', 'lazy_float', true, ValueType::FLOAT],
1128
-			[null, 'user1', 'app1', 'lazy_float', false, ValueType::FLOAT, UnknownKeyException::class],
1129
-			[null, 'user1', 'app1', 'fast_boolean', true, ValueType::BOOL, UnknownKeyException::class],
1130
-			[['user1'], 'user1', 'app1', 'fast_boolean', true, ValueType::BOOL],
1131
-			[null, 'user1', 'app1', 'fast_boolean', false, ValueType::BOOL],
1132
-			[null, 'user1', 'app1', 'lazy_boolean', true, ValueType::BOOL],
1133
-			[null, 'user1', 'app1', 'lazy_boolean', false, ValueType::BOOL, UnknownKeyException::class],
1134
-		];
1135
-	}
1136
-
1137
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueType')]
1138
-	public function testGetValueType(
1139
-		?array $preload,
1140
-		string $userId,
1141
-		string $app,
1142
-		string $key,
1143
-		?bool $lazy,
1144
-		?ValueType $result,
1145
-		?string $exception = null,
1146
-	): void {
1147
-		$userConfig = $this->generateUserConfig($preload ?? []);
1148
-		if ($exception !== null) {
1149
-			$this->expectException($exception);
1150
-		}
1151
-
1152
-		$type = $userConfig->getValueType($userId, $app, $key, $lazy);
1153
-		if ($exception === null) {
1154
-			$this->assertEquals($result->value, $type->value);
1155
-		}
1156
-	}
1157
-
1158
-	public static function providerSetValueMixed(): array {
1159
-		return [
1160
-			[null, 'user1', 'app1', 'key1', 'value', false, false, true],
1161
-			[null, 'user1', 'app1', 'key1', '12345', true, false, true],
1162
-			[null, 'user1', 'app1', 'key1', '12345', true, true, true],
1163
-			[null, 'user1', 'app1', 'key1', 'value1', false, false, false],
1164
-			[null, 'user1', 'app1', 'key1', 'value1', true, false, true],
1165
-			[null, 'user1', 'app1', 'key1', 'value1', false, true, true],
1166
-			[
1167
-				null, 'user1', 'app1', 'fast_string', 'f_value_2', false, false, true,
1168
-				TypeConflictException::class
1169
-			],
1170
-			[
1171
-				null, 'user1', 'app1', 'fast_string', 'f_value', true, false, true,
1172
-				TypeConflictException::class
1173
-			],
1174
-			[null, 'user1', 'app1', 'fast_string', 'f_value', true, true, true, TypeConflictException::class],
1175
-			[null, 'user1', 'app1', 'fast_int', 'n_value', false, false, true, TypeConflictException::class],
1176
-			[
1177
-				null, 'user1', 'app1', 'fast_float', 'n_value', false, false, true,
1178
-				TypeConflictException::class
1179
-			],
1180
-			[
1181
-				null, 'user1', 'app1', 'lazy_string', 'l_value_2', false, false, true,
1182
-				TypeConflictException::class
1183
-			],
1184
-			[null, 'user1', 'app1', 'lazy_string', 'l_value', true, false, false],
1185
-			[null, 'user1', 'app1', 'lazy_string', 'l_value', true, true, true, TypeConflictException::class],
1186
-			[null, 'user1', 'app1', 'lazy_int', 'l_value', false, false, true, TypeConflictException::class],
1187
-			[
1188
-				null, 'user1', 'app1', 'lazy_float', 'l_value', false, false, true,
1189
-				TypeConflictException::class
1190
-			],
1191
-		];
1192
-	}
1193
-
1194
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerSetValueMixed')]
1195
-	public function testSetValueMixed(
1196
-		?array $preload,
1197
-		string $userId,
1198
-		string $app,
1199
-		string $key,
1200
-		string $value,
1201
-		bool $lazy,
1202
-		bool $sensitive,
1203
-		bool $result,
1204
-		?string $exception = null,
1205
-	): void {
1206
-		$userConfig = $this->generateUserConfig($preload ?? []);
1207
-		if ($exception !== null) {
1208
-			$this->expectException($exception);
1209
-		}
1210
-
1211
-		$edited = $userConfig->setValueMixed($userId, $app, $key, $value, $lazy, ($sensitive) ? 1 : 0);
1212
-
1213
-		if ($exception === null) {
1214
-			$this->assertEquals($result, $edited);
1215
-		}
1216
-	}
1217
-
1218
-	/**
1219
-	 * This test needs to stay! Emails are expected to be lowercase due to performance reasons.
1220
-	 * This way we can skip the expensive casing change on the database.
1221
-	 */
1222
-	public function testSetValueMixedWithSettingsEmail(): void {
1223
-		$userConfig = $this->generateUserConfig();
1224
-
1225
-		$edited = $userConfig->setValueMixed('user1', 'settings', 'email', '[email protected]');
1226
-		$this->assertTrue($edited);
1227
-
1228
-		$actual = $userConfig->getValueMixed('user1', 'settings', 'email');
1229
-		$this->assertEquals('[email protected]', $actual);
1230
-	}
1231
-
1232
-	public static function providerSetValueString(): array {
1233
-		return [
1234
-			[null, 'user1', 'app1', 'key1', 'value', false, false, true],
1235
-			[null, 'user1', 'app1', 'key1', '12345', true, false, true],
1236
-			[null, 'user1', 'app1', 'key1', '12345', true, true, true],
1237
-			[null, 'user1', 'app1', 'key1', 'value1', false, false, false],
1238
-			[null, 'user1', 'app1', 'key1', 'value1', true, false, true],
1239
-			[null, 'user1', 'app1', 'key1', 'value1', false, true, true],
1240
-			[null, 'user1', 'app1', 'fast_string', 'f_value_2', false, false, true],
1241
-			[null, 'user1', 'app1', 'fast_string', 'f_value', false, false, false],
1242
-			[null, 'user1', 'app1', 'fast_string', 'f_value', true, false, true],
1243
-			[null, 'user1', 'app1', 'fast_string', 'f_value', true, true, true],
1244
-			[null, 'user1', 'app1', 'lazy_string', 'l_value_2', false, false, true],
1245
-			[null, 'user1', 'app1', 'lazy_string', 'l_value', true, false, false],
1246
-			[null, 'user1', 'app1', 'lazy_string', 'l_value', true, true, true],
1247
-			[null, 'user1', 'app1', 'fast_string_sensitive', 'fs_value', false, true, false],
1248
-			[null, 'user1', 'app1', 'fast_string_sensitive', 'fs_value', true, true, true],
1249
-			[null, 'user1', 'app1', 'fast_string_sensitive', 'fs_value', true, false, true],
1250
-			[null, 'user1', 'app1', 'lazy_string_sensitive', 'ls_value', false, true, true],
1251
-			[null, 'user1', 'app1', 'lazy_string_sensitive', 'ls_value', true, true, false],
1252
-			[null, 'user1', 'app1', 'lazy_string_sensitive', 'ls_value', true, false, false],
1253
-			[null, 'user1', 'app1', 'lazy_string_sensitive', 'ls_value_2', true, false, true],
1254
-			[null, 'user1', 'app1', 'fast_int', 'n_value', false, false, true, TypeConflictException::class],
1255
-			[
1256
-				null, 'user1', 'app1', 'fast_float', 'n_value', false, false, true,
1257
-				TypeConflictException::class
1258
-			],
1259
-			[
1260
-				null, 'user1', 'app1', 'fast_float', 'n_value', false, false, true,
1261
-				TypeConflictException::class
1262
-			],
1263
-			[null, 'user1', 'app1', 'lazy_int', 'n_value', false, false, true, TypeConflictException::class],
1264
-			[
1265
-				null, 'user1', 'app1', 'lazy_boolean', 'n_value', false, false, true,
1266
-				TypeConflictException::class
1267
-			],
1268
-			[
1269
-				null, 'user1', 'app1', 'lazy_float', 'n_value', false, false, true,
1270
-				TypeConflictException::class
1271
-			],
1272
-		];
1273
-	}
1274
-
1275
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerSetValueString')]
1276
-	public function testSetValueString(
1277
-		?array $preload,
1278
-		string $userId,
1279
-		string $app,
1280
-		string $key,
1281
-		string $value,
1282
-		bool $lazy,
1283
-		bool $sensitive,
1284
-		bool $result,
1285
-		?string $exception = null,
1286
-	): void {
1287
-		$userConfig = $this->generateUserConfig($preload ?? []);
1288
-		if ($exception !== null) {
1289
-			$this->expectException($exception);
1290
-		}
1291
-
1292
-		$edited = $userConfig->setValueString($userId, $app, $key, $value, $lazy, ($sensitive) ? 1 : 0);
1293
-		if ($exception !== null) {
1294
-			return;
1295
-		}
1296
-
1297
-		$this->assertEquals($result, $edited);
1298
-		if ($result) {
1299
-			$this->assertEquals($value, $userConfig->getValueString($userId, $app, $key, $value, $lazy));
1300
-			$userConfig = $this->generateUserConfig($preload ?? []);
1301
-			$this->assertEquals($value, $userConfig->getValueString($userId, $app, $key, $value, $lazy));
1302
-		}
1303
-	}
1304
-
1305
-	public static function providerSetValueInt(): array {
1306
-		return [
1307
-			[null, 'user1', 'app1', 'key1', 12345, false, false, true],
1308
-			[null, 'user1', 'app1', 'key1', 12345, true, false, true],
1309
-			[null, 'user1', 'app1', 'key1', 12345, true, true, true],
1310
-			[null, 'user1', 'app1', 'fast_int', 11, false, false, false],
1311
-			[null, 'user1', 'app1', 'fast_int', 111, false, false, true],
1312
-			[null, 'user1', 'app1', 'fast_int', 111, true, false, true],
1313
-			[null, 'user1', 'app1', 'fast_int', 111, false, true, true],
1314
-			[null, 'user1', 'app1', 'fast_int', 11, true, false, true],
1315
-			[null, 'user1', 'app1', 'fast_int', 11, false, true, true],
1316
-			[null, 'user1', 'app1', 'lazy_int', 12, false, false, true],
1317
-			[null, 'user1', 'app1', 'lazy_int', 121, false, false, true],
1318
-			[null, 'user1', 'app1', 'lazy_int', 121, true, false, true],
1319
-			[null, 'user1', 'app1', 'lazy_int', 121, false, true, true],
1320
-			[null, 'user1', 'app1', 'lazy_int', 12, true, false, false],
1321
-			[null, 'user1', 'app1', 'lazy_int', 12, false, true, true],
1322
-			[null, 'user1', 'app1', 'fast_string', 12345, false, false, true, TypeConflictException::class],
1323
-			[null, 'user1', 'app1', 'fast_string', 12345, false, false, false, TypeConflictException::class],
1324
-			[null, 'user1', 'app1', 'fast_string', 12345, true, false, true, TypeConflictException::class],
1325
-			[null, 'user1', 'app1', 'fast_string', 12345, true, true, true, TypeConflictException::class],
1326
-			[null, 'user1', 'app1', 'lazy_string', 12345, false, false, true, TypeConflictException::class],
1327
-			[null, 'user1', 'app1', 'lazy_string', 12345, true, false, false, TypeConflictException::class],
1328
-			[null, 'user1', 'app1', 'lazy_string', 12345, true, true, true, TypeConflictException::class],
1329
-			[null, 'user1', 'app1', 'fast_float', 12345, false, false, true, TypeConflictException::class],
1330
-			[null, 'user1', 'app1', 'fast_float', 12345, false, false, true, TypeConflictException::class],
1331
-			[null, 'user1', 'app1', 'lazy_boolean', 12345, false, false, true, TypeConflictException::class],
1332
-			[null, 'user1', 'app1', 'lazy_float', 12345, false, false, true, TypeConflictException::class],
1333
-		];
1334
-	}
1335
-
1336
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerSetValueInt')]
1337
-	public function testSetValueInt(
1338
-		?array $preload,
1339
-		string $userId,
1340
-		string $app,
1341
-		string $key,
1342
-		int $value,
1343
-		bool $lazy,
1344
-		bool $sensitive,
1345
-		bool $result,
1346
-		?string $exception = null,
1347
-	): void {
1348
-		$userConfig = $this->generateUserConfig($preload ?? []);
1349
-		if ($exception !== null) {
1350
-			$this->expectException($exception);
1351
-		}
1352
-
1353
-		$edited = $userConfig->setValueInt($userId, $app, $key, $value, $lazy, ($sensitive) ? 1 : 0);
1354
-
1355
-		if ($exception !== null) {
1356
-			return;
1357
-		}
1358
-
1359
-		$this->assertEquals($result, $edited);
1360
-		if ($result) {
1361
-			$this->assertEquals($value, $userConfig->getValueInt($userId, $app, $key, $value, $lazy));
1362
-			$userConfig = $this->generateUserConfig($preload ?? []);
1363
-			$this->assertEquals($value, $userConfig->getValueInt($userId, $app, $key, $value, $lazy));
1364
-		}
1365
-	}
1366
-
1367
-	public static function providerSetValueFloat(): array {
1368
-		return [
1369
-			[null, 'user1', 'app1', 'key1', 12.345, false, false, true],
1370
-			[null, 'user1', 'app1', 'key1', 12.345, true, false, true],
1371
-			[null, 'user1', 'app1', 'key1', 12.345, true, true, true],
1372
-			[null, 'user1', 'app1', 'fast_float', 3.14, false, false, false],
1373
-			[null, 'user1', 'app1', 'fast_float', 3.15, false, false, true],
1374
-			[null, 'user1', 'app1', 'fast_float', 3.15, true, false, true],
1375
-			[null, 'user1', 'app1', 'fast_float', 3.15, false, true, true],
1376
-			[null, 'user1', 'app1', 'fast_float', 3.14, true, false, true],
1377
-			[null, 'user1', 'app1', 'fast_float', 3.14, false, true, true],
1378
-			[null, 'user1', 'app1', 'lazy_float', 3.14159, false, false, true],
1379
-			[null, 'user1', 'app1', 'lazy_float', 3.14158, false, false, true],
1380
-			[null, 'user1', 'app1', 'lazy_float', 3.14158, true, false, true],
1381
-			[null, 'user1', 'app1', 'lazy_float', 3.14158, false, true, true],
1382
-			[null, 'user1', 'app1', 'lazy_float', 3.14159, true, false, false],
1383
-			[null, 'user1', 'app1', 'lazy_float', 3.14159, false, true, true],
1384
-			[null, 'user1', 'app1', 'fast_string', 12.345, false, false, true, TypeConflictException::class],
1385
-			[null, 'user1', 'app1', 'fast_string', 12.345, false, false, false, TypeConflictException::class],
1386
-			[null, 'user1', 'app1', 'fast_string', 12.345, true, false, true, TypeConflictException::class],
1387
-			[null, 'user1', 'app1', 'fast_string', 12.345, true, true, true, TypeConflictException::class],
1388
-			[null, 'user1', 'app1', 'lazy_string', 12.345, false, false, true, TypeConflictException::class],
1389
-			[null, 'user1', 'app1', 'lazy_string', 12.345, true, false, false, TypeConflictException::class],
1390
-			[null, 'user1', 'app1', 'fast_array', 12.345, true, true, true, TypeConflictException::class],
1391
-			[null, 'user1', 'app1', 'fast_int', 12.345, false, false, true, TypeConflictException::class],
1392
-			[null, 'user1', 'app1', 'fast_int', 12.345, false, false, true, TypeConflictException::class],
1393
-			[null, 'user1', 'app1', 'lazy_boolean', 12.345, false, false, true, TypeConflictException::class],
1394
-		];
1395
-	}
1396
-
1397
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerSetValueFloat')]
1398
-	public function testSetValueFloat(
1399
-		?array $preload,
1400
-		string $userId,
1401
-		string $app,
1402
-		string $key,
1403
-		float $value,
1404
-		bool $lazy,
1405
-		bool $sensitive,
1406
-		bool $result,
1407
-		?string $exception = null,
1408
-	): void {
1409
-		$userConfig = $this->generateUserConfig($preload ?? []);
1410
-		if ($exception !== null) {
1411
-			$this->expectException($exception);
1412
-		}
1413
-
1414
-		$edited = $userConfig->setValueFloat($userId, $app, $key, $value, $lazy, ($sensitive) ? 1 : 0);
1415
-
1416
-		if ($exception !== null) {
1417
-			return;
1418
-		}
1419
-
1420
-		$this->assertEquals($result, $edited);
1421
-		if ($result) {
1422
-			$this->assertEquals($value, $userConfig->getValueFloat($userId, $app, $key, $value, $lazy));
1423
-			$userConfig = $this->generateUserConfig($preload ?? []);
1424
-			$this->assertEquals($value, $userConfig->getValueFloat($userId, $app, $key, $value, $lazy));
1425
-		}
1426
-	}
1427
-
1428
-
1429
-	public static function providerSetValueArray(): array {
1430
-		return [
1431
-			[null, 'user1', 'app1', 'key1', [], false, false, true],
1432
-			[null, 'user1', 'app1', 'key1', [], true, false, true],
1433
-			[null, 'user1', 'app1', 'key1', [], true, true, true],
1434
-			[null, 'user1', 'app1', 'fast_array', ['year' => 2024], false, false, false],
1435
-			[null, 'user1', 'app1', 'fast_array', [], false, false, true],
1436
-			[null, 'user1', 'app1', 'fast_array', [], true, false, true],
1437
-			[null, 'user1', 'app1', 'fast_array', [], false, true, true],
1438
-			[null, 'user1', 'app1', 'fast_array', ['year' => 2024], true, false, true],
1439
-			[null, 'user1', 'app1', 'fast_array', ['year' => 2024], false, true, true],
1440
-			[null, 'user1', 'app1', 'lazy_array', ['month' => 'October'], false, false, true],
1441
-			[null, 'user1', 'app1', 'lazy_array', ['month' => 'September'], false, false, true],
1442
-			[null, 'user1', 'app1', 'lazy_array', ['month' => 'September'], true, false, true],
1443
-			[null, 'user1', 'app1', 'lazy_array', ['month' => 'September'], false, true, true],
1444
-			[null, 'user1', 'app1', 'lazy_array', ['month' => 'October'], true, false, false],
1445
-			[null, 'user1', 'app1', 'lazy_array', ['month' => 'October'], false, true, true],
1446
-			[null, 'user1', 'app1', 'fast_string', [], false, false, true, TypeConflictException::class],
1447
-			[null, 'user1', 'app1', 'fast_string', [], false, false, false, TypeConflictException::class],
1448
-			[null, 'user1', 'app1', 'fast_string', [], true, false, true, TypeConflictException::class],
1449
-			[null, 'user1', 'app1', 'fast_string', [], true, true, true, TypeConflictException::class],
1450
-			[null, 'user1', 'app1', 'lazy_string', [], false, false, true, TypeConflictException::class],
1451
-			[null, 'user1', 'app1', 'lazy_string', [], true, false, false, TypeConflictException::class],
1452
-			[null, 'user1', 'app1', 'lazy_string', [], true, true, true, TypeConflictException::class],
1453
-			[null, 'user1', 'app1', 'fast_int', [], false, false, true, TypeConflictException::class],
1454
-			[null, 'user1', 'app1', 'fast_int', [], false, false, true, TypeConflictException::class],
1455
-			[null, 'user1', 'app1', 'lazy_boolean', [], false, false, true, TypeConflictException::class],
1456
-		];
1457
-	}
1458
-
1459
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerSetValueArray')]
1460
-	public function testSetValueArray(
1461
-		?array $preload,
1462
-		string $userId,
1463
-		string $app,
1464
-		string $key,
1465
-		array $value,
1466
-		bool $lazy,
1467
-		bool $sensitive,
1468
-		bool $result,
1469
-		?string $exception = null,
1470
-	): void {
1471
-		$userConfig = $this->generateUserConfig($preload ?? []);
1472
-		if ($exception !== null) {
1473
-			$this->expectException($exception);
1474
-		}
1475
-
1476
-		$edited = $userConfig->setValueArray($userId, $app, $key, $value, $lazy, ($sensitive) ? 1 : 0);
1477
-
1478
-		if ($exception !== null) {
1479
-			return;
1480
-		}
1481
-
1482
-		$this->assertEquals($result, $edited);
1483
-		if ($result) {
1484
-			$this->assertEqualsCanonicalizing(
1485
-				$value, $userConfig->getValueArray($userId, $app, $key, $value, $lazy)
1486
-			);
1487
-			$userConfig = $this->generateUserConfig($preload ?? []);
1488
-			$this->assertEqualsCanonicalizing(
1489
-				$value, $userConfig->getValueArray($userId, $app, $key, $value, $lazy)
1490
-			);
1491
-		}
1492
-	}
1493
-
1494
-	public static function providerUpdateSensitive(): array {
1495
-		return [
1496
-			[null, 'user1', 'app1', 'key1', false, false],
1497
-			[['user1'], 'user1', 'app1', 'key1', false, false],
1498
-			[null, 'user1', 'app1', 'key1', true, true],
1499
-			[['user1'], 'user1', 'app1', 'key1', true, true],
1500
-		];
1501
-	}
1502
-
1503
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerUpdateSensitive')]
1504
-	public function testUpdateSensitive(
1505
-		?array $preload,
1506
-		string $userId,
1507
-		string $app,
1508
-		string $key,
1509
-		bool $sensitive,
1510
-		bool $result,
1511
-		?string $exception = null,
1512
-	): void {
1513
-		$userConfig = $this->generateUserConfig($preload ?? []);
1514
-		if ($exception !== null) {
1515
-			$this->expectException($exception);
1516
-		}
1517
-
1518
-		$edited = $userConfig->updateSensitive($userId, $app, $key, $sensitive);
1519
-		if ($exception !== null) {
1520
-			return;
1521
-		}
1522
-
1523
-		$this->assertEquals($result, $edited);
1524
-		if ($result) {
1525
-			$this->assertEquals($sensitive, $userConfig->isSensitive($userId, $app, $key));
1526
-			$userConfig = $this->generateUserConfig($preload ?? []);
1527
-			$this->assertEquals($sensitive, $userConfig->isSensitive($userId, $app, $key));
1528
-			if ($sensitive) {
1529
-				$this->assertEquals(true, str_starts_with(
1530
-					$userConfig->statusCache()['fastCache'][$userId][$app][$key]
1531
-					?? $userConfig->statusCache()['lazyCache'][$userId][$app][$key],
1532
-					'$UserConfigEncryption$')
1533
-				);
1534
-			}
1535
-		}
1536
-	}
1537
-
1538
-	public static function providerUpdateGlobalSensitive(): array {
1539
-		return [[true], [false]];
1540
-	}
1541
-
1542
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerUpdateGlobalSensitive')]
1543
-	public function testUpdateGlobalSensitive(bool $sensitive): void {
1544
-		$userConfig = $this->generateUserConfig($preload ?? []);
1545
-		$app = 'app2';
1546
-		if ($sensitive) {
1547
-			$key = 'key2';
1548
-			$value = 'value2a';
1549
-		} else {
1550
-			$key = 'key4';
1551
-			$value = 'value4';
1552
-		}
1553
-
1554
-		$this->assertEquals($value, $userConfig->getValueString('user1', $app, $key));
1555
-		foreach (['user1', 'user2', 'user3', 'user4'] as $userId) {
1556
-			$userConfig->getValueString($userId, $app, $key); // cache loading for userId
1557
-			$this->assertEquals(
1558
-				!$sensitive, str_starts_with(
1559
-					$userConfig->statusCache()['fastCache'][$userId][$app][$key]
1560
-					?? $userConfig->statusCache()['lazyCache'][$userId][$app][$key],
1561
-					'$UserConfigEncryption$'
1562
-				)
1563
-			);
1564
-		}
1565
-
1566
-		$userConfig->updateGlobalSensitive($app, $key, $sensitive);
1567
-
1568
-		$this->assertEquals($value, $userConfig->getValueString('user1', $app, $key));
1569
-		foreach (['user1', 'user2', 'user3', 'user4'] as $userId) {
1570
-			$this->assertEquals($sensitive, $userConfig->isSensitive($userId, $app, $key));
1571
-			// should only work if updateGlobalSensitive drop cache
1572
-			$this->assertEquals($sensitive, str_starts_with(
1573
-				$userConfig->statusCache()['fastCache'][$userId][$app][$key]
1574
-				?? $userConfig->statusCache()['lazyCache'][$userId][$app][$key],
1575
-				'$UserConfigEncryption$')
1576
-			);
1577
-		}
1578
-	}
1579
-
1580
-	public static function providerUpdateLazy(): array {
1581
-		return [
1582
-			[null, 'user1', 'app1', 'key1', false, false],
1583
-			[['user1'], 'user1', 'app1', 'key1', false, false],
1584
-			[null, 'user1', 'app1', 'key1', true, true],
1585
-			[['user1'], 'user1', 'app1', 'key1', true, true],
1586
-		];
1587
-	}
1588
-
1589
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerUpdateLazy')]
1590
-	public function testUpdateLazy(
1591
-		?array $preload,
1592
-		string $userId,
1593
-		string $app,
1594
-		string $key,
1595
-		bool $lazy,
1596
-		bool $result,
1597
-		?string $exception = null,
1598
-	): void {
1599
-		$userConfig = $this->generateUserConfig($preload ?? []);
1600
-		if ($exception !== null) {
1601
-			$this->expectException($exception);
1602
-		}
1603
-
1604
-		$edited = $userConfig->updateLazy($userId, $app, $key, $lazy);
1605
-		if ($exception !== null) {
1606
-			return;
1607
-		}
1608
-
1609
-		$this->assertEquals($result, $edited);
1610
-		if ($result) {
1611
-			$this->assertEquals($lazy, $userConfig->isLazy($userId, $app, $key));
1612
-			$userConfig = $this->generateUserConfig($preload ?? []);
1613
-			$this->assertEquals($lazy, $userConfig->isLazy($userId, $app, $key));
1614
-		}
1615
-	}
1616
-
1617
-	public static function providerUpdateGlobalLazy(): array {
1618
-		return [[true], [false]];
1619
-	}
1620
-
1621
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerUpdateGlobalLazy')]
1622
-	public function testUpdateGlobalLazy(bool $lazy): void {
1623
-		$userConfig = $this->generateUserConfig($preload ?? []);
1624
-		$app = 'app2';
1625
-		if ($lazy) {
1626
-			$key = 'key4';
1627
-			$value = 'value4';
1628
-		} else {
1629
-			$key = 'key3';
1630
-			$value = 'value3';
1631
-		}
1632
-
1633
-		$this->assertEquals($value, $userConfig->getValueString('user1', $app, $key, '', !$lazy));
1634
-		foreach (['user1', 'user2', 'user3', 'user4'] as $userId) {
1635
-			$this->assertEquals(!$lazy, $userConfig->isLazy($userId, $app, $key));
1636
-		}
1637
-
1638
-		$userConfig->updateGlobalLazy($app, $key, $lazy);
1639
-		$this->assertEquals($value, $userConfig->getValueString('user1', $app, $key, '', $lazy));
1640
-		foreach (['user1', 'user2', 'user3', 'user4'] as $userId) {
1641
-			$this->assertEquals($lazy, $userConfig->isLazy($userId, $app, $key));
1642
-		}
1643
-	}
1644
-
1645
-	public static function providerGetDetails(): array {
1646
-		return [
1647
-			[
1648
-				'user3', 'app2', 'key2',
1649
-				[
1650
-					'userId' => 'user3',
1651
-					'app' => 'app2',
1652
-					'key' => 'key2',
1653
-					'value' => 'value2c',
1654
-					'type' => 0,
1655
-					'lazy' => false,
1656
-					'typeString' => 'mixed',
1657
-					'sensitive' => false
1658
-				]
1659
-			],
1660
-			[
1661
-				'user1', 'app1', 'lazy_int',
1662
-				[
1663
-					'userId' => 'user1',
1664
-					'app' => 'app1',
1665
-					'key' => 'lazy_int',
1666
-					'value' => 12,
1667
-					'type' => 2,
1668
-					'lazy' => true,
1669
-					'typeString' => 'int',
1670
-					'sensitive' => false
1671
-				]
1672
-			],
1673
-			[
1674
-				'user1', 'app1', 'fast_float_sensitive',
1675
-				[
1676
-					'userId' => 'user1',
1677
-					'app' => 'app1',
1678
-					'key' => 'fast_float_sensitive',
1679
-					'value' => 1.41,
1680
-					'type' => 3,
1681
-					'lazy' => false,
1682
-					'typeString' => 'float',
1683
-					'sensitive' => true
1684
-				]
1685
-			],
1686
-		];
1687
-	}
1688
-
1689
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerGetDetails')]
1690
-	public function testGetDetails(string $userId, string $app, string $key, array $result): void {
1691
-		$userConfig = $this->generateUserConfig($preload ?? []);
1692
-		$this->assertEqualsCanonicalizing($result, $userConfig->getDetails($userId, $app, $key));
1693
-	}
1694
-
1695
-
1696
-	public static function providerDeletePreference(): array {
1697
-		return [
1698
-			[null, 'user1', 'app1', 'key22'],
1699
-			[['user1'], 'user1', 'app1', 'fast_string_sensitive'],
1700
-			[null, 'user1', 'app1', 'lazy_array_sensitive'],
1701
-			[['user2'], 'user1', 'app1', 'lazy_array_sensitive'],
1702
-			[null, 'user2', 'only-lazy', 'key1'],
1703
-			[['user2'], 'user2', 'only-lazy', 'key1'],
1704
-		];
1705
-	}
1706
-
1707
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerDeletePreference')]
1708
-	public function testDeletePreference(
1709
-		?array $preload,
1710
-		string $userId,
1711
-		string $app,
1712
-		string $key,
1713
-	): void {
1714
-		$userConfig = $this->generateUserConfig($preload ?? []);
1715
-		$lazy = $userConfig->isLazy($userId, $app, $key);
1716
-
1717
-		$userConfig = $this->generateUserConfig($preload ?? []);
1718
-		$this->assertEquals(true, $userConfig->hasKey($userId, $app, $key, $lazy));
1719
-		$userConfig->deleteUserConfig($userId, $app, $key);
1720
-		$this->assertEquals(false, $userConfig->hasKey($userId, $app, $key, $lazy));
1721
-		$userConfig = $this->generateUserConfig($preload ?? []);
1722
-		$this->assertEquals(false, $userConfig->hasKey($userId, $app, $key, $lazy));
1723
-	}
1724
-
1725
-	public static function providerDeleteKey(): array {
1726
-		return [
1727
-			[null, 'app2', 'key3'],
1728
-			[['user1'], 'app2', 'key3'],
1729
-			[null, 'only-lazy', 'key1'],
1730
-			[['user2'], 'only-lazy', 'key1'],
1731
-			[null, 'app2', 'lazy_string_sensitive'],
1732
-			[['user3', 'user1'], 'app2', 'lazy_string_sensitive'],
1733
-		];
1734
-	}
1735
-
1736
-	#[\PHPUnit\Framework\Attributes\DataProvider('providerDeleteKey')]
1737
-	public function testDeleteKey(
1738
-		?array $preload,
1739
-		string $app,
1740
-		string $key,
1741
-	): void {
1742
-		$userConfig = $this->generateUserConfig($preload ?? []);
1743
-		$userConfig->deleteKey($app, $key);
1744
-
1745
-		foreach (['user1', 'user2', 'user3', 'user4'] as $userId) {
1746
-			$this->assertEquals(false, $userConfig->hasKey($userId, $app, $key, null));
1747
-			$userConfigTemp = $this->generateUserConfig($preload ?? []);
1748
-			$this->assertEquals(false, $userConfigTemp->hasKey($userId, $app, $key, null));
1749
-		}
1750
-	}
1751
-
1752
-	public function testDeleteApp(): void {
1753
-		$userConfig = $this->generateUserConfig();
1754
-		$userConfig->deleteApp('only-lazy');
1755
-
1756
-		foreach (['user1', 'user2', 'user3', 'user4'] as $userId) {
1757
-			$this->assertEquals(false, in_array('only-lazy', $userConfig->getApps($userId)));
1758
-			$userConfigTemp = $this->generateUserConfig();
1759
-			$this->assertEquals(false, in_array('only-lazy', $userConfigTemp->getApps($userId)));
1760
-		}
1761
-	}
1762
-
1763
-	public function testDeleteAllPreferences(): void {
1764
-		$userConfig = $this->generateUserConfig();
1765
-		$userConfig->deleteAllUserConfig('user1');
1766
-
1767
-		$this->assertEqualsCanonicalizing([], $userConfig->getApps('user1'));
1768
-		$userConfig = $this->generateUserConfig();
1769
-		$this->assertEqualsCanonicalizing([], $userConfig->getApps('user1'));
1770
-	}
1771
-
1772
-	public function testClearCache(): void {
1773
-		$userConfig = $this->generateUserConfig(['user1', 'user2']);
1774
-		$userConfig->clearCache('user1');
1775
-
1776
-		$this->assertEquals(true, $userConfig->statusCache()['fastLoaded']['user2']);
1777
-		$this->assertEquals(false, $userConfig->statusCache()['fastLoaded']['user1']);
1778
-		$this->assertEquals('value2a', $userConfig->getValueString('user1', 'app2', 'key2'));
1779
-		$this->assertEquals(false, $userConfig->statusCache()['lazyLoaded']['user1']);
1780
-		$this->assertEquals(true, $userConfig->statusCache()['fastLoaded']['user1']);
1781
-	}
1782
-
1783
-	public function testClearCacheAll(): void {
1784
-		$userConfig = $this->generateUserConfig(['user1', 'user2']);
1785
-		$userConfig->clearCacheAll();
1786
-		$this->assertEqualsCanonicalizing(
1787
-			[
1788
-				'fastLoaded' => [],
1789
-				'fastCache' => [],
1790
-				'lazyLoaded' => [],
1791
-				'lazyCache' => [],
1792
-				'valueDetails' => [],
1793
-			],
1794
-			$userConfig->statusCache()
1795
-		);
1796
-	}
33
+    protected IDBConnection $connection;
34
+    private IConfig $config;
35
+    private ConfigManager $configManager;
36
+    private PresetManager $presetManager;
37
+    private LoggerInterface $logger;
38
+    private ICrypto $crypto;
39
+    private IEventDispatcher $dispatcher;
40
+    private array $originalPreferences;
41
+
42
+    /**
43
+     * @var array<string, array<string, array<array<string, string, int, bool, bool>>> [userId => [appId => prefKey, prefValue, valueType, lazy, sensitive]]]
44
+     */
45
+    private array $basePreferences
46
+        = [
47
+            'user1'
48
+                => [
49
+                    'app1' => [
50
+                        'key1' => ['key1', 'value1'],
51
+                        'key22' => ['key22', '31'],
52
+                        'fast_string' => ['fast_string', 'f_value', ValueType::STRING],
53
+                        'lazy_string' => ['lazy_string', 'l_value', ValueType::STRING, true],
54
+                        'fast_string_sensitive' => [
55
+                            'fast_string_sensitive', 'fs_value', ValueType::STRING, false, UserConfig::FLAG_SENSITIVE
56
+                        ],
57
+                        'lazy_string_sensitive' => [
58
+                            'lazy_string_sensitive', 'ls_value', ValueType::STRING, true, UserConfig::FLAG_SENSITIVE
59
+                        ],
60
+                        'fast_int' => ['fast_int', 11, ValueType::INT],
61
+                        'lazy_int' => ['lazy_int', 12, ValueType::INT, true],
62
+                        'fast_int_sensitive' => ['fast_int_sensitive', 2024, ValueType::INT, false, UserConfig::FLAG_SENSITIVE],
63
+                        'lazy_int_sensitive' => ['lazy_int_sensitive', 2048, ValueType::INT, true, UserConfig::FLAG_SENSITIVE],
64
+                        'fast_float' => ['fast_float', 3.14, ValueType::FLOAT],
65
+                        'lazy_float' => ['lazy_float', 3.14159, ValueType::FLOAT, true],
66
+                        'fast_float_sensitive' => [
67
+                            'fast_float_sensitive', 1.41, ValueType::FLOAT, false, UserConfig::FLAG_SENSITIVE
68
+                        ],
69
+                        'lazy_float_sensitive' => [
70
+                            'lazy_float_sensitive', 1.4142, ValueType::FLOAT, true, UserConfig::FLAG_SENSITIVE
71
+                        ],
72
+                        'fast_array' => ['fast_array', ['year' => 2024], ValueType::ARRAY],
73
+                        'lazy_array' => ['lazy_array', ['month' => 'October'], ValueType::ARRAY, true],
74
+                        'fast_array_sensitive' => [
75
+                            'fast_array_sensitive', ['password' => 'pwd'], ValueType::ARRAY, false, UserConfig::FLAG_SENSITIVE
76
+                        ],
77
+                        'lazy_array_sensitive' => [
78
+                            'lazy_array_sensitive', ['password' => 'qwerty'], ValueType::ARRAY, true, UserConfig::FLAG_SENSITIVE
79
+                        ],
80
+                        'fast_boolean' => ['fast_boolean', true, ValueType::BOOL],
81
+                        'fast_boolean_0' => ['fast_boolean_0', false, ValueType::BOOL],
82
+                        'lazy_boolean' => ['lazy_boolean', true, ValueType::BOOL, true],
83
+                        'lazy_boolean_0' => ['lazy_boolean_0', false, ValueType::BOOL, true],
84
+                    ],
85
+                    'app2' => [
86
+                        'key2' => ['key2', 'value2a', ValueType::STRING, false, 0, true],
87
+                        'key3' => ['key3', 'value3', ValueType::STRING, true],
88
+                        'key4' => ['key4', 'value4', ValueType::STRING, false, UserConfig::FLAG_SENSITIVE],
89
+                        'key8' => ['key8', 11, ValueType::INT, false, 0, true],
90
+                        'key9' => ['key9', 'value9a', ValueType::STRING],
91
+                    ],
92
+                    'app3' => [
93
+                        'key1' => ['key1', 'value123'],
94
+                        'key3' => ['key3', 'value3'],
95
+                        'key8' => ['key8', 12, ValueType::INT, false, UserConfig::FLAG_SENSITIVE, true],
96
+                        'key9' => ['key9', 'value9b', ValueType::STRING, false, UserConfig::FLAG_SENSITIVE],
97
+                        'key10' => ['key10', true, ValueType::BOOL, false, 0, true],
98
+                    ],
99
+                    'only-lazy' => [
100
+                        'key1' => ['key1', 'value456', ValueType::STRING, true, 0, true],
101
+                        'key2' => ['key2', 'value2c', ValueType::STRING, true, UserConfig::FLAG_SENSITIVE],
102
+                        'key3' => ['key3', 42, ValueType::INT, true],
103
+                        'key4' => ['key4', 17.42, ValueType::FLOAT, true],
104
+                        'key5' => ['key5', true, ValueType::BOOL, true],
105
+                    ]
106
+                ],
107
+            'user2'
108
+                => [
109
+                    'app1' => [
110
+                        '1' => ['1', 'value1'],
111
+                        '2' => ['2', 'value2', ValueType::STRING, true, UserConfig::FLAG_SENSITIVE],
112
+                        '3' => ['3', 17, ValueType::INT, true],
113
+                        '4' => ['4', 42, ValueType::INT, false, UserConfig::FLAG_SENSITIVE],
114
+                        '5' => ['5', 17.42, ValueType::FLOAT, false],
115
+                        '6' => ['6', true, ValueType::BOOL, false],
116
+                    ],
117
+                    'app2' => [
118
+                        'key2' => ['key2', 'value2b', ValueType::STRING, false, 0, true],
119
+                        'key3' => ['key3', 'value3', ValueType::STRING, true],
120
+                        'key4' => ['key4', 'value4', ValueType::STRING, false, UserConfig::FLAG_SENSITIVE],
121
+                        'key8' => ['key8', 12, ValueType::INT, false, 0, true],
122
+                    ],
123
+                    'app3' => [
124
+                        'key10' => ['key10', false, ValueType::BOOL, false, 0, true],
125
+                    ],
126
+                    'only-lazy' => [
127
+                        'key1' => ['key1', 'value1', ValueType::STRING, true, 0, true]
128
+                    ]
129
+                ],
130
+            'user3'
131
+                => [
132
+                    'app2' => [
133
+                        'key2' => ['key2', 'value2c', ValueType::MIXED, false, 0, true],
134
+                        'key3' => ['key3', 'value3', ValueType::STRING, true, ],
135
+                        'key4' => ['key4', 'value4', ValueType::STRING, false, UserConfig::FLAG_SENSITIVE],
136
+                        'fast_string_sensitive' => [
137
+                            'fast_string_sensitive', 'fs_value', ValueType::STRING, false, UserConfig::FLAG_SENSITIVE
138
+                        ],
139
+                        'lazy_string_sensitive' => [
140
+                            'lazy_string_sensitive', 'ls_value', ValueType::STRING, true, UserConfig::FLAG_SENSITIVE
141
+                        ],
142
+                    ],
143
+                    'only-lazy' => [
144
+                        'key3' => ['key3', 'value3', ValueType::STRING, true]
145
+                    ]
146
+                ],
147
+            'user4'
148
+                => [
149
+                    'app2' => [
150
+                        'key1' => ['key1', 'value1'],
151
+                        'key2' => ['key2', 'value2A', ValueType::MIXED, false, 0, true],
152
+                        'key3' => ['key3', 'value3', ValueType::STRING, true,],
153
+                        'key4' => ['key4', 'value4', ValueType::STRING, false, UserConfig::FLAG_SENSITIVE],
154
+                    ],
155
+                    'app3' => [
156
+                        'key10' => ['key10', true, ValueType::BOOL, false, 0, true],
157
+                    ],
158
+                    'only-lazy' => [
159
+                        'key1' => ['key1', 123, ValueType::INT, true, 0, true]
160
+                    ]
161
+                ],
162
+            'user5'
163
+                => [
164
+                    'app1' => [
165
+                        'key1' => ['key1', 'value1']
166
+                    ],
167
+                    'app2' => [
168
+                        'key8' => ['key8', 12, ValueType::INT, false, 0, true]
169
+                    ],
170
+                    'only-lazy' => [
171
+                        'key1' => ['key1', 'value1', ValueType::STRING, true, 0, true]
172
+                    ]
173
+                ],
174
+
175
+        ];
176
+
177
+    protected function setUp(): void {
178
+        parent::setUp();
179
+
180
+        $this->connection = Server::get(IDBConnection::class);
181
+        $this->config = Server::get(IConfig::class);
182
+        $this->configManager = Server::get(ConfigManager::class);
183
+        $this->presetManager = Server::get(PresetManager::class);
184
+        $this->logger = Server::get(LoggerInterface::class);
185
+        $this->crypto = Server::get(ICrypto::class);
186
+        $this->dispatcher = Server::get(IEventDispatcher::class);
187
+
188
+        // storing current preferences and emptying the data table
189
+        $sql = $this->connection->getQueryBuilder();
190
+        $sql->select('*')
191
+            ->from('preferences');
192
+        $result = $sql->executeQuery();
193
+        $this->originalPreferences = $result->fetchAllAssociative();
194
+        $result->closeCursor();
195
+
196
+        $sql = $this->connection->getQueryBuilder();
197
+        $sql->delete('preferences');
198
+        $sql->executeStatement();
199
+
200
+        $sql = $this->connection->getQueryBuilder();
201
+        $sql->insert('preferences')
202
+            ->values(
203
+                [
204
+                    'userid' => $sql->createParameter('userid'),
205
+                    'appid' => $sql->createParameter('appid'),
206
+                    'configkey' => $sql->createParameter('configkey'),
207
+                    'configvalue' => $sql->createParameter('configvalue'),
208
+                    'type' => $sql->createParameter('type'),
209
+                    'lazy' => $sql->createParameter('lazy'),
210
+                    'flags' => $sql->createParameter('flags'),
211
+                    'indexed' => $sql->createParameter('indexed')
212
+                ]
213
+            );
214
+
215
+        foreach ($this->basePreferences as $userId => $userData) {
216
+            foreach ($userData as $appId => $appData) {
217
+                foreach ($appData as $key => $row) {
218
+                    $value = $row[1];
219
+                    $type = ($row[2] ?? ValueType::MIXED)->value;
220
+
221
+                    if ($type === ValueType::ARRAY->value) {
222
+                        $value = json_encode($value);
223
+                    }
224
+
225
+                    if ($type === ValueType::BOOL->value && $value === false) {
226
+                        $value = '0';
227
+                    }
228
+
229
+                    $flags = $row[4] ?? 0;
230
+                    if ((UserConfig::FLAG_SENSITIVE & $flags) !== 0) {
231
+                        $value = self::invokePrivate(UserConfig::class, 'ENCRYPTION_PREFIX')
232
+                                    . $this->crypto->encrypt((string)$value);
233
+                    } else {
234
+                        $indexed = (($row[5] ?? false) === true) ? $value : '';
235
+                    }
236
+
237
+                    $sql->setParameters(
238
+                        [
239
+                            'userid' => $userId,
240
+                            'appid' => $appId,
241
+                            'configkey' => $row[0],
242
+                            'configvalue' => $value,
243
+                            'type' => $type,
244
+                            'lazy' => (($row[3] ?? false) === true) ? 1 : 0,
245
+                            'flags' => $flags,
246
+                            'indexed' => $indexed ?? ''
247
+                        ]
248
+                    )->executeStatement();
249
+                }
250
+            }
251
+        }
252
+    }
253
+
254
+    protected function tearDown(): void {
255
+        $sql = $this->connection->getQueryBuilder();
256
+        $sql->delete('preferences');
257
+        $sql->executeStatement();
258
+
259
+        $sql = $this->connection->getQueryBuilder();
260
+        $sql->insert('preferences')
261
+            ->values(
262
+                [
263
+                    'userid' => $sql->createParameter('userid'),
264
+                    'appid' => $sql->createParameter('appid'),
265
+                    'configkey' => $sql->createParameter('configkey'),
266
+                    'configvalue' => $sql->createParameter('configvalue'),
267
+                    'lazy' => $sql->createParameter('lazy'),
268
+                    'type' => $sql->createParameter('type'),
269
+                ]
270
+            );
271
+
272
+        foreach ($this->originalPreferences as $key => $configs) {
273
+            $sql->setParameter('userid', $configs['userid'])
274
+                ->setParameter('appid', $configs['appid'])
275
+                ->setParameter('configkey', $configs['configkey'])
276
+                ->setParameter('configvalue', $configs['configvalue'])
277
+                ->setParameter('lazy', ($configs['lazy'] === '1') ? '1' : '0')
278
+                ->setParameter('type', $configs['type']);
279
+            $sql->executeStatement();
280
+        }
281
+
282
+        parent::tearDown();
283
+    }
284
+
285
+    /**
286
+     * @param array $preLoading preload the 'fast' cache for a list of users)
287
+     *
288
+     * @return IUserConfig
289
+     */
290
+    private function generateUserConfig(array $preLoading = []): IUserConfig {
291
+        $userConfig = new UserConfig(
292
+            $this->connection,
293
+            $this->config,
294
+            $this->configManager,
295
+            $this->presetManager,
296
+            $this->logger,
297
+            $this->crypto,
298
+            $this->dispatcher
299
+        );
300
+        $msg = ' generateUserConfig() failed to confirm cache status';
301
+
302
+        // confirm cache status
303
+        $status = $userConfig->statusCache();
304
+        $this->assertSame([], $status['fastLoaded'], $msg);
305
+        $this->assertSame([], $status['lazyLoaded'], $msg);
306
+        $this->assertSame([], $status['fastCache'], $msg);
307
+        $this->assertSame([], $status['lazyCache'], $msg);
308
+        foreach ($preLoading as $preLoadUser) {
309
+            // simple way to initiate the load of non-lazy preferences values in cache
310
+            $userConfig->getValueString($preLoadUser, 'core', 'preload');
311
+
312
+            // confirm cache status
313
+            $status = $userConfig->statusCache();
314
+            $this->assertSame(true, $status['fastLoaded'][$preLoadUser], $msg);
315
+            $this->assertSame(false, $status['lazyLoaded'][$preLoadUser], $msg);
316
+
317
+            $apps = array_values(array_diff(array_keys($this->basePreferences[$preLoadUser]), ['only-lazy']));
318
+            $this->assertEqualsCanonicalizing($apps, array_keys($status['fastCache'][$preLoadUser]), $msg);
319
+            $this->assertSame([], array_keys($status['lazyCache'][$preLoadUser]), $msg);
320
+        }
321
+
322
+        return $userConfig;
323
+    }
324
+
325
+    public function testGetUserIdsEmpty(): void {
326
+        $userConfig = $this->generateUserConfig();
327
+        $this->assertEqualsCanonicalizing(array_keys($this->basePreferences), $userConfig->getUserIds());
328
+    }
329
+
330
+    public function testGetUserIds(): void {
331
+        $userConfig = $this->generateUserConfig();
332
+        $this->assertEqualsCanonicalizing(['user1', 'user2', 'user5'], $userConfig->getUserIds('app1'));
333
+    }
334
+
335
+    public function testGetApps(): void {
336
+        $userConfig = $this->generateUserConfig();
337
+        $this->assertEqualsCanonicalizing(
338
+            array_keys($this->basePreferences['user1']), $userConfig->getApps('user1')
339
+        );
340
+    }
341
+
342
+    public function testGetKeys(): void {
343
+        $userConfig = $this->generateUserConfig(['user1']);
344
+        $this->assertEqualsCanonicalizing(
345
+            array_keys($this->basePreferences['user1']['app1']), $userConfig->getKeys('user1', 'app1')
346
+        );
347
+    }
348
+
349
+    public static function providerHasKey(): array {
350
+        return [
351
+            ['user1', 'app1', 'key1', false, true],
352
+            ['user0', 'app1', 'key1', false, false],
353
+            ['user1', 'app1', 'key1', true, false],
354
+            ['user1', 'app1', 'key0', false, false],
355
+            ['user1', 'app1', 'key0', true, false],
356
+            ['user1', 'app1', 'fast_string_sensitive', false, true],
357
+            ['user1', 'app1', 'lazy_string_sensitive', true, true],
358
+            ['user2', 'only-lazy', 'key1', false, false],
359
+            ['user2', 'only-lazy', 'key1', true, true],
360
+        ];
361
+    }
362
+
363
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerHasKey')]
364
+    public function testHasKey(string $userId, string $appId, string $key, ?bool $lazy, bool $result): void {
365
+        $userConfig = $this->generateUserConfig();
366
+        $this->assertEquals($result, $userConfig->hasKey($userId, $appId, $key, $lazy));
367
+    }
368
+
369
+    public static function providerIsSensitive(): array {
370
+        return [
371
+            ['user1', 'app1', 'key1', false, false, false],
372
+            ['user0', 'app1', 'key1', false, false, true],
373
+            ['user1', 'app1', 'key1', true, false, true],
374
+            ['user1', 'app1', 'key1', null, false, false],
375
+            ['user1', 'app1', 'key0', false, false, true],
376
+            ['user1', 'app1', 'key0', true, false, true],
377
+            ['user1', 'app1', 'fast_string_sensitive', false, true, false],
378
+            ['user1', 'app1', 'lazy_string_sensitive', true, true, false],
379
+            ['user1', 'app1', 'fast_string_sensitive', true, true, true],
380
+            ['user1', 'app1', 'lazy_string_sensitive', false, true, true],
381
+            ['user1', 'app1', 'lazy_string_sensitive', null, true, false],
382
+            ['user2', 'only-lazy', 'key1', false, false, true],
383
+            ['user2', 'only-lazy', 'key1', true, false, false],
384
+            ['user2', 'only-lazy', 'key1', null, false, false],
385
+        ];
386
+    }
387
+
388
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerIsSensitive')]
389
+    public function testIsSensitive(
390
+        string $userId,
391
+        string $appId,
392
+        string $key,
393
+        ?bool $lazy,
394
+        bool $result,
395
+        bool $exception,
396
+    ): void {
397
+        $userConfig = $this->generateUserConfig();
398
+        if ($exception) {
399
+            $this->expectException(UnknownKeyException::class);
400
+        }
401
+
402
+        $this->assertEquals($result, $userConfig->isSensitive($userId, $appId, $key, $lazy));
403
+    }
404
+
405
+    public static function providerIsLazy(): array {
406
+        return [
407
+            ['user1', 'app1', 'key1', false, false],
408
+            ['user0', 'app1', 'key1', false, true],
409
+            ['user1', 'app1', 'key0', false, true],
410
+            ['user1', 'app1', 'key0', false, true],
411
+            ['user1', 'app1', 'fast_string_sensitive', false, false],
412
+            ['user1', 'app1', 'lazy_string_sensitive', true, false],
413
+            ['user2', 'only-lazy', 'key1', true, false],
414
+        ];
415
+    }
416
+
417
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerIsLazy')]
418
+    public function testIsLazy(
419
+        string $userId,
420
+        string $appId,
421
+        string $key,
422
+        bool $result,
423
+        bool $exception,
424
+    ): void {
425
+        $userConfig = $this->generateUserConfig();
426
+        if ($exception) {
427
+            $this->expectException(UnknownKeyException::class);
428
+        }
429
+
430
+        $this->assertEquals($result, $userConfig->isLazy($userId, $appId, $key));
431
+    }
432
+
433
+    public static function providerGetValues(): array {
434
+        return [
435
+            [
436
+                'user1', 'app1', '', true,
437
+                [
438
+                    'fast_array' => ['year' => 2024],
439
+                    'fast_array_sensitive' => '***REMOVED SENSITIVE VALUE***',
440
+                    'fast_boolean' => true,
441
+                    'fast_boolean_0' => false,
442
+                    'fast_float' => 3.14,
443
+                    'fast_float_sensitive' => '***REMOVED SENSITIVE VALUE***',
444
+                    'fast_int' => 11,
445
+                    'fast_int_sensitive' => '***REMOVED SENSITIVE VALUE***',
446
+                    'fast_string' => 'f_value',
447
+                    'fast_string_sensitive' => '***REMOVED SENSITIVE VALUE***',
448
+                    'key1' => 'value1',
449
+                    'key22' => '31',
450
+                    'lazy_array' => ['month' => 'October'],
451
+                    'lazy_array_sensitive' => '***REMOVED SENSITIVE VALUE***',
452
+                    'lazy_boolean' => true,
453
+                    'lazy_boolean_0' => false,
454
+                    'lazy_float' => 3.14159,
455
+                    'lazy_float_sensitive' => '***REMOVED SENSITIVE VALUE***',
456
+                    'lazy_int' => 12,
457
+                    'lazy_int_sensitive' => '***REMOVED SENSITIVE VALUE***',
458
+                    'lazy_string' => 'l_value',
459
+                    'lazy_string_sensitive' => '***REMOVED SENSITIVE VALUE***',
460
+                ]
461
+            ],
462
+            [
463
+                'user1', 'app1', '', false,
464
+                [
465
+                    'fast_array' => ['year' => 2024],
466
+                    'fast_array_sensitive' => ['password' => 'pwd'],
467
+                    'fast_boolean' => true,
468
+                    'fast_boolean_0' => false,
469
+                    'fast_float' => 3.14,
470
+                    'fast_float_sensitive' => 1.41,
471
+                    'fast_int' => 11,
472
+                    'fast_int_sensitive' => 2024,
473
+                    'fast_string' => 'f_value',
474
+                    'fast_string_sensitive' => 'fs_value',
475
+                    'key1' => 'value1',
476
+                    'key22' => '31',
477
+                    'lazy_array' => ['month' => 'October'],
478
+                    'lazy_array_sensitive' => ['password' => 'qwerty'],
479
+                    'lazy_boolean' => true,
480
+                    'lazy_boolean_0' => false,
481
+                    'lazy_float' => 3.14159,
482
+                    'lazy_float_sensitive' => 1.4142,
483
+                    'lazy_int' => 12,
484
+                    'lazy_int_sensitive' => 2048,
485
+                    'lazy_string' => 'l_value',
486
+                    'lazy_string_sensitive' => 'ls_value'
487
+                ]
488
+            ],
489
+            [
490
+                'user1', 'app1', 'fast_', true,
491
+                [
492
+                    'fast_array' => ['year' => 2024],
493
+                    'fast_array_sensitive' => '***REMOVED SENSITIVE VALUE***',
494
+                    'fast_boolean' => true,
495
+                    'fast_boolean_0' => false,
496
+                    'fast_float' => 3.14,
497
+                    'fast_float_sensitive' => '***REMOVED SENSITIVE VALUE***',
498
+                    'fast_int' => 11,
499
+                    'fast_int_sensitive' => '***REMOVED SENSITIVE VALUE***',
500
+                    'fast_string' => 'f_value',
501
+                    'fast_string_sensitive' => '***REMOVED SENSITIVE VALUE***',
502
+                ]
503
+            ],
504
+            [
505
+                'user1', 'app1', 'fast_', false,
506
+                [
507
+                    'fast_array' => ['year' => 2024],
508
+                    'fast_array_sensitive' => ['password' => 'pwd'],
509
+                    'fast_boolean' => true,
510
+                    'fast_boolean_0' => false,
511
+                    'fast_float' => 3.14,
512
+                    'fast_float_sensitive' => 1.41,
513
+                    'fast_int' => 11,
514
+                    'fast_int_sensitive' => 2024,
515
+                    'fast_string' => 'f_value',
516
+                    'fast_string_sensitive' => 'fs_value',
517
+                ]
518
+            ],
519
+            [
520
+                'user1', 'app1', 'key1', true,
521
+                [
522
+                    'key1' => 'value1',
523
+                ]
524
+            ],
525
+            [
526
+                'user2', 'app1', '', false,
527
+                [
528
+                    '1' => 'value1',
529
+                    '4' => 42,
530
+                    '5' => 17.42,
531
+                    '6' => true,
532
+                    '2' => 'value2',
533
+                    '3' => 17,
534
+                ]
535
+            ],
536
+            [
537
+                'user2', 'app1', '', true,
538
+                [
539
+                    '1' => 'value1',
540
+                    '4' => '***REMOVED SENSITIVE VALUE***',
541
+                    '5' => 17.42,
542
+                    '6' => true,
543
+                    '2' => '***REMOVED SENSITIVE VALUE***',
544
+                    '3' => 17,
545
+                ]
546
+            ],
547
+        ];
548
+    }
549
+
550
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetValues')]
551
+    public function testGetValues(
552
+        string $userId,
553
+        string $appId,
554
+        string $prefix,
555
+        bool $filtered,
556
+        array $result,
557
+    ): void {
558
+        $userConfig = $this->generateUserConfig();
559
+        $this->assertJsonStringEqualsJsonString(
560
+            json_encode($result), json_encode($userConfig->getValues($userId, $appId, $prefix, $filtered))
561
+        );
562
+    }
563
+
564
+    public static function providerGetAllValues(): array {
565
+        return [
566
+            [
567
+                'user2', false,
568
+                [
569
+                    'app1' => [
570
+                        '1' => 'value1',
571
+                        '4' => 42,
572
+                        '5' => 17.42,
573
+                        '6' => true,
574
+                        '2' => 'value2',
575
+                        '3' => 17,
576
+                    ],
577
+                    'app2' => [
578
+                        'key2' => 'value2b',
579
+                        'key3' => 'value3',
580
+                        'key4' => 'value4',
581
+                        'key8' => 12,
582
+                    ],
583
+                    'app3' => [
584
+                        'key10' => false,
585
+                    ],
586
+                    'only-lazy' => [
587
+                        'key1' => 'value1',
588
+                    ]
589
+                ],
590
+            ],
591
+            [
592
+                'user2', true,
593
+                [
594
+                    'app1' => [
595
+                        '1' => 'value1',
596
+                        '4' => '***REMOVED SENSITIVE VALUE***',
597
+                        '5' => 17.42,
598
+                        '6' => true,
599
+                        '2' => '***REMOVED SENSITIVE VALUE***',
600
+                        '3' => 17,
601
+                    ],
602
+                    'app2' => [
603
+                        'key2' => 'value2b',
604
+                        'key3' => 'value3',
605
+                        'key4' => '***REMOVED SENSITIVE VALUE***',
606
+                        'key8' => 12,
607
+                    ],
608
+                    'app3' => [
609
+                        'key10' => false,
610
+                    ],
611
+                    'only-lazy' => [
612
+                        'key1' => 'value1',
613
+                    ]
614
+                ],
615
+            ],
616
+            [
617
+                'user3', true,
618
+                [
619
+                    'app2' => [
620
+                        'key2' => 'value2c',
621
+                        'key3' => 'value3',
622
+                        'key4' => '***REMOVED SENSITIVE VALUE***',
623
+                        'fast_string_sensitive' => '***REMOVED SENSITIVE VALUE***',
624
+                        'lazy_string_sensitive' => '***REMOVED SENSITIVE VALUE***',
625
+                    ],
626
+                    'only-lazy' => [
627
+                        'key3' => 'value3',
628
+                    ]
629
+                ],
630
+            ],
631
+            [
632
+                'user3', false,
633
+                [
634
+                    'app2' => [
635
+                        'key2' => 'value2c',
636
+                        'key3' => 'value3',
637
+                        'key4' => 'value4',
638
+                        'fast_string_sensitive' => 'fs_value',
639
+                        'lazy_string_sensitive' => 'ls_value',
640
+                    ],
641
+                    'only-lazy' => [
642
+                        'key3' => 'value3',
643
+                    ]
644
+                ],
645
+            ],
646
+        ];
647
+    }
648
+
649
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetAllValues')]
650
+    public function testGetAllValues(
651
+        string $userId,
652
+        bool $filtered,
653
+        array $result,
654
+    ): void {
655
+        $userConfig = $this->generateUserConfig();
656
+        $this->assertEqualsCanonicalizing($result, $userConfig->getAllValues($userId, $filtered));
657
+    }
658
+
659
+    public static function providerSearchValuesByApps(): array {
660
+        return [
661
+            [
662
+                'user1', 'key1', false, null,
663
+                [
664
+                    'app1' => 'value1',
665
+                    'app3' => 'value123'
666
+                ]
667
+            ],
668
+            [
669
+                'user1', 'key1', true, null,
670
+                [
671
+                    'only-lazy' => 'value456'
672
+                ]
673
+            ],
674
+            [
675
+                'user1', 'key8', false, null,
676
+                [
677
+                    'app2' => 11,
678
+                    'app3' => 12,
679
+                ]
680
+            ],
681
+            [
682
+                'user1', 'key9', false, ValueType::INT,
683
+                [
684
+                    'app2' => 0,
685
+                    'app3' => 0,
686
+                ]
687
+            ]
688
+        ];
689
+    }
690
+
691
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerSearchValuesByApps')]
692
+    public function testSearchValuesByApps(
693
+        string $userId,
694
+        string $key,
695
+        bool $lazy,
696
+        ?ValueType $typedAs,
697
+        array $result,
698
+    ): void {
699
+        $userConfig = $this->generateUserConfig();
700
+        $this->assertEquals($result, $userConfig->getValuesByApps($userId, $key, $lazy, $typedAs));
701
+    }
702
+
703
+    public static function providerSearchValuesByUsers(): array {
704
+        return [
705
+            [
706
+                'app2', 'key2', null, null,
707
+                [
708
+                    'user1' => 'value2a',
709
+                    'user2' => 'value2b',
710
+                    'user3' => 'value2c',
711
+                    'user4' => 'value2A'
712
+                ]
713
+            ],
714
+            [
715
+                'app2', 'key2', null, ['user1', 'user3'],
716
+                [
717
+                    'user1' => 'value2a',
718
+                    'user3' => 'value2c',
719
+                ]
720
+            ],
721
+            [
722
+                'app2', 'key2', ValueType::INT, ['user1', 'user3'],
723
+                [
724
+                    'user1' => 0,
725
+                    'user3' => 0,
726
+                ]
727
+            ],
728
+            [
729
+                'app2', 'key8', ValueType::INT, null,
730
+                [
731
+                    'user1' => 11,
732
+                    'user2' => 12,
733
+                    'user5' => 12,
734
+                ]
735
+            ],
736
+        ];
737
+    }
738
+
739
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerSearchValuesByUsers')]
740
+    public function testSearchValuesByUsers(
741
+        string $app,
742
+        string $key,
743
+        ?ValueType $typedAs,
744
+        ?array $userIds,
745
+        array $result,
746
+    ): void {
747
+        $userConfig = $this->generateUserConfig();
748
+        $this->assertEqualsCanonicalizing(
749
+            $result, $userConfig->getValuesByUsers($app, $key, $typedAs, $userIds)
750
+        );
751
+    }
752
+
753
+    public static function providerSearchValuesByValueString(): array {
754
+        return [
755
+            ['app2', 'key2', 'value2a', false, ['user1']],
756
+            ['app2', 'key2', 'value2A', false, ['user4']],
757
+            ['app2', 'key2', 'value2A', true, ['user1', 'user4']]
758
+        ];
759
+    }
760
+
761
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerSearchValuesByValueString')]
762
+    public function testSearchUsersByValueString(
763
+        string $app,
764
+        string $key,
765
+        string|array $value,
766
+        bool $ci,
767
+        array $result,
768
+    ): void {
769
+        $userConfig = $this->generateUserConfig();
770
+        $this->assertEqualsCanonicalizing($result, iterator_to_array($userConfig->searchUsersByValueString($app, $key, $value, $ci)));
771
+    }
772
+
773
+    public static function providerSearchValuesByValueInt(): array {
774
+        return [
775
+            ['app3', 'key8', 12, []], // sensitive value, cannot search
776
+            ['app2', 'key8', 12, ['user2', 'user5']], // sensitive value, cannot search
777
+            ['only-lazy', 'key1', 123, ['user4']],
778
+        ];
779
+    }
780
+
781
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerSearchValuesByValueInt')]
782
+    public function testSearchUsersByValueInt(
783
+        string $app,
784
+        string $key,
785
+        int $value,
786
+        array $result,
787
+    ): void {
788
+        $userConfig = $this->generateUserConfig();
789
+        $this->assertEqualsCanonicalizing($result, iterator_to_array($userConfig->searchUsersByValueInt($app, $key, $value)));
790
+    }
791
+
792
+    public static function providerSearchValuesByValues(): array {
793
+        return [
794
+            ['app2', 'key2', ['value2a', 'value2b'], ['user1', 'user2']],
795
+            ['app2', 'key2', ['value2a', 'value2c'], ['user1', 'user3']],
796
+        ];
797
+    }
798
+
799
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerSearchValuesByValues')]
800
+    public function testSearchUsersByValues(
801
+        string $app,
802
+        string $key,
803
+        array $values,
804
+        array $result,
805
+    ): void {
806
+        $userConfig = $this->generateUserConfig();
807
+        $this->assertEqualsCanonicalizing($result, iterator_to_array($userConfig->searchUsersByValues($app, $key, $values)));
808
+    }
809
+
810
+    public static function providerSearchValuesByValueBool(): array {
811
+        return [
812
+            ['app3', 'key10', true, ['user1', 'user4']],
813
+            ['app3', 'key10', false, ['user2']],
814
+        ];
815
+    }
816
+
817
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerSearchValuesByValueBool')]
818
+    public function testSearchUsersByValueBool(
819
+        string $app,
820
+        string $key,
821
+        bool $value,
822
+        array $result,
823
+    ): void {
824
+        $userConfig = $this->generateUserConfig();
825
+        $this->assertEqualsCanonicalizing($result, iterator_to_array($userConfig->searchUsersByValueBool($app, $key, $value)));
826
+    }
827
+
828
+    public static function providerGetValueMixed(): array {
829
+        return [
830
+            [
831
+                ['user1'], 'user1', 'app1', 'key0', 'default_because_unknown_key', true,
832
+                'default_because_unknown_key'
833
+            ],
834
+            [
835
+                null, 'user1', 'app1', 'key0', 'default_because_unknown_key', true,
836
+                'default_because_unknown_key'
837
+            ],
838
+            [
839
+                ['user1'], 'user1', 'app1', 'key0', 'default_because_unknown_key', false,
840
+                'default_because_unknown_key'
841
+            ],
842
+            [
843
+                null, 'user1', 'app1', 'key0', 'default_because_unknown_key', false,
844
+                'default_because_unknown_key'
845
+            ],
846
+            [['user1'], 'user1', 'app1', 'fast_string', 'default_because_unknown_key', false, 'f_value'],
847
+            [null, 'user1', 'app1', 'fast_string', 'default_because_unknown_key', false, 'f_value'],
848
+            [['user1'], 'user1', 'app1', 'fast_string', 'default_because_unknown_key', true, 'f_value'],
849
+            // because non-lazy are already loaded
850
+            [
851
+                null, 'user1', 'app1', 'fast_string', 'default_because_unknown_key', true,
852
+                'default_because_unknown_key'
853
+            ],
854
+            [
855
+                ['user1'], 'user1', 'app1', 'lazy_string', 'default_because_unknown_key', false,
856
+                'default_because_unknown_key'
857
+            ],
858
+            [
859
+                null, 'user1', 'app1', 'lazy_string', 'default_because_unknown_key', false,
860
+                'default_because_unknown_key'
861
+            ],
862
+            [['user1'], 'user1', 'app1', 'lazy_string', 'default_because_unknown_key', true, 'l_value'],
863
+            [null, 'user1', 'app1', 'lazy_string', 'default_because_unknown_key', true, 'l_value'],
864
+            [
865
+                ['user1'], 'user1', 'app1', 'fast_string_sensitive', 'default_because_unknown_key', false,
866
+                'fs_value'
867
+            ],
868
+            [
869
+                null, 'user1', 'app1', 'fast_string_sensitive', 'default_because_unknown_key', false,
870
+                'fs_value'
871
+            ],
872
+            [
873
+                ['user1'], 'user1', 'app1', 'fast_string_sensitive', 'default_because_unknown_key', true,
874
+                'fs_value'
875
+            ],
876
+            [
877
+                null, 'user1', 'app1', 'fast_string_sensitive', 'default_because_unknown_key', true,
878
+                'default_because_unknown_key'
879
+            ],
880
+            [
881
+                ['user1'], 'user1', 'app1', 'lazy_string_sensitive', 'default_because_unknown_key', false,
882
+                'default_because_unknown_key'
883
+            ],
884
+            [
885
+                null, 'user1', 'app1', 'lazy_string_sensitive', 'default_because_unknown_key', false,
886
+                'default_because_unknown_key'
887
+            ],
888
+            [
889
+                ['user1'], 'user1', 'app1', 'lazy_string_sensitive', 'default_because_unknown_key', true,
890
+                'ls_value'
891
+            ],
892
+            [null, 'user1', 'app1', 'lazy_string_sensitive', 'default_because_unknown_key', true, 'ls_value'],
893
+        ];
894
+    }
895
+
896
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueMixed')]
897
+    public function testGetValueMixed(
898
+        ?array $preload,
899
+        string $userId,
900
+        string $app,
901
+        string $key,
902
+        string $default,
903
+        bool $lazy,
904
+        string $result,
905
+    ): void {
906
+        $userConfig = $this->generateUserConfig($preload ?? []);
907
+        $this->assertEquals($result, $userConfig->getValueMixed($userId, $app, $key, $default, $lazy));
908
+    }
909
+
910
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueMixed')]
911
+    public function testGetValueString(
912
+        ?array $preload,
913
+        string $userId,
914
+        string $app,
915
+        string $key,
916
+        string $default,
917
+        bool $lazy,
918
+        string $result,
919
+    ): void {
920
+        $userConfig = $this->generateUserConfig($preload ?? []);
921
+        $this->assertEquals($result, $userConfig->getValueString($userId, $app, $key, $default, $lazy));
922
+    }
923
+
924
+    public static function providerGetValueInt(): array {
925
+        return [
926
+            [['user1'], 'user1', 'app1', 'key0', 54321, true, 54321],
927
+            [null, 'user1', 'app1', 'key0', 54321, true, 54321],
928
+            [['user1'], 'user1', 'app1', 'key0', 54321, false, 54321],
929
+            [null, 'user1', 'app1', 'key0', 54321, false, 54321],
930
+            [null, 'user1', 'app1', 'key22', 54321, false, 31],
931
+            [['user1'], 'user1', 'app1', 'fast_int', 54321, false, 11],
932
+            [null, 'user1', 'app1', 'fast_int', 54321, false, 11],
933
+            [['user1'], 'user1', 'app1', 'fast_int', 54321, true, 11],
934
+            [null, 'user1', 'app1', 'fast_int', 54321, true, 54321],
935
+            [['user1'], 'user1', 'app1', 'fast_int_sensitive', 54321, false, 2024],
936
+            [null, 'user1', 'app1', 'fast_int_sensitive', 54321, false, 2024],
937
+            [['user1'], 'user1', 'app1', 'fast_int_sensitive', 54321, true, 2024],
938
+            [null, 'user1', 'app1', 'fast_int_sensitive', 54321, true, 54321],
939
+            [['user1'], 'user1', 'app1', 'lazy_int', 54321, false, 54321],
940
+            [null, 'user1', 'app1', 'lazy_int', 54321, false, 54321],
941
+            [['user1'], 'user1', 'app1', 'lazy_int', 54321, true, 12],
942
+            [null, 'user1', 'app1', 'lazy_int', 54321, true, 12],
943
+            [['user1'], 'user1', 'app1', 'lazy_int_sensitive', 54321, false, 54321],
944
+            [null, 'user1', 'app1', 'lazy_int_sensitive', 54321, false, 54321],
945
+            [['user1'], 'user1', 'app1', 'lazy_int_sensitive', 54321, true, 2048],
946
+            [null, 'user1', 'app1', 'lazy_int_sensitive', 54321, true, 2048],
947
+        ];
948
+    }
949
+
950
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueInt')]
951
+    public function testGetValueInt(
952
+        ?array $preload,
953
+        string $userId,
954
+        string $app,
955
+        string $key,
956
+        int $default,
957
+        bool $lazy,
958
+        int $result,
959
+    ): void {
960
+        $userConfig = $this->generateUserConfig($preload ?? []);
961
+        $this->assertEquals($result, $userConfig->getValueInt($userId, $app, $key, $default, $lazy));
962
+    }
963
+
964
+    public static function providerGetValueFloat(): array {
965
+        return [
966
+            [['user1'], 'user1', 'app1', 'key0', 54.321, true, 54.321],
967
+            [null, 'user1', 'app1', 'key0', 54.321, true, 54.321],
968
+            [['user1'], 'user1', 'app1', 'key0', 54.321, false, 54.321],
969
+            [null, 'user1', 'app1', 'key0', 54.321, false, 54.321],
970
+            [['user1'], 'user1', 'app1', 'fast_float', 54.321, false, 3.14],
971
+            [null, 'user1', 'app1', 'fast_float', 54.321, false, 3.14],
972
+            [['user1'], 'user1', 'app1', 'fast_float', 54.321, true, 3.14],
973
+            [null, 'user1', 'app1', 'fast_float', 54.321, true, 54.321],
974
+            [['user1'], 'user1', 'app1', 'fast_float_sensitive', 54.321, false, 1.41],
975
+            [null, 'user1', 'app1', 'fast_float_sensitive', 54.321, false, 1.41],
976
+            [['user1'], 'user1', 'app1', 'fast_float_sensitive', 54.321, true, 1.41],
977
+            [null, 'user1', 'app1', 'fast_float_sensitive', 54.321, true, 54.321],
978
+            [['user1'], 'user1', 'app1', 'lazy_float', 54.321, false, 54.321],
979
+            [null, 'user1', 'app1', 'lazy_float', 54.321, false, 54.321],
980
+            [['user1'], 'user1', 'app1', 'lazy_float', 54.321, true, 3.14159],
981
+            [null, 'user1', 'app1', 'lazy_float', 54.321, true, 3.14159],
982
+            [['user1'], 'user1', 'app1', 'lazy_float_sensitive', 54.321, false, 54.321],
983
+            [null, 'user1', 'app1', 'lazy_float_sensitive', 54.321, false, 54.321],
984
+            [['user1'], 'user1', 'app1', 'lazy_float_sensitive', 54.321, true, 1.4142],
985
+            [null, 'user1', 'app1', 'lazy_float_sensitive', 54.321, true, 1.4142],
986
+        ];
987
+    }
988
+
989
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueFloat')]
990
+    public function testGetValueFloat(
991
+        ?array $preload,
992
+        string $userId,
993
+        string $app,
994
+        string $key,
995
+        float $default,
996
+        bool $lazy,
997
+        float $result,
998
+    ): void {
999
+        $userConfig = $this->generateUserConfig($preload ?? []);
1000
+        $this->assertEquals($result, $userConfig->getValueFloat($userId, $app, $key, $default, $lazy));
1001
+    }
1002
+
1003
+    public static function providerGetValueBool(): array {
1004
+        return [
1005
+            [['user1'], 'user1', 'app1', 'key0', false, true, false],
1006
+            [null, 'user1', 'app1', 'key0', false, true, false],
1007
+            [['user1'], 'user1', 'app1', 'key0', true, true, true],
1008
+            [null, 'user1', 'app1', 'key0', true, true, true],
1009
+            [['user1'], 'user1', 'app1', 'key0', false, false, false],
1010
+            [null, 'user1', 'app1', 'key0', false, false, false],
1011
+            [['user1'], 'user1', 'app1', 'key0', true, false, true],
1012
+            [null, 'user1', 'app1', 'key0', true, false, true],
1013
+            [['user1'], 'user1', 'app1', 'fast_boolean', false, false, true],
1014
+            [null, 'user1', 'app1', 'fast_boolean', false, false, true],
1015
+            [['user1'], 'user1', 'app1', 'fast_boolean_0', false, false, false],
1016
+            [null, 'user1', 'app1', 'fast_boolean_0', false, false, false],
1017
+            [['user1'], 'user1', 'app1', 'fast_boolean', true, false, true],
1018
+            [null, 'user1', 'app1', 'fast_boolean', true, false, true],
1019
+            [['user1'], 'user1', 'app1', 'fast_boolean_0', true, false, false],
1020
+            [null, 'user1', 'app1', 'fast_boolean_0', true, false, false],
1021
+            [['user1'], 'user1', 'app1', 'fast_boolean', false, true, true],
1022
+            [null, 'user1', 'app1', 'fast_boolean', false, true, false],
1023
+            [['user1'], 'user1', 'app1', 'fast_boolean_0', false, true, false],
1024
+            [null, 'user1', 'app1', 'fast_boolean_0', false, true, false],
1025
+            [['user1'], 'user1', 'app1', 'fast_boolean', true, true, true],
1026
+            [null, 'user1', 'app1', 'fast_boolean', true, true, true],
1027
+            [['user1'], 'user1', 'app1', 'fast_boolean_0', true, true, false],
1028
+            [null, 'user1', 'app1', 'fast_boolean_0', true, true, true],
1029
+            [['user1'], 'user1', 'app1', 'lazy_boolean', false, false, false],
1030
+            [null, 'user1', 'app1', 'lazy_boolean', false, false, false],
1031
+            [['user1'], 'user1', 'app1', 'lazy_boolean_0', false, false, false],
1032
+            [null, 'user1', 'app1', 'lazy_boolean_0', false, false, false],
1033
+            [['user1'], 'user1', 'app1', 'lazy_boolean', true, false, true],
1034
+            [null, 'user1', 'app1', 'lazy_boolean', true, false, true],
1035
+            [['user1'], 'user1', 'app1', 'lazy_boolean_0', true, false, true],
1036
+            [null, 'user1', 'app1', 'lazy_boolean_0', true, false, true],
1037
+            [['user1'], 'user1', 'app1', 'lazy_boolean', false, true, true],
1038
+            [null, 'user1', 'app1', 'lazy_boolean', false, true, true],
1039
+            [['user1'], 'user1', 'app1', 'lazy_boolean_0', false, true, false],
1040
+            [null, 'user1', 'app1', 'lazy_boolean_0', false, true, false],
1041
+            [['user1'], 'user1', 'app1', 'lazy_boolean', true, true, true],
1042
+            [null, 'user1', 'app1', 'lazy_boolean', true, true, true],
1043
+            [['user1'], 'user1', 'app1', 'lazy_boolean_0', true, true, false],
1044
+            [null, 'user1', 'app1', 'lazy_boolean_0', true, true, false],
1045
+        ];
1046
+    }
1047
+
1048
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueBool')]
1049
+    public function testGetValueBool(
1050
+        ?array $preload,
1051
+        string $userId,
1052
+        string $app,
1053
+        string $key,
1054
+        bool $default,
1055
+        bool $lazy,
1056
+        bool $result,
1057
+    ): void {
1058
+        $userConfig = $this->generateUserConfig($preload ?? []);
1059
+        $this->assertEquals($result, $userConfig->getValueBool($userId, $app, $key, $default, $lazy));
1060
+    }
1061
+
1062
+    public static function providerGetValueArray(): array {
1063
+        return [
1064
+            [
1065
+                ['user1'], 'user1', 'app1', 'key0', ['default_because_unknown_key'], true,
1066
+                ['default_because_unknown_key']
1067
+            ],
1068
+            [
1069
+                null, 'user1', 'app1', 'key0', ['default_because_unknown_key'], true,
1070
+                ['default_because_unknown_key']
1071
+            ],
1072
+            [
1073
+                ['user1'], 'user1', 'app1', 'key0', ['default_because_unknown_key'], false,
1074
+                ['default_because_unknown_key']
1075
+            ],
1076
+            [
1077
+                null, 'user1', 'app1', 'key0', ['default_because_unknown_key'], false,
1078
+                ['default_because_unknown_key']
1079
+            ],
1080
+        ];
1081
+    }
1082
+
1083
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueArray')]
1084
+    public function testGetValueArray(
1085
+        ?array $preload,
1086
+        string $userId,
1087
+        string $app,
1088
+        string $key,
1089
+        array $default,
1090
+        bool $lazy,
1091
+        array $result,
1092
+    ): void {
1093
+        $userConfig = $this->generateUserConfig($preload ?? []);
1094
+        $this->assertEqualsCanonicalizing(
1095
+            $result, $userConfig->getValueArray($userId, $app, $key, $default, $lazy)
1096
+        );
1097
+    }
1098
+
1099
+    public static function providerGetValueType(): array {
1100
+        return [
1101
+            [null, 'user1', 'app1', 'key1', false, ValueType::MIXED],
1102
+            [null, 'user1', 'app1', 'key1', true, null, UnknownKeyException::class],
1103
+            [null, 'user1', 'app1', 'fast_string', true, ValueType::STRING, UnknownKeyException::class],
1104
+            [['user1'], 'user1', 'app1', 'fast_string', true, ValueType::STRING],
1105
+            [null, 'user1', 'app1', 'fast_string', false, ValueType::STRING],
1106
+            [null, 'user1', 'app1', 'lazy_string', true, ValueType::STRING],
1107
+            [null, 'user1', 'app1', 'lazy_string', false, ValueType::STRING, UnknownKeyException::class],
1108
+            [
1109
+                null, 'user1', 'app1', 'fast_string_sensitive', true, ValueType::STRING,
1110
+                UnknownKeyException::class
1111
+            ],
1112
+            [['user1'], 'user1', 'app1', 'fast_string_sensitive', true, ValueType::STRING],
1113
+            [null, 'user1', 'app1', 'fast_string_sensitive', false, ValueType::STRING],
1114
+            [null, 'user1', 'app1', 'lazy_string_sensitive', true, ValueType::STRING],
1115
+            [
1116
+                null, 'user1', 'app1', 'lazy_string_sensitive', false, ValueType::STRING,
1117
+                UnknownKeyException::class
1118
+            ],
1119
+            [null, 'user1', 'app1', 'fast_int', true, ValueType::INT, UnknownKeyException::class],
1120
+            [['user1'], 'user1', 'app1', 'fast_int', true, ValueType::INT],
1121
+            [null, 'user1', 'app1', 'fast_int', false, ValueType::INT],
1122
+            [null, 'user1', 'app1', 'lazy_int', true, ValueType::INT],
1123
+            [null, 'user1', 'app1', 'lazy_int', false, ValueType::INT, UnknownKeyException::class],
1124
+            [null, 'user1', 'app1', 'fast_float', true, ValueType::FLOAT, UnknownKeyException::class],
1125
+            [['user1'], 'user1', 'app1', 'fast_float', true, ValueType::FLOAT],
1126
+            [null, 'user1', 'app1', 'fast_float', false, ValueType::FLOAT],
1127
+            [null, 'user1', 'app1', 'lazy_float', true, ValueType::FLOAT],
1128
+            [null, 'user1', 'app1', 'lazy_float', false, ValueType::FLOAT, UnknownKeyException::class],
1129
+            [null, 'user1', 'app1', 'fast_boolean', true, ValueType::BOOL, UnknownKeyException::class],
1130
+            [['user1'], 'user1', 'app1', 'fast_boolean', true, ValueType::BOOL],
1131
+            [null, 'user1', 'app1', 'fast_boolean', false, ValueType::BOOL],
1132
+            [null, 'user1', 'app1', 'lazy_boolean', true, ValueType::BOOL],
1133
+            [null, 'user1', 'app1', 'lazy_boolean', false, ValueType::BOOL, UnknownKeyException::class],
1134
+        ];
1135
+    }
1136
+
1137
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetValueType')]
1138
+    public function testGetValueType(
1139
+        ?array $preload,
1140
+        string $userId,
1141
+        string $app,
1142
+        string $key,
1143
+        ?bool $lazy,
1144
+        ?ValueType $result,
1145
+        ?string $exception = null,
1146
+    ): void {
1147
+        $userConfig = $this->generateUserConfig($preload ?? []);
1148
+        if ($exception !== null) {
1149
+            $this->expectException($exception);
1150
+        }
1151
+
1152
+        $type = $userConfig->getValueType($userId, $app, $key, $lazy);
1153
+        if ($exception === null) {
1154
+            $this->assertEquals($result->value, $type->value);
1155
+        }
1156
+    }
1157
+
1158
+    public static function providerSetValueMixed(): array {
1159
+        return [
1160
+            [null, 'user1', 'app1', 'key1', 'value', false, false, true],
1161
+            [null, 'user1', 'app1', 'key1', '12345', true, false, true],
1162
+            [null, 'user1', 'app1', 'key1', '12345', true, true, true],
1163
+            [null, 'user1', 'app1', 'key1', 'value1', false, false, false],
1164
+            [null, 'user1', 'app1', 'key1', 'value1', true, false, true],
1165
+            [null, 'user1', 'app1', 'key1', 'value1', false, true, true],
1166
+            [
1167
+                null, 'user1', 'app1', 'fast_string', 'f_value_2', false, false, true,
1168
+                TypeConflictException::class
1169
+            ],
1170
+            [
1171
+                null, 'user1', 'app1', 'fast_string', 'f_value', true, false, true,
1172
+                TypeConflictException::class
1173
+            ],
1174
+            [null, 'user1', 'app1', 'fast_string', 'f_value', true, true, true, TypeConflictException::class],
1175
+            [null, 'user1', 'app1', 'fast_int', 'n_value', false, false, true, TypeConflictException::class],
1176
+            [
1177
+                null, 'user1', 'app1', 'fast_float', 'n_value', false, false, true,
1178
+                TypeConflictException::class
1179
+            ],
1180
+            [
1181
+                null, 'user1', 'app1', 'lazy_string', 'l_value_2', false, false, true,
1182
+                TypeConflictException::class
1183
+            ],
1184
+            [null, 'user1', 'app1', 'lazy_string', 'l_value', true, false, false],
1185
+            [null, 'user1', 'app1', 'lazy_string', 'l_value', true, true, true, TypeConflictException::class],
1186
+            [null, 'user1', 'app1', 'lazy_int', 'l_value', false, false, true, TypeConflictException::class],
1187
+            [
1188
+                null, 'user1', 'app1', 'lazy_float', 'l_value', false, false, true,
1189
+                TypeConflictException::class
1190
+            ],
1191
+        ];
1192
+    }
1193
+
1194
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerSetValueMixed')]
1195
+    public function testSetValueMixed(
1196
+        ?array $preload,
1197
+        string $userId,
1198
+        string $app,
1199
+        string $key,
1200
+        string $value,
1201
+        bool $lazy,
1202
+        bool $sensitive,
1203
+        bool $result,
1204
+        ?string $exception = null,
1205
+    ): void {
1206
+        $userConfig = $this->generateUserConfig($preload ?? []);
1207
+        if ($exception !== null) {
1208
+            $this->expectException($exception);
1209
+        }
1210
+
1211
+        $edited = $userConfig->setValueMixed($userId, $app, $key, $value, $lazy, ($sensitive) ? 1 : 0);
1212
+
1213
+        if ($exception === null) {
1214
+            $this->assertEquals($result, $edited);
1215
+        }
1216
+    }
1217
+
1218
+    /**
1219
+     * This test needs to stay! Emails are expected to be lowercase due to performance reasons.
1220
+     * This way we can skip the expensive casing change on the database.
1221
+     */
1222
+    public function testSetValueMixedWithSettingsEmail(): void {
1223
+        $userConfig = $this->generateUserConfig();
1224
+
1225
+        $edited = $userConfig->setValueMixed('user1', 'settings', 'email', '[email protected]');
1226
+        $this->assertTrue($edited);
1227
+
1228
+        $actual = $userConfig->getValueMixed('user1', 'settings', 'email');
1229
+        $this->assertEquals('[email protected]', $actual);
1230
+    }
1231
+
1232
+    public static function providerSetValueString(): array {
1233
+        return [
1234
+            [null, 'user1', 'app1', 'key1', 'value', false, false, true],
1235
+            [null, 'user1', 'app1', 'key1', '12345', true, false, true],
1236
+            [null, 'user1', 'app1', 'key1', '12345', true, true, true],
1237
+            [null, 'user1', 'app1', 'key1', 'value1', false, false, false],
1238
+            [null, 'user1', 'app1', 'key1', 'value1', true, false, true],
1239
+            [null, 'user1', 'app1', 'key1', 'value1', false, true, true],
1240
+            [null, 'user1', 'app1', 'fast_string', 'f_value_2', false, false, true],
1241
+            [null, 'user1', 'app1', 'fast_string', 'f_value', false, false, false],
1242
+            [null, 'user1', 'app1', 'fast_string', 'f_value', true, false, true],
1243
+            [null, 'user1', 'app1', 'fast_string', 'f_value', true, true, true],
1244
+            [null, 'user1', 'app1', 'lazy_string', 'l_value_2', false, false, true],
1245
+            [null, 'user1', 'app1', 'lazy_string', 'l_value', true, false, false],
1246
+            [null, 'user1', 'app1', 'lazy_string', 'l_value', true, true, true],
1247
+            [null, 'user1', 'app1', 'fast_string_sensitive', 'fs_value', false, true, false],
1248
+            [null, 'user1', 'app1', 'fast_string_sensitive', 'fs_value', true, true, true],
1249
+            [null, 'user1', 'app1', 'fast_string_sensitive', 'fs_value', true, false, true],
1250
+            [null, 'user1', 'app1', 'lazy_string_sensitive', 'ls_value', false, true, true],
1251
+            [null, 'user1', 'app1', 'lazy_string_sensitive', 'ls_value', true, true, false],
1252
+            [null, 'user1', 'app1', 'lazy_string_sensitive', 'ls_value', true, false, false],
1253
+            [null, 'user1', 'app1', 'lazy_string_sensitive', 'ls_value_2', true, false, true],
1254
+            [null, 'user1', 'app1', 'fast_int', 'n_value', false, false, true, TypeConflictException::class],
1255
+            [
1256
+                null, 'user1', 'app1', 'fast_float', 'n_value', false, false, true,
1257
+                TypeConflictException::class
1258
+            ],
1259
+            [
1260
+                null, 'user1', 'app1', 'fast_float', 'n_value', false, false, true,
1261
+                TypeConflictException::class
1262
+            ],
1263
+            [null, 'user1', 'app1', 'lazy_int', 'n_value', false, false, true, TypeConflictException::class],
1264
+            [
1265
+                null, 'user1', 'app1', 'lazy_boolean', 'n_value', false, false, true,
1266
+                TypeConflictException::class
1267
+            ],
1268
+            [
1269
+                null, 'user1', 'app1', 'lazy_float', 'n_value', false, false, true,
1270
+                TypeConflictException::class
1271
+            ],
1272
+        ];
1273
+    }
1274
+
1275
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerSetValueString')]
1276
+    public function testSetValueString(
1277
+        ?array $preload,
1278
+        string $userId,
1279
+        string $app,
1280
+        string $key,
1281
+        string $value,
1282
+        bool $lazy,
1283
+        bool $sensitive,
1284
+        bool $result,
1285
+        ?string $exception = null,
1286
+    ): void {
1287
+        $userConfig = $this->generateUserConfig($preload ?? []);
1288
+        if ($exception !== null) {
1289
+            $this->expectException($exception);
1290
+        }
1291
+
1292
+        $edited = $userConfig->setValueString($userId, $app, $key, $value, $lazy, ($sensitive) ? 1 : 0);
1293
+        if ($exception !== null) {
1294
+            return;
1295
+        }
1296
+
1297
+        $this->assertEquals($result, $edited);
1298
+        if ($result) {
1299
+            $this->assertEquals($value, $userConfig->getValueString($userId, $app, $key, $value, $lazy));
1300
+            $userConfig = $this->generateUserConfig($preload ?? []);
1301
+            $this->assertEquals($value, $userConfig->getValueString($userId, $app, $key, $value, $lazy));
1302
+        }
1303
+    }
1304
+
1305
+    public static function providerSetValueInt(): array {
1306
+        return [
1307
+            [null, 'user1', 'app1', 'key1', 12345, false, false, true],
1308
+            [null, 'user1', 'app1', 'key1', 12345, true, false, true],
1309
+            [null, 'user1', 'app1', 'key1', 12345, true, true, true],
1310
+            [null, 'user1', 'app1', 'fast_int', 11, false, false, false],
1311
+            [null, 'user1', 'app1', 'fast_int', 111, false, false, true],
1312
+            [null, 'user1', 'app1', 'fast_int', 111, true, false, true],
1313
+            [null, 'user1', 'app1', 'fast_int', 111, false, true, true],
1314
+            [null, 'user1', 'app1', 'fast_int', 11, true, false, true],
1315
+            [null, 'user1', 'app1', 'fast_int', 11, false, true, true],
1316
+            [null, 'user1', 'app1', 'lazy_int', 12, false, false, true],
1317
+            [null, 'user1', 'app1', 'lazy_int', 121, false, false, true],
1318
+            [null, 'user1', 'app1', 'lazy_int', 121, true, false, true],
1319
+            [null, 'user1', 'app1', 'lazy_int', 121, false, true, true],
1320
+            [null, 'user1', 'app1', 'lazy_int', 12, true, false, false],
1321
+            [null, 'user1', 'app1', 'lazy_int', 12, false, true, true],
1322
+            [null, 'user1', 'app1', 'fast_string', 12345, false, false, true, TypeConflictException::class],
1323
+            [null, 'user1', 'app1', 'fast_string', 12345, false, false, false, TypeConflictException::class],
1324
+            [null, 'user1', 'app1', 'fast_string', 12345, true, false, true, TypeConflictException::class],
1325
+            [null, 'user1', 'app1', 'fast_string', 12345, true, true, true, TypeConflictException::class],
1326
+            [null, 'user1', 'app1', 'lazy_string', 12345, false, false, true, TypeConflictException::class],
1327
+            [null, 'user1', 'app1', 'lazy_string', 12345, true, false, false, TypeConflictException::class],
1328
+            [null, 'user1', 'app1', 'lazy_string', 12345, true, true, true, TypeConflictException::class],
1329
+            [null, 'user1', 'app1', 'fast_float', 12345, false, false, true, TypeConflictException::class],
1330
+            [null, 'user1', 'app1', 'fast_float', 12345, false, false, true, TypeConflictException::class],
1331
+            [null, 'user1', 'app1', 'lazy_boolean', 12345, false, false, true, TypeConflictException::class],
1332
+            [null, 'user1', 'app1', 'lazy_float', 12345, false, false, true, TypeConflictException::class],
1333
+        ];
1334
+    }
1335
+
1336
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerSetValueInt')]
1337
+    public function testSetValueInt(
1338
+        ?array $preload,
1339
+        string $userId,
1340
+        string $app,
1341
+        string $key,
1342
+        int $value,
1343
+        bool $lazy,
1344
+        bool $sensitive,
1345
+        bool $result,
1346
+        ?string $exception = null,
1347
+    ): void {
1348
+        $userConfig = $this->generateUserConfig($preload ?? []);
1349
+        if ($exception !== null) {
1350
+            $this->expectException($exception);
1351
+        }
1352
+
1353
+        $edited = $userConfig->setValueInt($userId, $app, $key, $value, $lazy, ($sensitive) ? 1 : 0);
1354
+
1355
+        if ($exception !== null) {
1356
+            return;
1357
+        }
1358
+
1359
+        $this->assertEquals($result, $edited);
1360
+        if ($result) {
1361
+            $this->assertEquals($value, $userConfig->getValueInt($userId, $app, $key, $value, $lazy));
1362
+            $userConfig = $this->generateUserConfig($preload ?? []);
1363
+            $this->assertEquals($value, $userConfig->getValueInt($userId, $app, $key, $value, $lazy));
1364
+        }
1365
+    }
1366
+
1367
+    public static function providerSetValueFloat(): array {
1368
+        return [
1369
+            [null, 'user1', 'app1', 'key1', 12.345, false, false, true],
1370
+            [null, 'user1', 'app1', 'key1', 12.345, true, false, true],
1371
+            [null, 'user1', 'app1', 'key1', 12.345, true, true, true],
1372
+            [null, 'user1', 'app1', 'fast_float', 3.14, false, false, false],
1373
+            [null, 'user1', 'app1', 'fast_float', 3.15, false, false, true],
1374
+            [null, 'user1', 'app1', 'fast_float', 3.15, true, false, true],
1375
+            [null, 'user1', 'app1', 'fast_float', 3.15, false, true, true],
1376
+            [null, 'user1', 'app1', 'fast_float', 3.14, true, false, true],
1377
+            [null, 'user1', 'app1', 'fast_float', 3.14, false, true, true],
1378
+            [null, 'user1', 'app1', 'lazy_float', 3.14159, false, false, true],
1379
+            [null, 'user1', 'app1', 'lazy_float', 3.14158, false, false, true],
1380
+            [null, 'user1', 'app1', 'lazy_float', 3.14158, true, false, true],
1381
+            [null, 'user1', 'app1', 'lazy_float', 3.14158, false, true, true],
1382
+            [null, 'user1', 'app1', 'lazy_float', 3.14159, true, false, false],
1383
+            [null, 'user1', 'app1', 'lazy_float', 3.14159, false, true, true],
1384
+            [null, 'user1', 'app1', 'fast_string', 12.345, false, false, true, TypeConflictException::class],
1385
+            [null, 'user1', 'app1', 'fast_string', 12.345, false, false, false, TypeConflictException::class],
1386
+            [null, 'user1', 'app1', 'fast_string', 12.345, true, false, true, TypeConflictException::class],
1387
+            [null, 'user1', 'app1', 'fast_string', 12.345, true, true, true, TypeConflictException::class],
1388
+            [null, 'user1', 'app1', 'lazy_string', 12.345, false, false, true, TypeConflictException::class],
1389
+            [null, 'user1', 'app1', 'lazy_string', 12.345, true, false, false, TypeConflictException::class],
1390
+            [null, 'user1', 'app1', 'fast_array', 12.345, true, true, true, TypeConflictException::class],
1391
+            [null, 'user1', 'app1', 'fast_int', 12.345, false, false, true, TypeConflictException::class],
1392
+            [null, 'user1', 'app1', 'fast_int', 12.345, false, false, true, TypeConflictException::class],
1393
+            [null, 'user1', 'app1', 'lazy_boolean', 12.345, false, false, true, TypeConflictException::class],
1394
+        ];
1395
+    }
1396
+
1397
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerSetValueFloat')]
1398
+    public function testSetValueFloat(
1399
+        ?array $preload,
1400
+        string $userId,
1401
+        string $app,
1402
+        string $key,
1403
+        float $value,
1404
+        bool $lazy,
1405
+        bool $sensitive,
1406
+        bool $result,
1407
+        ?string $exception = null,
1408
+    ): void {
1409
+        $userConfig = $this->generateUserConfig($preload ?? []);
1410
+        if ($exception !== null) {
1411
+            $this->expectException($exception);
1412
+        }
1413
+
1414
+        $edited = $userConfig->setValueFloat($userId, $app, $key, $value, $lazy, ($sensitive) ? 1 : 0);
1415
+
1416
+        if ($exception !== null) {
1417
+            return;
1418
+        }
1419
+
1420
+        $this->assertEquals($result, $edited);
1421
+        if ($result) {
1422
+            $this->assertEquals($value, $userConfig->getValueFloat($userId, $app, $key, $value, $lazy));
1423
+            $userConfig = $this->generateUserConfig($preload ?? []);
1424
+            $this->assertEquals($value, $userConfig->getValueFloat($userId, $app, $key, $value, $lazy));
1425
+        }
1426
+    }
1427
+
1428
+
1429
+    public static function providerSetValueArray(): array {
1430
+        return [
1431
+            [null, 'user1', 'app1', 'key1', [], false, false, true],
1432
+            [null, 'user1', 'app1', 'key1', [], true, false, true],
1433
+            [null, 'user1', 'app1', 'key1', [], true, true, true],
1434
+            [null, 'user1', 'app1', 'fast_array', ['year' => 2024], false, false, false],
1435
+            [null, 'user1', 'app1', 'fast_array', [], false, false, true],
1436
+            [null, 'user1', 'app1', 'fast_array', [], true, false, true],
1437
+            [null, 'user1', 'app1', 'fast_array', [], false, true, true],
1438
+            [null, 'user1', 'app1', 'fast_array', ['year' => 2024], true, false, true],
1439
+            [null, 'user1', 'app1', 'fast_array', ['year' => 2024], false, true, true],
1440
+            [null, 'user1', 'app1', 'lazy_array', ['month' => 'October'], false, false, true],
1441
+            [null, 'user1', 'app1', 'lazy_array', ['month' => 'September'], false, false, true],
1442
+            [null, 'user1', 'app1', 'lazy_array', ['month' => 'September'], true, false, true],
1443
+            [null, 'user1', 'app1', 'lazy_array', ['month' => 'September'], false, true, true],
1444
+            [null, 'user1', 'app1', 'lazy_array', ['month' => 'October'], true, false, false],
1445
+            [null, 'user1', 'app1', 'lazy_array', ['month' => 'October'], false, true, true],
1446
+            [null, 'user1', 'app1', 'fast_string', [], false, false, true, TypeConflictException::class],
1447
+            [null, 'user1', 'app1', 'fast_string', [], false, false, false, TypeConflictException::class],
1448
+            [null, 'user1', 'app1', 'fast_string', [], true, false, true, TypeConflictException::class],
1449
+            [null, 'user1', 'app1', 'fast_string', [], true, true, true, TypeConflictException::class],
1450
+            [null, 'user1', 'app1', 'lazy_string', [], false, false, true, TypeConflictException::class],
1451
+            [null, 'user1', 'app1', 'lazy_string', [], true, false, false, TypeConflictException::class],
1452
+            [null, 'user1', 'app1', 'lazy_string', [], true, true, true, TypeConflictException::class],
1453
+            [null, 'user1', 'app1', 'fast_int', [], false, false, true, TypeConflictException::class],
1454
+            [null, 'user1', 'app1', 'fast_int', [], false, false, true, TypeConflictException::class],
1455
+            [null, 'user1', 'app1', 'lazy_boolean', [], false, false, true, TypeConflictException::class],
1456
+        ];
1457
+    }
1458
+
1459
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerSetValueArray')]
1460
+    public function testSetValueArray(
1461
+        ?array $preload,
1462
+        string $userId,
1463
+        string $app,
1464
+        string $key,
1465
+        array $value,
1466
+        bool $lazy,
1467
+        bool $sensitive,
1468
+        bool $result,
1469
+        ?string $exception = null,
1470
+    ): void {
1471
+        $userConfig = $this->generateUserConfig($preload ?? []);
1472
+        if ($exception !== null) {
1473
+            $this->expectException($exception);
1474
+        }
1475
+
1476
+        $edited = $userConfig->setValueArray($userId, $app, $key, $value, $lazy, ($sensitive) ? 1 : 0);
1477
+
1478
+        if ($exception !== null) {
1479
+            return;
1480
+        }
1481
+
1482
+        $this->assertEquals($result, $edited);
1483
+        if ($result) {
1484
+            $this->assertEqualsCanonicalizing(
1485
+                $value, $userConfig->getValueArray($userId, $app, $key, $value, $lazy)
1486
+            );
1487
+            $userConfig = $this->generateUserConfig($preload ?? []);
1488
+            $this->assertEqualsCanonicalizing(
1489
+                $value, $userConfig->getValueArray($userId, $app, $key, $value, $lazy)
1490
+            );
1491
+        }
1492
+    }
1493
+
1494
+    public static function providerUpdateSensitive(): array {
1495
+        return [
1496
+            [null, 'user1', 'app1', 'key1', false, false],
1497
+            [['user1'], 'user1', 'app1', 'key1', false, false],
1498
+            [null, 'user1', 'app1', 'key1', true, true],
1499
+            [['user1'], 'user1', 'app1', 'key1', true, true],
1500
+        ];
1501
+    }
1502
+
1503
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerUpdateSensitive')]
1504
+    public function testUpdateSensitive(
1505
+        ?array $preload,
1506
+        string $userId,
1507
+        string $app,
1508
+        string $key,
1509
+        bool $sensitive,
1510
+        bool $result,
1511
+        ?string $exception = null,
1512
+    ): void {
1513
+        $userConfig = $this->generateUserConfig($preload ?? []);
1514
+        if ($exception !== null) {
1515
+            $this->expectException($exception);
1516
+        }
1517
+
1518
+        $edited = $userConfig->updateSensitive($userId, $app, $key, $sensitive);
1519
+        if ($exception !== null) {
1520
+            return;
1521
+        }
1522
+
1523
+        $this->assertEquals($result, $edited);
1524
+        if ($result) {
1525
+            $this->assertEquals($sensitive, $userConfig->isSensitive($userId, $app, $key));
1526
+            $userConfig = $this->generateUserConfig($preload ?? []);
1527
+            $this->assertEquals($sensitive, $userConfig->isSensitive($userId, $app, $key));
1528
+            if ($sensitive) {
1529
+                $this->assertEquals(true, str_starts_with(
1530
+                    $userConfig->statusCache()['fastCache'][$userId][$app][$key]
1531
+                    ?? $userConfig->statusCache()['lazyCache'][$userId][$app][$key],
1532
+                    '$UserConfigEncryption$')
1533
+                );
1534
+            }
1535
+        }
1536
+    }
1537
+
1538
+    public static function providerUpdateGlobalSensitive(): array {
1539
+        return [[true], [false]];
1540
+    }
1541
+
1542
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerUpdateGlobalSensitive')]
1543
+    public function testUpdateGlobalSensitive(bool $sensitive): void {
1544
+        $userConfig = $this->generateUserConfig($preload ?? []);
1545
+        $app = 'app2';
1546
+        if ($sensitive) {
1547
+            $key = 'key2';
1548
+            $value = 'value2a';
1549
+        } else {
1550
+            $key = 'key4';
1551
+            $value = 'value4';
1552
+        }
1553
+
1554
+        $this->assertEquals($value, $userConfig->getValueString('user1', $app, $key));
1555
+        foreach (['user1', 'user2', 'user3', 'user4'] as $userId) {
1556
+            $userConfig->getValueString($userId, $app, $key); // cache loading for userId
1557
+            $this->assertEquals(
1558
+                !$sensitive, str_starts_with(
1559
+                    $userConfig->statusCache()['fastCache'][$userId][$app][$key]
1560
+                    ?? $userConfig->statusCache()['lazyCache'][$userId][$app][$key],
1561
+                    '$UserConfigEncryption$'
1562
+                )
1563
+            );
1564
+        }
1565
+
1566
+        $userConfig->updateGlobalSensitive($app, $key, $sensitive);
1567
+
1568
+        $this->assertEquals($value, $userConfig->getValueString('user1', $app, $key));
1569
+        foreach (['user1', 'user2', 'user3', 'user4'] as $userId) {
1570
+            $this->assertEquals($sensitive, $userConfig->isSensitive($userId, $app, $key));
1571
+            // should only work if updateGlobalSensitive drop cache
1572
+            $this->assertEquals($sensitive, str_starts_with(
1573
+                $userConfig->statusCache()['fastCache'][$userId][$app][$key]
1574
+                ?? $userConfig->statusCache()['lazyCache'][$userId][$app][$key],
1575
+                '$UserConfigEncryption$')
1576
+            );
1577
+        }
1578
+    }
1579
+
1580
+    public static function providerUpdateLazy(): array {
1581
+        return [
1582
+            [null, 'user1', 'app1', 'key1', false, false],
1583
+            [['user1'], 'user1', 'app1', 'key1', false, false],
1584
+            [null, 'user1', 'app1', 'key1', true, true],
1585
+            [['user1'], 'user1', 'app1', 'key1', true, true],
1586
+        ];
1587
+    }
1588
+
1589
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerUpdateLazy')]
1590
+    public function testUpdateLazy(
1591
+        ?array $preload,
1592
+        string $userId,
1593
+        string $app,
1594
+        string $key,
1595
+        bool $lazy,
1596
+        bool $result,
1597
+        ?string $exception = null,
1598
+    ): void {
1599
+        $userConfig = $this->generateUserConfig($preload ?? []);
1600
+        if ($exception !== null) {
1601
+            $this->expectException($exception);
1602
+        }
1603
+
1604
+        $edited = $userConfig->updateLazy($userId, $app, $key, $lazy);
1605
+        if ($exception !== null) {
1606
+            return;
1607
+        }
1608
+
1609
+        $this->assertEquals($result, $edited);
1610
+        if ($result) {
1611
+            $this->assertEquals($lazy, $userConfig->isLazy($userId, $app, $key));
1612
+            $userConfig = $this->generateUserConfig($preload ?? []);
1613
+            $this->assertEquals($lazy, $userConfig->isLazy($userId, $app, $key));
1614
+        }
1615
+    }
1616
+
1617
+    public static function providerUpdateGlobalLazy(): array {
1618
+        return [[true], [false]];
1619
+    }
1620
+
1621
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerUpdateGlobalLazy')]
1622
+    public function testUpdateGlobalLazy(bool $lazy): void {
1623
+        $userConfig = $this->generateUserConfig($preload ?? []);
1624
+        $app = 'app2';
1625
+        if ($lazy) {
1626
+            $key = 'key4';
1627
+            $value = 'value4';
1628
+        } else {
1629
+            $key = 'key3';
1630
+            $value = 'value3';
1631
+        }
1632
+
1633
+        $this->assertEquals($value, $userConfig->getValueString('user1', $app, $key, '', !$lazy));
1634
+        foreach (['user1', 'user2', 'user3', 'user4'] as $userId) {
1635
+            $this->assertEquals(!$lazy, $userConfig->isLazy($userId, $app, $key));
1636
+        }
1637
+
1638
+        $userConfig->updateGlobalLazy($app, $key, $lazy);
1639
+        $this->assertEquals($value, $userConfig->getValueString('user1', $app, $key, '', $lazy));
1640
+        foreach (['user1', 'user2', 'user3', 'user4'] as $userId) {
1641
+            $this->assertEquals($lazy, $userConfig->isLazy($userId, $app, $key));
1642
+        }
1643
+    }
1644
+
1645
+    public static function providerGetDetails(): array {
1646
+        return [
1647
+            [
1648
+                'user3', 'app2', 'key2',
1649
+                [
1650
+                    'userId' => 'user3',
1651
+                    'app' => 'app2',
1652
+                    'key' => 'key2',
1653
+                    'value' => 'value2c',
1654
+                    'type' => 0,
1655
+                    'lazy' => false,
1656
+                    'typeString' => 'mixed',
1657
+                    'sensitive' => false
1658
+                ]
1659
+            ],
1660
+            [
1661
+                'user1', 'app1', 'lazy_int',
1662
+                [
1663
+                    'userId' => 'user1',
1664
+                    'app' => 'app1',
1665
+                    'key' => 'lazy_int',
1666
+                    'value' => 12,
1667
+                    'type' => 2,
1668
+                    'lazy' => true,
1669
+                    'typeString' => 'int',
1670
+                    'sensitive' => false
1671
+                ]
1672
+            ],
1673
+            [
1674
+                'user1', 'app1', 'fast_float_sensitive',
1675
+                [
1676
+                    'userId' => 'user1',
1677
+                    'app' => 'app1',
1678
+                    'key' => 'fast_float_sensitive',
1679
+                    'value' => 1.41,
1680
+                    'type' => 3,
1681
+                    'lazy' => false,
1682
+                    'typeString' => 'float',
1683
+                    'sensitive' => true
1684
+                ]
1685
+            ],
1686
+        ];
1687
+    }
1688
+
1689
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerGetDetails')]
1690
+    public function testGetDetails(string $userId, string $app, string $key, array $result): void {
1691
+        $userConfig = $this->generateUserConfig($preload ?? []);
1692
+        $this->assertEqualsCanonicalizing($result, $userConfig->getDetails($userId, $app, $key));
1693
+    }
1694
+
1695
+
1696
+    public static function providerDeletePreference(): array {
1697
+        return [
1698
+            [null, 'user1', 'app1', 'key22'],
1699
+            [['user1'], 'user1', 'app1', 'fast_string_sensitive'],
1700
+            [null, 'user1', 'app1', 'lazy_array_sensitive'],
1701
+            [['user2'], 'user1', 'app1', 'lazy_array_sensitive'],
1702
+            [null, 'user2', 'only-lazy', 'key1'],
1703
+            [['user2'], 'user2', 'only-lazy', 'key1'],
1704
+        ];
1705
+    }
1706
+
1707
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerDeletePreference')]
1708
+    public function testDeletePreference(
1709
+        ?array $preload,
1710
+        string $userId,
1711
+        string $app,
1712
+        string $key,
1713
+    ): void {
1714
+        $userConfig = $this->generateUserConfig($preload ?? []);
1715
+        $lazy = $userConfig->isLazy($userId, $app, $key);
1716
+
1717
+        $userConfig = $this->generateUserConfig($preload ?? []);
1718
+        $this->assertEquals(true, $userConfig->hasKey($userId, $app, $key, $lazy));
1719
+        $userConfig->deleteUserConfig($userId, $app, $key);
1720
+        $this->assertEquals(false, $userConfig->hasKey($userId, $app, $key, $lazy));
1721
+        $userConfig = $this->generateUserConfig($preload ?? []);
1722
+        $this->assertEquals(false, $userConfig->hasKey($userId, $app, $key, $lazy));
1723
+    }
1724
+
1725
+    public static function providerDeleteKey(): array {
1726
+        return [
1727
+            [null, 'app2', 'key3'],
1728
+            [['user1'], 'app2', 'key3'],
1729
+            [null, 'only-lazy', 'key1'],
1730
+            [['user2'], 'only-lazy', 'key1'],
1731
+            [null, 'app2', 'lazy_string_sensitive'],
1732
+            [['user3', 'user1'], 'app2', 'lazy_string_sensitive'],
1733
+        ];
1734
+    }
1735
+
1736
+    #[\PHPUnit\Framework\Attributes\DataProvider('providerDeleteKey')]
1737
+    public function testDeleteKey(
1738
+        ?array $preload,
1739
+        string $app,
1740
+        string $key,
1741
+    ): void {
1742
+        $userConfig = $this->generateUserConfig($preload ?? []);
1743
+        $userConfig->deleteKey($app, $key);
1744
+
1745
+        foreach (['user1', 'user2', 'user3', 'user4'] as $userId) {
1746
+            $this->assertEquals(false, $userConfig->hasKey($userId, $app, $key, null));
1747
+            $userConfigTemp = $this->generateUserConfig($preload ?? []);
1748
+            $this->assertEquals(false, $userConfigTemp->hasKey($userId, $app, $key, null));
1749
+        }
1750
+    }
1751
+
1752
+    public function testDeleteApp(): void {
1753
+        $userConfig = $this->generateUserConfig();
1754
+        $userConfig->deleteApp('only-lazy');
1755
+
1756
+        foreach (['user1', 'user2', 'user3', 'user4'] as $userId) {
1757
+            $this->assertEquals(false, in_array('only-lazy', $userConfig->getApps($userId)));
1758
+            $userConfigTemp = $this->generateUserConfig();
1759
+            $this->assertEquals(false, in_array('only-lazy', $userConfigTemp->getApps($userId)));
1760
+        }
1761
+    }
1762
+
1763
+    public function testDeleteAllPreferences(): void {
1764
+        $userConfig = $this->generateUserConfig();
1765
+        $userConfig->deleteAllUserConfig('user1');
1766
+
1767
+        $this->assertEqualsCanonicalizing([], $userConfig->getApps('user1'));
1768
+        $userConfig = $this->generateUserConfig();
1769
+        $this->assertEqualsCanonicalizing([], $userConfig->getApps('user1'));
1770
+    }
1771
+
1772
+    public function testClearCache(): void {
1773
+        $userConfig = $this->generateUserConfig(['user1', 'user2']);
1774
+        $userConfig->clearCache('user1');
1775
+
1776
+        $this->assertEquals(true, $userConfig->statusCache()['fastLoaded']['user2']);
1777
+        $this->assertEquals(false, $userConfig->statusCache()['fastLoaded']['user1']);
1778
+        $this->assertEquals('value2a', $userConfig->getValueString('user1', 'app2', 'key2'));
1779
+        $this->assertEquals(false, $userConfig->statusCache()['lazyLoaded']['user1']);
1780
+        $this->assertEquals(true, $userConfig->statusCache()['fastLoaded']['user1']);
1781
+    }
1782
+
1783
+    public function testClearCacheAll(): void {
1784
+        $userConfig = $this->generateUserConfig(['user1', 'user2']);
1785
+        $userConfig->clearCacheAll();
1786
+        $this->assertEqualsCanonicalizing(
1787
+            [
1788
+                'fastLoaded' => [],
1789
+                'fastCache' => [],
1790
+                'lazyLoaded' => [],
1791
+                'lazyCache' => [],
1792
+                'valueDetails' => [],
1793
+            ],
1794
+            $userConfig->statusCache()
1795
+        );
1796
+    }
1797 1797
 }
Please login to merge, or discard this patch.