Completed
Push — master ( 5d14f8...2337bd )
by Robin
27:19 queued 16s
created
apps/dav/tests/unit/Connector/Sabre/AuthTest.php 1 patch
Indentation   +575 added lines, -575 removed lines patch added patch discarded remove patch
@@ -30,579 +30,579 @@
 block discarded – undo
30 30
  * @group DB
31 31
  */
32 32
 class AuthTest extends TestCase {
33
-	private ISession&MockObject $session;
34
-	private Session&MockObject $userSession;
35
-	private IRequest&MockObject $request;
36
-	private Manager&MockObject $twoFactorManager;
37
-	private IThrottler&MockObject $throttler;
38
-	private Auth $auth;
39
-
40
-	protected function setUp(): void {
41
-		parent::setUp();
42
-		$this->session = $this->createMock(ISession::class);
43
-		$this->userSession = $this->createMock(Session::class);
44
-		$this->request = $this->createMock(IRequest::class);
45
-		$this->twoFactorManager = $this->createMock(Manager::class);
46
-		$this->throttler = $this->createMock(IThrottler::class);
47
-		$this->auth = new Auth(
48
-			$this->session,
49
-			$this->userSession,
50
-			$this->request,
51
-			$this->twoFactorManager,
52
-			$this->throttler
53
-		);
54
-	}
55
-
56
-	public function testIsDavAuthenticatedWithoutDavSession(): void {
57
-		$this->session
58
-			->expects($this->once())
59
-			->method('get')
60
-			->with('AUTHENTICATED_TO_DAV_BACKEND')
61
-			->willReturn(null);
62
-
63
-		$this->assertFalse(self::invokePrivate($this->auth, 'isDavAuthenticated', ['MyTestUser']));
64
-	}
65
-
66
-	public function testIsDavAuthenticatedWithWrongDavSession(): void {
67
-		$this->session
68
-			->expects($this->exactly(2))
69
-			->method('get')
70
-			->with('AUTHENTICATED_TO_DAV_BACKEND')
71
-			->willReturn('AnotherUser');
72
-
73
-		$this->assertFalse(self::invokePrivate($this->auth, 'isDavAuthenticated', ['MyTestUser']));
74
-	}
75
-
76
-	public function testIsDavAuthenticatedWithCorrectDavSession(): void {
77
-		$this->session
78
-			->expects($this->exactly(2))
79
-			->method('get')
80
-			->with('AUTHENTICATED_TO_DAV_BACKEND')
81
-			->willReturn('MyTestUser');
82
-
83
-		$this->assertTrue(self::invokePrivate($this->auth, 'isDavAuthenticated', ['MyTestUser']));
84
-	}
85
-
86
-	public function testValidateUserPassOfAlreadyDAVAuthenticatedUser(): void {
87
-		$user = $this->createMock(IUser::class);
88
-		$user->expects($this->exactly(1))
89
-			->method('getUID')
90
-			->willReturn('MyTestUser');
91
-		$this->userSession
92
-			->expects($this->once())
93
-			->method('isLoggedIn')
94
-			->willReturn(true);
95
-		$this->userSession
96
-			->expects($this->exactly(1))
97
-			->method('getUser')
98
-			->willReturn($user);
99
-		$this->session
100
-			->expects($this->exactly(2))
101
-			->method('get')
102
-			->with('AUTHENTICATED_TO_DAV_BACKEND')
103
-			->willReturn('MyTestUser');
104
-		$this->session
105
-			->expects($this->once())
106
-			->method('close');
107
-
108
-		$this->assertTrue(self::invokePrivate($this->auth, 'validateUserPass', ['MyTestUser', 'MyTestPassword']));
109
-	}
110
-
111
-	public function testValidateUserPassOfInvalidDAVAuthenticatedUser(): void {
112
-		$user = $this->createMock(IUser::class);
113
-		$user->expects($this->once())
114
-			->method('getUID')
115
-			->willReturn('MyTestUser');
116
-		$this->userSession
117
-			->expects($this->once())
118
-			->method('isLoggedIn')
119
-			->willReturn(true);
120
-		$this->userSession
121
-			->expects($this->once())
122
-			->method('getUser')
123
-			->willReturn($user);
124
-		$this->session
125
-			->expects($this->exactly(2))
126
-			->method('get')
127
-			->with('AUTHENTICATED_TO_DAV_BACKEND')
128
-			->willReturn('AnotherUser');
129
-		$this->session
130
-			->expects($this->once())
131
-			->method('close');
132
-
133
-		$this->assertFalse(self::invokePrivate($this->auth, 'validateUserPass', ['MyTestUser', 'MyTestPassword']));
134
-	}
135
-
136
-	public function testValidateUserPassOfInvalidDAVAuthenticatedUserWithValidPassword(): void {
137
-		$user = $this->createMock(IUser::class);
138
-		$user->expects($this->exactly(2))
139
-			->method('getUID')
140
-			->willReturn('MyTestUser');
141
-		$this->userSession
142
-			->expects($this->once())
143
-			->method('isLoggedIn')
144
-			->willReturn(true);
145
-		$this->userSession
146
-			->expects($this->exactly(2))
147
-			->method('getUser')
148
-			->willReturn($user);
149
-		$this->session
150
-			->expects($this->exactly(2))
151
-			->method('get')
152
-			->with('AUTHENTICATED_TO_DAV_BACKEND')
153
-			->willReturn('AnotherUser');
154
-		$this->userSession
155
-			->expects($this->once())
156
-			->method('logClientIn')
157
-			->with('MyTestUser', 'MyTestPassword', $this->request)
158
-			->willReturn(true);
159
-		$this->session
160
-			->expects($this->once())
161
-			->method('set')
162
-			->with('AUTHENTICATED_TO_DAV_BACKEND', 'MyTestUser');
163
-		$this->session
164
-			->expects($this->once())
165
-			->method('close');
166
-
167
-		$this->assertTrue(self::invokePrivate($this->auth, 'validateUserPass', ['MyTestUser', 'MyTestPassword']));
168
-	}
169
-
170
-	public function testValidateUserPassWithInvalidPassword(): void {
171
-		$this->userSession
172
-			->expects($this->once())
173
-			->method('isLoggedIn')
174
-			->willReturn(false);
175
-		$this->userSession
176
-			->expects($this->once())
177
-			->method('logClientIn')
178
-			->with('MyTestUser', 'MyTestPassword')
179
-			->willReturn(false);
180
-		$this->session
181
-			->expects($this->once())
182
-			->method('close');
183
-
184
-		$this->assertFalse(self::invokePrivate($this->auth, 'validateUserPass', ['MyTestUser', 'MyTestPassword']));
185
-	}
186
-
187
-
188
-	public function testValidateUserPassWithPasswordLoginForbidden(): void {
189
-		$this->expectException(PasswordLoginForbidden::class);
190
-
191
-		$this->userSession
192
-			->expects($this->once())
193
-			->method('isLoggedIn')
194
-			->willReturn(false);
195
-		$this->userSession
196
-			->expects($this->once())
197
-			->method('logClientIn')
198
-			->with('MyTestUser', 'MyTestPassword')
199
-			->willThrowException(new PasswordLoginForbiddenException());
200
-		$this->session
201
-			->expects($this->once())
202
-			->method('close');
203
-
204
-		self::invokePrivate($this->auth, 'validateUserPass', ['MyTestUser', 'MyTestPassword']);
205
-	}
206
-
207
-	public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenForNonGet(): void {
208
-		$request = $this->createMock(RequestInterface::class);
209
-		$response = $this->createMock(ResponseInterface::class);
210
-		$this->userSession
211
-			->expects($this->any())
212
-			->method('isLoggedIn')
213
-			->willReturn(true);
214
-		$this->request
215
-			->expects($this->any())
216
-			->method('getMethod')
217
-			->willReturn('POST');
218
-		$this->session
219
-			->expects($this->any())
220
-			->method('get')
221
-			->with('AUTHENTICATED_TO_DAV_BACKEND')
222
-			->willReturn(null);
223
-		$user = $this->createMock(IUser::class);
224
-		$user->expects($this->any())
225
-			->method('getUID')
226
-			->willReturn('MyWrongDavUser');
227
-		$this->userSession
228
-			->expects($this->any())
229
-			->method('getUser')
230
-			->willReturn($user);
231
-		$this->request
232
-			->expects($this->once())
233
-			->method('passesCSRFCheck')
234
-			->willReturn(false);
235
-
236
-		$expectedResponse = [
237
-			false,
238
-			"No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured",
239
-		];
240
-		$response = $this->auth->check($request, $response);
241
-		$this->assertSame($expectedResponse, $response);
242
-	}
243
-
244
-	public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenAndCorrectlyDavAuthenticated(): void {
245
-		$request = $this->createMock(RequestInterface::class);
246
-		$response = $this->createMock(ResponseInterface::class);
247
-		$this->userSession
248
-			->expects($this->any())
249
-			->method('isLoggedIn')
250
-			->willReturn(true);
251
-		$this->request
252
-			->expects($this->any())
253
-			->method('getMethod')
254
-			->willReturn('PROPFIND');
255
-		$this->request
256
-			->expects($this->any())
257
-			->method('isUserAgent')
258
-			->willReturn(false);
259
-		$this->session
260
-			->expects($this->any())
261
-			->method('get')
262
-			->with('AUTHENTICATED_TO_DAV_BACKEND')
263
-			->willReturn('LoggedInUser');
264
-		$user = $this->createMock(IUser::class);
265
-		$user->expects($this->any())
266
-			->method('getUID')
267
-			->willReturn('LoggedInUser');
268
-		$this->userSession
269
-			->expects($this->any())
270
-			->method('getUser')
271
-			->willReturn($user);
272
-		$this->request
273
-			->expects($this->once())
274
-			->method('passesCSRFCheck')
275
-			->willReturn(false);
276
-		$this->auth->check($request, $response);
277
-	}
278
-
279
-
280
-	public function testAuthenticateAlreadyLoggedInWithoutTwoFactorChallengePassed(): void {
281
-		$this->expectException(\Sabre\DAV\Exception\NotAuthenticated::class);
282
-		$this->expectExceptionMessage('2FA challenge not passed.');
283
-
284
-		$request = $this->createMock(RequestInterface::class);
285
-		$response = $this->createMock(ResponseInterface::class);
286
-		$this->userSession
287
-			->expects($this->any())
288
-			->method('isLoggedIn')
289
-			->willReturn(true);
290
-		$this->request
291
-			->expects($this->any())
292
-			->method('getMethod')
293
-			->willReturn('PROPFIND');
294
-		$this->request
295
-			->expects($this->any())
296
-			->method('isUserAgent')
297
-			->willReturn(false);
298
-		$this->session
299
-			->expects($this->any())
300
-			->method('get')
301
-			->with('AUTHENTICATED_TO_DAV_BACKEND')
302
-			->willReturn('LoggedInUser');
303
-		$user = $this->createMock(IUser::class);
304
-		$user->expects($this->any())
305
-			->method('getUID')
306
-			->willReturn('LoggedInUser');
307
-		$this->userSession
308
-			->expects($this->any())
309
-			->method('getUser')
310
-			->willReturn($user);
311
-		$this->request
312
-			->expects($this->once())
313
-			->method('passesCSRFCheck')
314
-			->willReturn(true);
315
-		$this->twoFactorManager->expects($this->once())
316
-			->method('needsSecondFactor')
317
-			->with($user)
318
-			->willReturn(true);
319
-		$this->auth->check($request, $response);
320
-	}
321
-
322
-
323
-	public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenAndIncorrectlyDavAuthenticated(): void {
324
-		$this->expectException(\Sabre\DAV\Exception\NotAuthenticated::class);
325
-		$this->expectExceptionMessage('CSRF check not passed.');
326
-
327
-		$request = $this->createMock(RequestInterface::class);
328
-		$response = $this->createMock(ResponseInterface::class);
329
-		$this->userSession
330
-			->expects($this->any())
331
-			->method('isLoggedIn')
332
-			->willReturn(true);
333
-		$this->request
334
-			->expects($this->any())
335
-			->method('getMethod')
336
-			->willReturn('PROPFIND');
337
-		$this->request
338
-			->expects($this->any())
339
-			->method('isUserAgent')
340
-			->willReturn(false);
341
-		$this->session
342
-			->expects($this->any())
343
-			->method('get')
344
-			->with('AUTHENTICATED_TO_DAV_BACKEND')
345
-			->willReturn('AnotherUser');
346
-		$user = $this->createMock(IUser::class);
347
-		$user->expects($this->any())
348
-			->method('getUID')
349
-			->willReturn('LoggedInUser');
350
-		$this->userSession
351
-			->expects($this->any())
352
-			->method('getUser')
353
-			->willReturn($user);
354
-		$this->request
355
-			->expects($this->once())
356
-			->method('passesCSRFCheck')
357
-			->willReturn(false);
358
-		$this->auth->check($request, $response);
359
-	}
360
-
361
-	public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenForNonGetAndDesktopClient(): void {
362
-		$request = $this->createMock(RequestInterface::class);
363
-		$response = $this->createMock(ResponseInterface::class);
364
-		$this->userSession
365
-			->expects($this->any())
366
-			->method('isLoggedIn')
367
-			->willReturn(true);
368
-		$this->request
369
-			->expects($this->any())
370
-			->method('getMethod')
371
-			->willReturn('POST');
372
-		$this->request
373
-			->expects($this->any())
374
-			->method('isUserAgent')
375
-			->willReturn(true);
376
-		$this->session
377
-			->expects($this->any())
378
-			->method('get')
379
-			->with('AUTHENTICATED_TO_DAV_BACKEND')
380
-			->willReturn(null);
381
-		$user = $this->createMock(IUser::class);
382
-		$user->expects($this->any())
383
-			->method('getUID')
384
-			->willReturn('MyWrongDavUser');
385
-		$this->userSession
386
-			->expects($this->any())
387
-			->method('getUser')
388
-			->willReturn($user);
389
-		$this->request
390
-			->expects($this->once())
391
-			->method('passesCSRFCheck')
392
-			->willReturn(false);
393
-
394
-		$this->auth->check($request, $response);
395
-	}
396
-
397
-	public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenForGet(): void {
398
-		$request = $this->createMock(RequestInterface::class);
399
-		$response = $this->createMock(ResponseInterface::class);
400
-		$this->userSession
401
-			->expects($this->any())
402
-			->method('isLoggedIn')
403
-			->willReturn(true);
404
-		$this->session
405
-			->expects($this->any())
406
-			->method('get')
407
-			->with('AUTHENTICATED_TO_DAV_BACKEND')
408
-			->willReturn(null);
409
-		$user = $this->createMock(IUser::class);
410
-		$user->expects($this->any())
411
-			->method('getUID')
412
-			->willReturn('MyWrongDavUser');
413
-		$this->userSession
414
-			->expects($this->any())
415
-			->method('getUser')
416
-			->willReturn($user);
417
-		$this->request
418
-			->expects($this->any())
419
-			->method('getMethod')
420
-			->willReturn('GET');
421
-
422
-		$response = $this->auth->check($request, $response);
423
-		$this->assertEquals([true, 'principals/users/MyWrongDavUser'], $response);
424
-	}
425
-
426
-	public function testAuthenticateAlreadyLoggedInWithCsrfTokenForGet(): void {
427
-		$request = $this->createMock(RequestInterface::class);
428
-		$response = $this->createMock(ResponseInterface::class);
429
-		$this->userSession
430
-			->expects($this->any())
431
-			->method('isLoggedIn')
432
-			->willReturn(true);
433
-		$this->session
434
-			->expects($this->any())
435
-			->method('get')
436
-			->with('AUTHENTICATED_TO_DAV_BACKEND')
437
-			->willReturn(null);
438
-		$user = $this->createMock(IUser::class);
439
-		$user->expects($this->any())
440
-			->method('getUID')
441
-			->willReturn('MyWrongDavUser');
442
-		$this->userSession
443
-			->expects($this->any())
444
-			->method('getUser')
445
-			->willReturn($user);
446
-		$this->request
447
-			->expects($this->once())
448
-			->method('passesCSRFCheck')
449
-			->willReturn(true);
450
-
451
-		$response = $this->auth->check($request, $response);
452
-		$this->assertEquals([true, 'principals/users/MyWrongDavUser'], $response);
453
-	}
454
-
455
-	public function testAuthenticateNoBasicAuthenticateHeadersProvided(): void {
456
-		$server = $this->createMock(Server::class);
457
-		$server->httpRequest = $this->createMock(RequestInterface::class);
458
-		$server->httpResponse = $this->createMock(ResponseInterface::class);
459
-		$response = $this->auth->check($server->httpRequest, $server->httpResponse);
460
-		$this->assertEquals([false, 'No \'Authorization: Basic\' header found. Either the client didn\'t send one, or the server is misconfigured'], $response);
461
-	}
462
-
463
-
464
-	public function testAuthenticateNoBasicAuthenticateHeadersProvidedWithAjax(): void {
465
-		$this->expectException(\Sabre\DAV\Exception\NotAuthenticated::class);
466
-		$this->expectExceptionMessage('Cannot authenticate over ajax calls');
467
-
468
-		/** @var \Sabre\HTTP\RequestInterface&MockObject $httpRequest */
469
-		$httpRequest = $this->createMock(RequestInterface::class);
470
-		/** @var \Sabre\HTTP\ResponseInterface&MockObject $httpResponse */
471
-		$httpResponse = $this->createMock(ResponseInterface::class);
472
-		$this->userSession
473
-			->expects($this->any())
474
-			->method('isLoggedIn')
475
-			->willReturn(false);
476
-		$httpRequest
477
-			->expects($this->exactly(2))
478
-			->method('getHeader')
479
-			->willReturnMap([
480
-				['X-Requested-With', 'XMLHttpRequest'],
481
-				['Authorization', null],
482
-			]);
483
-
484
-		$this->auth->check($httpRequest, $httpResponse);
485
-	}
486
-
487
-	public function testAuthenticateWithBasicAuthenticateHeadersProvidedWithAjax(): void {
488
-		// No CSRF
489
-		$this->request
490
-			->expects($this->once())
491
-			->method('passesCSRFCheck')
492
-			->willReturn(false);
493
-
494
-		/** @var \Sabre\HTTP\RequestInterface&MockObject $httpRequest */
495
-		$httpRequest = $this->createMock(RequestInterface::class);
496
-		/** @var \Sabre\HTTP\ResponseInterface&MockObject $httpResponse */
497
-		$httpResponse = $this->createMock(ResponseInterface::class);
498
-		$httpRequest
499
-			->expects($this->any())
500
-			->method('getHeader')
501
-			->willReturnMap([
502
-				['X-Requested-With', 'XMLHttpRequest'],
503
-				['Authorization', 'basic dXNlcm5hbWU6cGFzc3dvcmQ='],
504
-			]);
505
-
506
-		$user = $this->createMock(IUser::class);
507
-		$user->expects($this->any())
508
-			->method('getUID')
509
-			->willReturn('MyDavUser');
510
-		$this->userSession
511
-			->expects($this->any())
512
-			->method('isLoggedIn')
513
-			->willReturn(false);
514
-		$this->userSession
515
-			->expects($this->once())
516
-			->method('logClientIn')
517
-			->with('username', 'password')
518
-			->willReturn(true);
519
-		$this->userSession
520
-			->expects($this->any())
521
-			->method('getUser')
522
-			->willReturn($user);
523
-
524
-		$this->auth->check($httpRequest, $httpResponse);
525
-	}
526
-
527
-	public function testAuthenticateNoBasicAuthenticateHeadersProvidedWithAjaxButUserIsStillLoggedIn(): void {
528
-		/** @var \Sabre\HTTP\RequestInterface $httpRequest */
529
-		$httpRequest = $this->createMock(RequestInterface::class);
530
-		/** @var \Sabre\HTTP\ResponseInterface $httpResponse */
531
-		$httpResponse = $this->createMock(ResponseInterface::class);
532
-		$user = $this->createMock(IUser::class);
533
-		$user->method('getUID')->willReturn('MyTestUser');
534
-		$this->userSession
535
-			->expects($this->any())
536
-			->method('isLoggedIn')
537
-			->willReturn(true);
538
-		$this->userSession
539
-			->expects($this->any())
540
-			->method('getUser')
541
-			->willReturn($user);
542
-		$this->session
543
-			->expects($this->atLeastOnce())
544
-			->method('get')
545
-			->with('AUTHENTICATED_TO_DAV_BACKEND')
546
-			->willReturn('MyTestUser');
547
-		$this->request
548
-			->expects($this->once())
549
-			->method('getMethod')
550
-			->willReturn('GET');
551
-		$httpRequest
552
-			->expects($this->atLeastOnce())
553
-			->method('getHeader')
554
-			->with('Authorization')
555
-			->willReturn(null);
556
-		$this->assertEquals(
557
-			[true, 'principals/users/MyTestUser'],
558
-			$this->auth->check($httpRequest, $httpResponse)
559
-		);
560
-	}
561
-
562
-	public function testAuthenticateValidCredentials(): void {
563
-		$server = $this->createMock(Server::class);
564
-		$server->httpRequest = $this->createMock(RequestInterface::class);
565
-		$server->httpRequest
566
-			->expects($this->once())
567
-			->method('getHeader')
568
-			->with('Authorization')
569
-			->willReturn('basic dXNlcm5hbWU6cGFzc3dvcmQ=');
570
-
571
-		$server->httpResponse = $this->createMock(ResponseInterface::class);
572
-		$this->userSession
573
-			->expects($this->once())
574
-			->method('logClientIn')
575
-			->with('username', 'password')
576
-			->willReturn(true);
577
-		$user = $this->createMock(IUser::class);
578
-		$user->expects($this->exactly(2))
579
-			->method('getUID')
580
-			->willReturn('MyTestUser');
581
-		$this->userSession
582
-			->expects($this->exactly(3))
583
-			->method('getUser')
584
-			->willReturn($user);
585
-		$response = $this->auth->check($server->httpRequest, $server->httpResponse);
586
-		$this->assertEquals([true, 'principals/users/MyTestUser'], $response);
587
-	}
588
-
589
-	public function testAuthenticateInvalidCredentials(): void {
590
-		$server = $this->createMock(Server::class);
591
-		$server->httpRequest = $this->createMock(RequestInterface::class);
592
-		$server->httpRequest
593
-			->expects($this->exactly(2))
594
-			->method('getHeader')
595
-			->willReturnMap([
596
-				['Authorization', 'basic dXNlcm5hbWU6cGFzc3dvcmQ='],
597
-				['X-Requested-With', null],
598
-			]);
599
-		$server->httpResponse = $this->createMock(ResponseInterface::class);
600
-		$this->userSession
601
-			->expects($this->once())
602
-			->method('logClientIn')
603
-			->with('username', 'password')
604
-			->willReturn(false);
605
-		$response = $this->auth->check($server->httpRequest, $server->httpResponse);
606
-		$this->assertEquals([false, 'Username or password was incorrect'], $response);
607
-	}
33
+    private ISession&MockObject $session;
34
+    private Session&MockObject $userSession;
35
+    private IRequest&MockObject $request;
36
+    private Manager&MockObject $twoFactorManager;
37
+    private IThrottler&MockObject $throttler;
38
+    private Auth $auth;
39
+
40
+    protected function setUp(): void {
41
+        parent::setUp();
42
+        $this->session = $this->createMock(ISession::class);
43
+        $this->userSession = $this->createMock(Session::class);
44
+        $this->request = $this->createMock(IRequest::class);
45
+        $this->twoFactorManager = $this->createMock(Manager::class);
46
+        $this->throttler = $this->createMock(IThrottler::class);
47
+        $this->auth = new Auth(
48
+            $this->session,
49
+            $this->userSession,
50
+            $this->request,
51
+            $this->twoFactorManager,
52
+            $this->throttler
53
+        );
54
+    }
55
+
56
+    public function testIsDavAuthenticatedWithoutDavSession(): void {
57
+        $this->session
58
+            ->expects($this->once())
59
+            ->method('get')
60
+            ->with('AUTHENTICATED_TO_DAV_BACKEND')
61
+            ->willReturn(null);
62
+
63
+        $this->assertFalse(self::invokePrivate($this->auth, 'isDavAuthenticated', ['MyTestUser']));
64
+    }
65
+
66
+    public function testIsDavAuthenticatedWithWrongDavSession(): void {
67
+        $this->session
68
+            ->expects($this->exactly(2))
69
+            ->method('get')
70
+            ->with('AUTHENTICATED_TO_DAV_BACKEND')
71
+            ->willReturn('AnotherUser');
72
+
73
+        $this->assertFalse(self::invokePrivate($this->auth, 'isDavAuthenticated', ['MyTestUser']));
74
+    }
75
+
76
+    public function testIsDavAuthenticatedWithCorrectDavSession(): void {
77
+        $this->session
78
+            ->expects($this->exactly(2))
79
+            ->method('get')
80
+            ->with('AUTHENTICATED_TO_DAV_BACKEND')
81
+            ->willReturn('MyTestUser');
82
+
83
+        $this->assertTrue(self::invokePrivate($this->auth, 'isDavAuthenticated', ['MyTestUser']));
84
+    }
85
+
86
+    public function testValidateUserPassOfAlreadyDAVAuthenticatedUser(): void {
87
+        $user = $this->createMock(IUser::class);
88
+        $user->expects($this->exactly(1))
89
+            ->method('getUID')
90
+            ->willReturn('MyTestUser');
91
+        $this->userSession
92
+            ->expects($this->once())
93
+            ->method('isLoggedIn')
94
+            ->willReturn(true);
95
+        $this->userSession
96
+            ->expects($this->exactly(1))
97
+            ->method('getUser')
98
+            ->willReturn($user);
99
+        $this->session
100
+            ->expects($this->exactly(2))
101
+            ->method('get')
102
+            ->with('AUTHENTICATED_TO_DAV_BACKEND')
103
+            ->willReturn('MyTestUser');
104
+        $this->session
105
+            ->expects($this->once())
106
+            ->method('close');
107
+
108
+        $this->assertTrue(self::invokePrivate($this->auth, 'validateUserPass', ['MyTestUser', 'MyTestPassword']));
109
+    }
110
+
111
+    public function testValidateUserPassOfInvalidDAVAuthenticatedUser(): void {
112
+        $user = $this->createMock(IUser::class);
113
+        $user->expects($this->once())
114
+            ->method('getUID')
115
+            ->willReturn('MyTestUser');
116
+        $this->userSession
117
+            ->expects($this->once())
118
+            ->method('isLoggedIn')
119
+            ->willReturn(true);
120
+        $this->userSession
121
+            ->expects($this->once())
122
+            ->method('getUser')
123
+            ->willReturn($user);
124
+        $this->session
125
+            ->expects($this->exactly(2))
126
+            ->method('get')
127
+            ->with('AUTHENTICATED_TO_DAV_BACKEND')
128
+            ->willReturn('AnotherUser');
129
+        $this->session
130
+            ->expects($this->once())
131
+            ->method('close');
132
+
133
+        $this->assertFalse(self::invokePrivate($this->auth, 'validateUserPass', ['MyTestUser', 'MyTestPassword']));
134
+    }
135
+
136
+    public function testValidateUserPassOfInvalidDAVAuthenticatedUserWithValidPassword(): void {
137
+        $user = $this->createMock(IUser::class);
138
+        $user->expects($this->exactly(2))
139
+            ->method('getUID')
140
+            ->willReturn('MyTestUser');
141
+        $this->userSession
142
+            ->expects($this->once())
143
+            ->method('isLoggedIn')
144
+            ->willReturn(true);
145
+        $this->userSession
146
+            ->expects($this->exactly(2))
147
+            ->method('getUser')
148
+            ->willReturn($user);
149
+        $this->session
150
+            ->expects($this->exactly(2))
151
+            ->method('get')
152
+            ->with('AUTHENTICATED_TO_DAV_BACKEND')
153
+            ->willReturn('AnotherUser');
154
+        $this->userSession
155
+            ->expects($this->once())
156
+            ->method('logClientIn')
157
+            ->with('MyTestUser', 'MyTestPassword', $this->request)
158
+            ->willReturn(true);
159
+        $this->session
160
+            ->expects($this->once())
161
+            ->method('set')
162
+            ->with('AUTHENTICATED_TO_DAV_BACKEND', 'MyTestUser');
163
+        $this->session
164
+            ->expects($this->once())
165
+            ->method('close');
166
+
167
+        $this->assertTrue(self::invokePrivate($this->auth, 'validateUserPass', ['MyTestUser', 'MyTestPassword']));
168
+    }
169
+
170
+    public function testValidateUserPassWithInvalidPassword(): void {
171
+        $this->userSession
172
+            ->expects($this->once())
173
+            ->method('isLoggedIn')
174
+            ->willReturn(false);
175
+        $this->userSession
176
+            ->expects($this->once())
177
+            ->method('logClientIn')
178
+            ->with('MyTestUser', 'MyTestPassword')
179
+            ->willReturn(false);
180
+        $this->session
181
+            ->expects($this->once())
182
+            ->method('close');
183
+
184
+        $this->assertFalse(self::invokePrivate($this->auth, 'validateUserPass', ['MyTestUser', 'MyTestPassword']));
185
+    }
186
+
187
+
188
+    public function testValidateUserPassWithPasswordLoginForbidden(): void {
189
+        $this->expectException(PasswordLoginForbidden::class);
190
+
191
+        $this->userSession
192
+            ->expects($this->once())
193
+            ->method('isLoggedIn')
194
+            ->willReturn(false);
195
+        $this->userSession
196
+            ->expects($this->once())
197
+            ->method('logClientIn')
198
+            ->with('MyTestUser', 'MyTestPassword')
199
+            ->willThrowException(new PasswordLoginForbiddenException());
200
+        $this->session
201
+            ->expects($this->once())
202
+            ->method('close');
203
+
204
+        self::invokePrivate($this->auth, 'validateUserPass', ['MyTestUser', 'MyTestPassword']);
205
+    }
206
+
207
+    public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenForNonGet(): void {
208
+        $request = $this->createMock(RequestInterface::class);
209
+        $response = $this->createMock(ResponseInterface::class);
210
+        $this->userSession
211
+            ->expects($this->any())
212
+            ->method('isLoggedIn')
213
+            ->willReturn(true);
214
+        $this->request
215
+            ->expects($this->any())
216
+            ->method('getMethod')
217
+            ->willReturn('POST');
218
+        $this->session
219
+            ->expects($this->any())
220
+            ->method('get')
221
+            ->with('AUTHENTICATED_TO_DAV_BACKEND')
222
+            ->willReturn(null);
223
+        $user = $this->createMock(IUser::class);
224
+        $user->expects($this->any())
225
+            ->method('getUID')
226
+            ->willReturn('MyWrongDavUser');
227
+        $this->userSession
228
+            ->expects($this->any())
229
+            ->method('getUser')
230
+            ->willReturn($user);
231
+        $this->request
232
+            ->expects($this->once())
233
+            ->method('passesCSRFCheck')
234
+            ->willReturn(false);
235
+
236
+        $expectedResponse = [
237
+            false,
238
+            "No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured",
239
+        ];
240
+        $response = $this->auth->check($request, $response);
241
+        $this->assertSame($expectedResponse, $response);
242
+    }
243
+
244
+    public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenAndCorrectlyDavAuthenticated(): void {
245
+        $request = $this->createMock(RequestInterface::class);
246
+        $response = $this->createMock(ResponseInterface::class);
247
+        $this->userSession
248
+            ->expects($this->any())
249
+            ->method('isLoggedIn')
250
+            ->willReturn(true);
251
+        $this->request
252
+            ->expects($this->any())
253
+            ->method('getMethod')
254
+            ->willReturn('PROPFIND');
255
+        $this->request
256
+            ->expects($this->any())
257
+            ->method('isUserAgent')
258
+            ->willReturn(false);
259
+        $this->session
260
+            ->expects($this->any())
261
+            ->method('get')
262
+            ->with('AUTHENTICATED_TO_DAV_BACKEND')
263
+            ->willReturn('LoggedInUser');
264
+        $user = $this->createMock(IUser::class);
265
+        $user->expects($this->any())
266
+            ->method('getUID')
267
+            ->willReturn('LoggedInUser');
268
+        $this->userSession
269
+            ->expects($this->any())
270
+            ->method('getUser')
271
+            ->willReturn($user);
272
+        $this->request
273
+            ->expects($this->once())
274
+            ->method('passesCSRFCheck')
275
+            ->willReturn(false);
276
+        $this->auth->check($request, $response);
277
+    }
278
+
279
+
280
+    public function testAuthenticateAlreadyLoggedInWithoutTwoFactorChallengePassed(): void {
281
+        $this->expectException(\Sabre\DAV\Exception\NotAuthenticated::class);
282
+        $this->expectExceptionMessage('2FA challenge not passed.');
283
+
284
+        $request = $this->createMock(RequestInterface::class);
285
+        $response = $this->createMock(ResponseInterface::class);
286
+        $this->userSession
287
+            ->expects($this->any())
288
+            ->method('isLoggedIn')
289
+            ->willReturn(true);
290
+        $this->request
291
+            ->expects($this->any())
292
+            ->method('getMethod')
293
+            ->willReturn('PROPFIND');
294
+        $this->request
295
+            ->expects($this->any())
296
+            ->method('isUserAgent')
297
+            ->willReturn(false);
298
+        $this->session
299
+            ->expects($this->any())
300
+            ->method('get')
301
+            ->with('AUTHENTICATED_TO_DAV_BACKEND')
302
+            ->willReturn('LoggedInUser');
303
+        $user = $this->createMock(IUser::class);
304
+        $user->expects($this->any())
305
+            ->method('getUID')
306
+            ->willReturn('LoggedInUser');
307
+        $this->userSession
308
+            ->expects($this->any())
309
+            ->method('getUser')
310
+            ->willReturn($user);
311
+        $this->request
312
+            ->expects($this->once())
313
+            ->method('passesCSRFCheck')
314
+            ->willReturn(true);
315
+        $this->twoFactorManager->expects($this->once())
316
+            ->method('needsSecondFactor')
317
+            ->with($user)
318
+            ->willReturn(true);
319
+        $this->auth->check($request, $response);
320
+    }
321
+
322
+
323
+    public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenAndIncorrectlyDavAuthenticated(): void {
324
+        $this->expectException(\Sabre\DAV\Exception\NotAuthenticated::class);
325
+        $this->expectExceptionMessage('CSRF check not passed.');
326
+
327
+        $request = $this->createMock(RequestInterface::class);
328
+        $response = $this->createMock(ResponseInterface::class);
329
+        $this->userSession
330
+            ->expects($this->any())
331
+            ->method('isLoggedIn')
332
+            ->willReturn(true);
333
+        $this->request
334
+            ->expects($this->any())
335
+            ->method('getMethod')
336
+            ->willReturn('PROPFIND');
337
+        $this->request
338
+            ->expects($this->any())
339
+            ->method('isUserAgent')
340
+            ->willReturn(false);
341
+        $this->session
342
+            ->expects($this->any())
343
+            ->method('get')
344
+            ->with('AUTHENTICATED_TO_DAV_BACKEND')
345
+            ->willReturn('AnotherUser');
346
+        $user = $this->createMock(IUser::class);
347
+        $user->expects($this->any())
348
+            ->method('getUID')
349
+            ->willReturn('LoggedInUser');
350
+        $this->userSession
351
+            ->expects($this->any())
352
+            ->method('getUser')
353
+            ->willReturn($user);
354
+        $this->request
355
+            ->expects($this->once())
356
+            ->method('passesCSRFCheck')
357
+            ->willReturn(false);
358
+        $this->auth->check($request, $response);
359
+    }
360
+
361
+    public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenForNonGetAndDesktopClient(): void {
362
+        $request = $this->createMock(RequestInterface::class);
363
+        $response = $this->createMock(ResponseInterface::class);
364
+        $this->userSession
365
+            ->expects($this->any())
366
+            ->method('isLoggedIn')
367
+            ->willReturn(true);
368
+        $this->request
369
+            ->expects($this->any())
370
+            ->method('getMethod')
371
+            ->willReturn('POST');
372
+        $this->request
373
+            ->expects($this->any())
374
+            ->method('isUserAgent')
375
+            ->willReturn(true);
376
+        $this->session
377
+            ->expects($this->any())
378
+            ->method('get')
379
+            ->with('AUTHENTICATED_TO_DAV_BACKEND')
380
+            ->willReturn(null);
381
+        $user = $this->createMock(IUser::class);
382
+        $user->expects($this->any())
383
+            ->method('getUID')
384
+            ->willReturn('MyWrongDavUser');
385
+        $this->userSession
386
+            ->expects($this->any())
387
+            ->method('getUser')
388
+            ->willReturn($user);
389
+        $this->request
390
+            ->expects($this->once())
391
+            ->method('passesCSRFCheck')
392
+            ->willReturn(false);
393
+
394
+        $this->auth->check($request, $response);
395
+    }
396
+
397
+    public function testAuthenticateAlreadyLoggedInWithoutCsrfTokenForGet(): void {
398
+        $request = $this->createMock(RequestInterface::class);
399
+        $response = $this->createMock(ResponseInterface::class);
400
+        $this->userSession
401
+            ->expects($this->any())
402
+            ->method('isLoggedIn')
403
+            ->willReturn(true);
404
+        $this->session
405
+            ->expects($this->any())
406
+            ->method('get')
407
+            ->with('AUTHENTICATED_TO_DAV_BACKEND')
408
+            ->willReturn(null);
409
+        $user = $this->createMock(IUser::class);
410
+        $user->expects($this->any())
411
+            ->method('getUID')
412
+            ->willReturn('MyWrongDavUser');
413
+        $this->userSession
414
+            ->expects($this->any())
415
+            ->method('getUser')
416
+            ->willReturn($user);
417
+        $this->request
418
+            ->expects($this->any())
419
+            ->method('getMethod')
420
+            ->willReturn('GET');
421
+
422
+        $response = $this->auth->check($request, $response);
423
+        $this->assertEquals([true, 'principals/users/MyWrongDavUser'], $response);
424
+    }
425
+
426
+    public function testAuthenticateAlreadyLoggedInWithCsrfTokenForGet(): void {
427
+        $request = $this->createMock(RequestInterface::class);
428
+        $response = $this->createMock(ResponseInterface::class);
429
+        $this->userSession
430
+            ->expects($this->any())
431
+            ->method('isLoggedIn')
432
+            ->willReturn(true);
433
+        $this->session
434
+            ->expects($this->any())
435
+            ->method('get')
436
+            ->with('AUTHENTICATED_TO_DAV_BACKEND')
437
+            ->willReturn(null);
438
+        $user = $this->createMock(IUser::class);
439
+        $user->expects($this->any())
440
+            ->method('getUID')
441
+            ->willReturn('MyWrongDavUser');
442
+        $this->userSession
443
+            ->expects($this->any())
444
+            ->method('getUser')
445
+            ->willReturn($user);
446
+        $this->request
447
+            ->expects($this->once())
448
+            ->method('passesCSRFCheck')
449
+            ->willReturn(true);
450
+
451
+        $response = $this->auth->check($request, $response);
452
+        $this->assertEquals([true, 'principals/users/MyWrongDavUser'], $response);
453
+    }
454
+
455
+    public function testAuthenticateNoBasicAuthenticateHeadersProvided(): void {
456
+        $server = $this->createMock(Server::class);
457
+        $server->httpRequest = $this->createMock(RequestInterface::class);
458
+        $server->httpResponse = $this->createMock(ResponseInterface::class);
459
+        $response = $this->auth->check($server->httpRequest, $server->httpResponse);
460
+        $this->assertEquals([false, 'No \'Authorization: Basic\' header found. Either the client didn\'t send one, or the server is misconfigured'], $response);
461
+    }
462
+
463
+
464
+    public function testAuthenticateNoBasicAuthenticateHeadersProvidedWithAjax(): void {
465
+        $this->expectException(\Sabre\DAV\Exception\NotAuthenticated::class);
466
+        $this->expectExceptionMessage('Cannot authenticate over ajax calls');
467
+
468
+        /** @var \Sabre\HTTP\RequestInterface&MockObject $httpRequest */
469
+        $httpRequest = $this->createMock(RequestInterface::class);
470
+        /** @var \Sabre\HTTP\ResponseInterface&MockObject $httpResponse */
471
+        $httpResponse = $this->createMock(ResponseInterface::class);
472
+        $this->userSession
473
+            ->expects($this->any())
474
+            ->method('isLoggedIn')
475
+            ->willReturn(false);
476
+        $httpRequest
477
+            ->expects($this->exactly(2))
478
+            ->method('getHeader')
479
+            ->willReturnMap([
480
+                ['X-Requested-With', 'XMLHttpRequest'],
481
+                ['Authorization', null],
482
+            ]);
483
+
484
+        $this->auth->check($httpRequest, $httpResponse);
485
+    }
486
+
487
+    public function testAuthenticateWithBasicAuthenticateHeadersProvidedWithAjax(): void {
488
+        // No CSRF
489
+        $this->request
490
+            ->expects($this->once())
491
+            ->method('passesCSRFCheck')
492
+            ->willReturn(false);
493
+
494
+        /** @var \Sabre\HTTP\RequestInterface&MockObject $httpRequest */
495
+        $httpRequest = $this->createMock(RequestInterface::class);
496
+        /** @var \Sabre\HTTP\ResponseInterface&MockObject $httpResponse */
497
+        $httpResponse = $this->createMock(ResponseInterface::class);
498
+        $httpRequest
499
+            ->expects($this->any())
500
+            ->method('getHeader')
501
+            ->willReturnMap([
502
+                ['X-Requested-With', 'XMLHttpRequest'],
503
+                ['Authorization', 'basic dXNlcm5hbWU6cGFzc3dvcmQ='],
504
+            ]);
505
+
506
+        $user = $this->createMock(IUser::class);
507
+        $user->expects($this->any())
508
+            ->method('getUID')
509
+            ->willReturn('MyDavUser');
510
+        $this->userSession
511
+            ->expects($this->any())
512
+            ->method('isLoggedIn')
513
+            ->willReturn(false);
514
+        $this->userSession
515
+            ->expects($this->once())
516
+            ->method('logClientIn')
517
+            ->with('username', 'password')
518
+            ->willReturn(true);
519
+        $this->userSession
520
+            ->expects($this->any())
521
+            ->method('getUser')
522
+            ->willReturn($user);
523
+
524
+        $this->auth->check($httpRequest, $httpResponse);
525
+    }
526
+
527
+    public function testAuthenticateNoBasicAuthenticateHeadersProvidedWithAjaxButUserIsStillLoggedIn(): void {
528
+        /** @var \Sabre\HTTP\RequestInterface $httpRequest */
529
+        $httpRequest = $this->createMock(RequestInterface::class);
530
+        /** @var \Sabre\HTTP\ResponseInterface $httpResponse */
531
+        $httpResponse = $this->createMock(ResponseInterface::class);
532
+        $user = $this->createMock(IUser::class);
533
+        $user->method('getUID')->willReturn('MyTestUser');
534
+        $this->userSession
535
+            ->expects($this->any())
536
+            ->method('isLoggedIn')
537
+            ->willReturn(true);
538
+        $this->userSession
539
+            ->expects($this->any())
540
+            ->method('getUser')
541
+            ->willReturn($user);
542
+        $this->session
543
+            ->expects($this->atLeastOnce())
544
+            ->method('get')
545
+            ->with('AUTHENTICATED_TO_DAV_BACKEND')
546
+            ->willReturn('MyTestUser');
547
+        $this->request
548
+            ->expects($this->once())
549
+            ->method('getMethod')
550
+            ->willReturn('GET');
551
+        $httpRequest
552
+            ->expects($this->atLeastOnce())
553
+            ->method('getHeader')
554
+            ->with('Authorization')
555
+            ->willReturn(null);
556
+        $this->assertEquals(
557
+            [true, 'principals/users/MyTestUser'],
558
+            $this->auth->check($httpRequest, $httpResponse)
559
+        );
560
+    }
561
+
562
+    public function testAuthenticateValidCredentials(): void {
563
+        $server = $this->createMock(Server::class);
564
+        $server->httpRequest = $this->createMock(RequestInterface::class);
565
+        $server->httpRequest
566
+            ->expects($this->once())
567
+            ->method('getHeader')
568
+            ->with('Authorization')
569
+            ->willReturn('basic dXNlcm5hbWU6cGFzc3dvcmQ=');
570
+
571
+        $server->httpResponse = $this->createMock(ResponseInterface::class);
572
+        $this->userSession
573
+            ->expects($this->once())
574
+            ->method('logClientIn')
575
+            ->with('username', 'password')
576
+            ->willReturn(true);
577
+        $user = $this->createMock(IUser::class);
578
+        $user->expects($this->exactly(2))
579
+            ->method('getUID')
580
+            ->willReturn('MyTestUser');
581
+        $this->userSession
582
+            ->expects($this->exactly(3))
583
+            ->method('getUser')
584
+            ->willReturn($user);
585
+        $response = $this->auth->check($server->httpRequest, $server->httpResponse);
586
+        $this->assertEquals([true, 'principals/users/MyTestUser'], $response);
587
+    }
588
+
589
+    public function testAuthenticateInvalidCredentials(): void {
590
+        $server = $this->createMock(Server::class);
591
+        $server->httpRequest = $this->createMock(RequestInterface::class);
592
+        $server->httpRequest
593
+            ->expects($this->exactly(2))
594
+            ->method('getHeader')
595
+            ->willReturnMap([
596
+                ['Authorization', 'basic dXNlcm5hbWU6cGFzc3dvcmQ='],
597
+                ['X-Requested-With', null],
598
+            ]);
599
+        $server->httpResponse = $this->createMock(ResponseInterface::class);
600
+        $this->userSession
601
+            ->expects($this->once())
602
+            ->method('logClientIn')
603
+            ->with('username', 'password')
604
+            ->willReturn(false);
605
+        $response = $this->auth->check($server->httpRequest, $server->httpResponse);
606
+        $this->assertEquals([false, 'Username or password was incorrect'], $response);
607
+    }
608 608
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Connector/Sabre/RequestTest/DeleteTest.php 1 patch
Indentation   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -19,25 +19,25 @@
 block discarded – undo
19 19
  * @package OCA\DAV\Tests\unit\Connector\Sabre\RequestTest
20 20
  */
21 21
 class DeleteTest extends RequestTestCase {
22
-	public function testBasicUpload(): void {
23
-		$user = self::getUniqueID();
24
-		$view = $this->setupUser($user, 'pass');
22
+    public function testBasicUpload(): void {
23
+        $user = self::getUniqueID();
24
+        $view = $this->setupUser($user, 'pass');
25 25
 
26
-		$view->file_put_contents('foo.txt', 'asd');
27
-		$mount = $view->getMount('foo.txt');
28
-		$internalPath = $view->getAbsolutePath();
26
+        $view->file_put_contents('foo.txt', 'asd');
27
+        $mount = $view->getMount('foo.txt');
28
+        $internalPath = $view->getAbsolutePath();
29 29
 
30
-		// create a ghost file
31
-		$mount->getStorage()->unlink($mount->getInternalPath($internalPath));
30
+        // create a ghost file
31
+        $mount->getStorage()->unlink($mount->getInternalPath($internalPath));
32 32
 
33
-		// cache entry still exists
34
-		$this->assertInstanceOf(FileInfo::class, $view->getFileInfo('foo.txt'));
33
+        // cache entry still exists
34
+        $this->assertInstanceOf(FileInfo::class, $view->getFileInfo('foo.txt'));
35 35
 
36
-		$response = $this->request($view, $user, 'pass', 'DELETE', '/foo.txt');
36
+        $response = $this->request($view, $user, 'pass', 'DELETE', '/foo.txt');
37 37
 
38
-		$this->assertEquals(Http::STATUS_NO_CONTENT, $response->getStatus());
38
+        $this->assertEquals(Http::STATUS_NO_CONTENT, $response->getStatus());
39 39
 
40
-		// no longer in the cache
41
-		$this->assertFalse($view->getFileInfo('foo.txt'));
42
-	}
40
+        // no longer in the cache
41
+        $this->assertFalse($view->getFileInfo('foo.txt'));
42
+    }
43 43
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Connector/Sabre/ExceptionLoggerPluginTest.php 1 patch
Indentation   +38 added lines, -38 removed lines patch added patch discarded remove patch
@@ -19,48 +19,48 @@
 block discarded – undo
19 19
 use Test\TestCase;
20 20
 
21 21
 class ExceptionLoggerPluginTest extends TestCase {
22
-	private Server $server;
23
-	private ExceptionLoggerPlugin $plugin;
24
-	private LoggerInterface&MockObject $logger;
22
+    private Server $server;
23
+    private ExceptionLoggerPlugin $plugin;
24
+    private LoggerInterface&MockObject $logger;
25 25
 
26
-	private function init(): void {
27
-		$config = $this->createMock(SystemConfig::class);
28
-		$config->expects($this->any())
29
-			->method('getValue')
30
-			->willReturnCallback(function ($key, $default) {
31
-				switch ($key) {
32
-					case 'loglevel':
33
-						return 0;
34
-					default:
35
-						return $default;
36
-				}
37
-			});
26
+    private function init(): void {
27
+        $config = $this->createMock(SystemConfig::class);
28
+        $config->expects($this->any())
29
+            ->method('getValue')
30
+            ->willReturnCallback(function ($key, $default) {
31
+                switch ($key) {
32
+                    case 'loglevel':
33
+                        return 0;
34
+                    default:
35
+                        return $default;
36
+                }
37
+            });
38 38
 
39
-		$this->server = new Server();
40
-		$this->logger = $this->createMock(LoggerInterface::class);
41
-		$this->plugin = new ExceptionLoggerPlugin('unit-test', $this->logger);
42
-		$this->plugin->initialize($this->server);
43
-	}
39
+        $this->server = new Server();
40
+        $this->logger = $this->createMock(LoggerInterface::class);
41
+        $this->plugin = new ExceptionLoggerPlugin('unit-test', $this->logger);
42
+        $this->plugin->initialize($this->server);
43
+    }
44 44
 
45
-	#[\PHPUnit\Framework\Attributes\DataProvider('providesExceptions')]
46
-	public function testLogging(string $expectedLogLevel, \Throwable $e): void {
47
-		$this->init();
45
+    #[\PHPUnit\Framework\Attributes\DataProvider('providesExceptions')]
46
+    public function testLogging(string $expectedLogLevel, \Throwable $e): void {
47
+        $this->init();
48 48
 
49
-		$this->logger->expects($this->once())
50
-			->method($expectedLogLevel)
51
-			->with($e->getMessage(), ['app' => 'unit-test','exception' => $e]);
49
+        $this->logger->expects($this->once())
50
+            ->method($expectedLogLevel)
51
+            ->with($e->getMessage(), ['app' => 'unit-test','exception' => $e]);
52 52
 
53
-		$this->plugin->logException($e);
54
-	}
53
+        $this->plugin->logException($e);
54
+    }
55 55
 
56
-	public static function providesExceptions(): array {
57
-		return [
58
-			['debug', new NotFound()],
59
-			['debug', new ServerMaintenanceMode('System is in maintenance mode.')],
60
-			// Faking a translation
61
-			['debug', new ServerMaintenanceMode('Syst3m 1s 1n m41nt3n4nc3 m0d3.')],
62
-			['debug', new ServerMaintenanceMode('Upgrade needed')],
63
-			['critical', new InvalidPath('This path leads to nowhere')]
64
-		];
65
-	}
56
+    public static function providesExceptions(): array {
57
+        return [
58
+            ['debug', new NotFound()],
59
+            ['debug', new ServerMaintenanceMode('System is in maintenance mode.')],
60
+            // Faking a translation
61
+            ['debug', new ServerMaintenanceMode('Syst3m 1s 1n m41nt3n4nc3 m0d3.')],
62
+            ['debug', new ServerMaintenanceMode('Upgrade needed')],
63
+            ['critical', new InvalidPath('This path leads to nowhere')]
64
+        ];
65
+    }
66 66
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Connector/Sabre/BlockLegacyClientPluginTest.php 1 patch
Indentation   +148 added lines, -148 removed lines patch added patch discarded remove patch
@@ -17,9 +17,9 @@  discard block
 block discarded – undo
17 17
 use Test\TestCase;
18 18
 
19 19
 enum ERROR_TYPE {
20
-	case MIN_ERROR;
21
-	case MAX_ERROR;
22
-	case NONE;
20
+    case MIN_ERROR;
21
+    case MAX_ERROR;
22
+    case NONE;
23 23
 }
24 24
 
25 25
 /**
@@ -29,149 +29,149 @@  discard block
 block discarded – undo
29 29
  */
30 30
 class BlockLegacyClientPluginTest extends TestCase {
31 31
 
32
-	private IConfig&MockObject $config;
33
-	private ThemingDefaults&MockObject $themingDefaults;
34
-	private BlockLegacyClientPlugin $blockLegacyClientVersionPlugin;
35
-
36
-	protected function setUp(): void {
37
-		parent::setUp();
38
-
39
-		$this->config = $this->createMock(IConfig::class);
40
-		$this->themingDefaults = $this->createMock(ThemingDefaults::class);
41
-		$this->blockLegacyClientVersionPlugin = new BlockLegacyClientPlugin(
42
-			$this->config,
43
-			$this->themingDefaults,
44
-		);
45
-	}
46
-
47
-	public static function oldDesktopClientProvider(): array {
48
-		return [
49
-			['Mozilla/5.0 (Windows) mirall/1.5.0', ERROR_TYPE::MIN_ERROR],
50
-			['Mozilla/5.0 (Bogus Text) mirall/1.6.9', ERROR_TYPE::MIN_ERROR],
51
-			['Mozilla/5.0 (Windows) mirall/2.5.0', ERROR_TYPE::MAX_ERROR],
52
-			['Mozilla/5.0 (Bogus Text) mirall/2.0.1', ERROR_TYPE::MAX_ERROR],
53
-			['Mozilla/5.0 (Windows) mirall/2.0.0', ERROR_TYPE::NONE],
54
-			['Mozilla/5.0 (Bogus Text) mirall/2.0.0', ERROR_TYPE::NONE],
55
-		];
56
-	}
57
-
58
-	#[\PHPUnit\Framework\Attributes\DataProvider('oldDesktopClientProvider')]
59
-	public function testBeforeHandlerException(string $userAgent, ERROR_TYPE $errorType): void {
60
-		$this->themingDefaults
61
-			->expects($this->atMost(1))
62
-			->method('getSyncClientUrl')
63
-			->willReturn('https://nextcloud.com/install/#install-clients');
64
-
65
-		$this->config
66
-			->expects($this->exactly(2))
67
-			->method('getSystemValueString')
68
-			->willReturnCallback(function (string $key) {
69
-				if ($key === 'minimum.supported.desktop.version') {
70
-					return '1.7.0';
71
-				}
72
-				return '2.0.0';
73
-			});
74
-
75
-		if ($errorType !== ERROR_TYPE::NONE) {
76
-			$errorString = $errorType === ERROR_TYPE::MIN_ERROR
77
-			? 'This version of the client is unsupported. Upgrade to <a href="https://nextcloud.com/install/#install-clients">version 1.7.0 or later</a>.'
78
-			: 'This version of the client is unsupported. Downgrade to <a href="https://nextcloud.com/install/#install-clients">version 2.0.0 or earlier</a>.';
79
-			$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
80
-			$this->expectExceptionMessage($errorString);
81
-		}
82
-
83
-		/** @var RequestInterface|MockObject $request */
84
-		$request = $this->createMock(RequestInterface::class);
85
-		$request
86
-			->expects($this->once())
87
-			->method('getHeader')
88
-			->with('User-Agent')
89
-			->willReturn($userAgent);
90
-
91
-		$this->blockLegacyClientVersionPlugin->beforeHandler($request);
92
-	}
93
-
94
-	/**
95
-	 * Ensure that there is no room for XSS attack through configured URL / version
96
-	 */
97
-	#[\PHPUnit\Framework\Attributes\DataProvider('oldDesktopClientProvider')]
98
-	public function testBeforeHandlerExceptionPreventXSSAttack(string $userAgent, ERROR_TYPE $errorType): void {
99
-		$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
100
-
101
-		$this->themingDefaults
102
-			->expects($this->atMost(1))
103
-			->method('getSyncClientUrl')
104
-			->willReturn('https://example.com"><script>alter("hacked");</script>');
105
-
106
-		$this->config
107
-			->expects($this->exactly(2))
108
-			->method('getSystemValueString')
109
-			->willReturnCallback(function (string $key) {
110
-				if ($key === 'minimum.supported.desktop.version') {
111
-					return '1.7.0 <script>alert("unsafe")</script>';
112
-				}
113
-				return '2.0.0 <script>alert("unsafe")</script>';
114
-			});
115
-
116
-		$errorString = $errorType === ERROR_TYPE::MIN_ERROR
117
-			? 'This version of the client is unsupported. Upgrade to <a href="https://example.com&quot;&gt;&lt;script&gt;alter(&quot;hacked&quot;);&lt;/script&gt;">version 1.7.0 &lt;script&gt;alert(&quot;unsafe&quot;)&lt;/script&gt; or later</a>.'
118
-			: 'This version of the client is unsupported. Downgrade to <a href="https://example.com&quot;&gt;&lt;script&gt;alter(&quot;hacked&quot;);&lt;/script&gt;">version 2.0.0 &lt;script&gt;alert(&quot;unsafe&quot;)&lt;/script&gt; or earlier</a>.';
119
-		$this->expectExceptionMessage($errorString);
120
-
121
-		/** @var RequestInterface|MockObject $request */
122
-		$request = $this->createMock('\Sabre\HTTP\RequestInterface');
123
-		$request
124
-			->expects($this->once())
125
-			->method('getHeader')
126
-			->with('User-Agent')
127
-			->willReturn($userAgent);
128
-
129
-		$this->blockLegacyClientVersionPlugin->beforeHandler($request);
130
-	}
131
-
132
-	public static function newAndAlternateDesktopClientProvider(): array {
133
-		return [
134
-			['Mozilla/5.0 (Windows) mirall/1.7.0'],
135
-			['Mozilla/5.0 (Bogus Text) mirall/1.9.3'],
136
-			['Mozilla/5.0 (Not Our Client But Old Version) LegacySync/1.1.0'],
137
-			['Mozilla/5.0 (Windows) mirall/4.7.0'],
138
-			['Mozilla/5.0 (Bogus Text) mirall/3.9.3'],
139
-			['Mozilla/5.0 (Not Our Client But Old Version) LegacySync/45.0.0'],
140
-		];
141
-	}
142
-
143
-	#[\PHPUnit\Framework\Attributes\DataProvider('newAndAlternateDesktopClientProvider')]
144
-	public function testBeforeHandlerSuccess(string $userAgent): void {
145
-		/** @var RequestInterface|MockObject $request */
146
-		$request = $this->createMock(RequestInterface::class);
147
-		$request
148
-			->expects($this->once())
149
-			->method('getHeader')
150
-			->with('User-Agent')
151
-			->willReturn($userAgent);
152
-
153
-		$this->config
154
-			->expects($this->exactly(2))
155
-			->method('getSystemValueString')
156
-			->willReturnCallback(function (string $key) {
157
-				if ($key === 'minimum.supported.desktop.version') {
158
-					return '1.7.0';
159
-				}
160
-				return '10.0.0';
161
-			});
162
-
163
-		$this->blockLegacyClientVersionPlugin->beforeHandler($request);
164
-	}
165
-
166
-	public function testBeforeHandlerNoUserAgent(): void {
167
-		/** @var RequestInterface|MockObject $request */
168
-		$request = $this->createMock(RequestInterface::class);
169
-		$request
170
-			->expects($this->once())
171
-			->method('getHeader')
172
-			->with('User-Agent')
173
-			->willReturn(null);
174
-
175
-		$this->blockLegacyClientVersionPlugin->beforeHandler($request);
176
-	}
32
+    private IConfig&MockObject $config;
33
+    private ThemingDefaults&MockObject $themingDefaults;
34
+    private BlockLegacyClientPlugin $blockLegacyClientVersionPlugin;
35
+
36
+    protected function setUp(): void {
37
+        parent::setUp();
38
+
39
+        $this->config = $this->createMock(IConfig::class);
40
+        $this->themingDefaults = $this->createMock(ThemingDefaults::class);
41
+        $this->blockLegacyClientVersionPlugin = new BlockLegacyClientPlugin(
42
+            $this->config,
43
+            $this->themingDefaults,
44
+        );
45
+    }
46
+
47
+    public static function oldDesktopClientProvider(): array {
48
+        return [
49
+            ['Mozilla/5.0 (Windows) mirall/1.5.0', ERROR_TYPE::MIN_ERROR],
50
+            ['Mozilla/5.0 (Bogus Text) mirall/1.6.9', ERROR_TYPE::MIN_ERROR],
51
+            ['Mozilla/5.0 (Windows) mirall/2.5.0', ERROR_TYPE::MAX_ERROR],
52
+            ['Mozilla/5.0 (Bogus Text) mirall/2.0.1', ERROR_TYPE::MAX_ERROR],
53
+            ['Mozilla/5.0 (Windows) mirall/2.0.0', ERROR_TYPE::NONE],
54
+            ['Mozilla/5.0 (Bogus Text) mirall/2.0.0', ERROR_TYPE::NONE],
55
+        ];
56
+    }
57
+
58
+    #[\PHPUnit\Framework\Attributes\DataProvider('oldDesktopClientProvider')]
59
+    public function testBeforeHandlerException(string $userAgent, ERROR_TYPE $errorType): void {
60
+        $this->themingDefaults
61
+            ->expects($this->atMost(1))
62
+            ->method('getSyncClientUrl')
63
+            ->willReturn('https://nextcloud.com/install/#install-clients');
64
+
65
+        $this->config
66
+            ->expects($this->exactly(2))
67
+            ->method('getSystemValueString')
68
+            ->willReturnCallback(function (string $key) {
69
+                if ($key === 'minimum.supported.desktop.version') {
70
+                    return '1.7.0';
71
+                }
72
+                return '2.0.0';
73
+            });
74
+
75
+        if ($errorType !== ERROR_TYPE::NONE) {
76
+            $errorString = $errorType === ERROR_TYPE::MIN_ERROR
77
+            ? 'This version of the client is unsupported. Upgrade to <a href="https://nextcloud.com/install/#install-clients">version 1.7.0 or later</a>.'
78
+            : 'This version of the client is unsupported. Downgrade to <a href="https://nextcloud.com/install/#install-clients">version 2.0.0 or earlier</a>.';
79
+            $this->expectException(\Sabre\DAV\Exception\Forbidden::class);
80
+            $this->expectExceptionMessage($errorString);
81
+        }
82
+
83
+        /** @var RequestInterface|MockObject $request */
84
+        $request = $this->createMock(RequestInterface::class);
85
+        $request
86
+            ->expects($this->once())
87
+            ->method('getHeader')
88
+            ->with('User-Agent')
89
+            ->willReturn($userAgent);
90
+
91
+        $this->blockLegacyClientVersionPlugin->beforeHandler($request);
92
+    }
93
+
94
+    /**
95
+     * Ensure that there is no room for XSS attack through configured URL / version
96
+     */
97
+    #[\PHPUnit\Framework\Attributes\DataProvider('oldDesktopClientProvider')]
98
+    public function testBeforeHandlerExceptionPreventXSSAttack(string $userAgent, ERROR_TYPE $errorType): void {
99
+        $this->expectException(\Sabre\DAV\Exception\Forbidden::class);
100
+
101
+        $this->themingDefaults
102
+            ->expects($this->atMost(1))
103
+            ->method('getSyncClientUrl')
104
+            ->willReturn('https://example.com"><script>alter("hacked");</script>');
105
+
106
+        $this->config
107
+            ->expects($this->exactly(2))
108
+            ->method('getSystemValueString')
109
+            ->willReturnCallback(function (string $key) {
110
+                if ($key === 'minimum.supported.desktop.version') {
111
+                    return '1.7.0 <script>alert("unsafe")</script>';
112
+                }
113
+                return '2.0.0 <script>alert("unsafe")</script>';
114
+            });
115
+
116
+        $errorString = $errorType === ERROR_TYPE::MIN_ERROR
117
+            ? 'This version of the client is unsupported. Upgrade to <a href="https://example.com&quot;&gt;&lt;script&gt;alter(&quot;hacked&quot;);&lt;/script&gt;">version 1.7.0 &lt;script&gt;alert(&quot;unsafe&quot;)&lt;/script&gt; or later</a>.'
118
+            : 'This version of the client is unsupported. Downgrade to <a href="https://example.com&quot;&gt;&lt;script&gt;alter(&quot;hacked&quot;);&lt;/script&gt;">version 2.0.0 &lt;script&gt;alert(&quot;unsafe&quot;)&lt;/script&gt; or earlier</a>.';
119
+        $this->expectExceptionMessage($errorString);
120
+
121
+        /** @var RequestInterface|MockObject $request */
122
+        $request = $this->createMock('\Sabre\HTTP\RequestInterface');
123
+        $request
124
+            ->expects($this->once())
125
+            ->method('getHeader')
126
+            ->with('User-Agent')
127
+            ->willReturn($userAgent);
128
+
129
+        $this->blockLegacyClientVersionPlugin->beforeHandler($request);
130
+    }
131
+
132
+    public static function newAndAlternateDesktopClientProvider(): array {
133
+        return [
134
+            ['Mozilla/5.0 (Windows) mirall/1.7.0'],
135
+            ['Mozilla/5.0 (Bogus Text) mirall/1.9.3'],
136
+            ['Mozilla/5.0 (Not Our Client But Old Version) LegacySync/1.1.0'],
137
+            ['Mozilla/5.0 (Windows) mirall/4.7.0'],
138
+            ['Mozilla/5.0 (Bogus Text) mirall/3.9.3'],
139
+            ['Mozilla/5.0 (Not Our Client But Old Version) LegacySync/45.0.0'],
140
+        ];
141
+    }
142
+
143
+    #[\PHPUnit\Framework\Attributes\DataProvider('newAndAlternateDesktopClientProvider')]
144
+    public function testBeforeHandlerSuccess(string $userAgent): void {
145
+        /** @var RequestInterface|MockObject $request */
146
+        $request = $this->createMock(RequestInterface::class);
147
+        $request
148
+            ->expects($this->once())
149
+            ->method('getHeader')
150
+            ->with('User-Agent')
151
+            ->willReturn($userAgent);
152
+
153
+        $this->config
154
+            ->expects($this->exactly(2))
155
+            ->method('getSystemValueString')
156
+            ->willReturnCallback(function (string $key) {
157
+                if ($key === 'minimum.supported.desktop.version') {
158
+                    return '1.7.0';
159
+                }
160
+                return '10.0.0';
161
+            });
162
+
163
+        $this->blockLegacyClientVersionPlugin->beforeHandler($request);
164
+    }
165
+
166
+    public function testBeforeHandlerNoUserAgent(): void {
167
+        /** @var RequestInterface|MockObject $request */
168
+        $request = $this->createMock(RequestInterface::class);
169
+        $request
170
+            ->expects($this->once())
171
+            ->method('getHeader')
172
+            ->with('User-Agent')
173
+            ->willReturn(null);
174
+
175
+        $this->blockLegacyClientVersionPlugin->beforeHandler($request);
176
+    }
177 177
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Connector/Sabre/PrincipalTest.php 1 patch
Indentation   +902 added lines, -902 removed lines patch added patch discarded remove patch
@@ -32,906 +32,906 @@
 block discarded – undo
32 32
 use Test\TestCase;
33 33
 
34 34
 class PrincipalTest extends TestCase {
35
-	private IUserManager&MockObject $userManager;
36
-	private IGroupManager&MockObject $groupManager;
37
-	private IAccountManager&MockObject $accountManager;
38
-	private IManager&MockObject $shareManager;
39
-	private IUserSession&MockObject $userSession;
40
-	private IAppManager&MockObject $appManager;
41
-	private ProxyMapper&MockObject $proxyMapper;
42
-	private KnownUserService&MockObject $knownUserService;
43
-	private IConfig&MockObject $config;
44
-	private IFactory&MockObject $languageFactory;
45
-	private Principal $connector;
46
-
47
-	protected function setUp(): void {
48
-		parent::setUp();
49
-
50
-		$this->userManager = $this->createMock(IUserManager::class);
51
-		$this->groupManager = $this->createMock(IGroupManager::class);
52
-		$this->accountManager = $this->createMock(IAccountManager::class);
53
-		$this->shareManager = $this->createMock(IManager::class);
54
-		$this->userSession = $this->createMock(IUserSession::class);
55
-		$this->appManager = $this->createMock(IAppManager::class);
56
-		$this->proxyMapper = $this->createMock(ProxyMapper::class);
57
-		$this->knownUserService = $this->createMock(KnownUserService::class);
58
-		$this->config = $this->createMock(IConfig::class);
59
-		$this->languageFactory = $this->createMock(IFactory::class);
60
-
61
-		$this->connector = new Principal(
62
-			$this->userManager,
63
-			$this->groupManager,
64
-			$this->accountManager,
65
-			$this->shareManager,
66
-			$this->userSession,
67
-			$this->appManager,
68
-			$this->proxyMapper,
69
-			$this->knownUserService,
70
-			$this->config,
71
-			$this->languageFactory
72
-		);
73
-	}
74
-
75
-	public function testGetPrincipalsByPrefixWithoutPrefix(): void {
76
-		$response = $this->connector->getPrincipalsByPrefix('');
77
-		$this->assertSame([], $response);
78
-	}
79
-
80
-	public function testGetPrincipalsByPrefixWithUsers(): void {
81
-		$fooUser = $this->createMock(User::class);
82
-		$fooUser
83
-			->expects($this->once())
84
-			->method('getUID')
85
-			->willReturn('foo');
86
-		$fooUser
87
-			->expects($this->once())
88
-			->method('getDisplayName')
89
-			->willReturn('Dr. Foo-Bar');
90
-		$fooUser
91
-			->expects($this->once())
92
-			->method('getSystemEMailAddress')
93
-			->willReturn('');
94
-		$barUser = $this->createMock(User::class);
95
-		$barUser
96
-			->expects($this->once())
97
-			->method('getUID')
98
-			->willReturn('bar');
99
-		$barUser
100
-			->expects($this->once())
101
-			->method('getSystemEMailAddress')
102
-			->willReturn('[email protected]');
103
-		$this->userManager
104
-			->expects($this->once())
105
-			->method('search')
106
-			->with('')
107
-			->willReturn([$fooUser, $barUser]);
108
-
109
-		$this->languageFactory
110
-			->expects($this->exactly(2))
111
-			->method('getUserLanguage')
112
-			->willReturnMap([
113
-				[$fooUser, 'de'],
114
-				[$barUser, 'en'],
115
-			]);
116
-
117
-		$fooAccountPropertyCollection = $this->createMock(IAccountPropertyCollection::class);
118
-		$fooAccountPropertyCollection->expects($this->once())
119
-			->method('getProperties')
120
-			->willReturn([]);
121
-		$fooAccount = $this->createMock(IAccount::class);
122
-		$fooAccount->expects($this->once())
123
-			->method('getPropertyCollection')
124
-			->with(IAccountManager::COLLECTION_EMAIL)
125
-			->willReturn($fooAccountPropertyCollection);
126
-
127
-		$emailPropertyOne = $this->createMock(IAccountProperty::class);
128
-		$emailPropertyOne->expects($this->once())
129
-			->method('getValue')
130
-			->willReturn('[email protected]');
131
-		$emailPropertyTwo = $this->createMock(IAccountProperty::class);
132
-		$emailPropertyTwo->expects($this->once())
133
-			->method('getValue')
134
-			->willReturn('[email protected]');
135
-
136
-		$barAccountPropertyCollection = $this->createMock(IAccountPropertyCollection::class);
137
-		$barAccountPropertyCollection->expects($this->once())
138
-			->method('getProperties')
139
-			->willReturn([$emailPropertyOne, $emailPropertyTwo]);
140
-		$barAccount = $this->createMock(IAccount::class);
141
-		$barAccount->expects($this->once())
142
-			->method('getPropertyCollection')
143
-			->with(IAccountManager::COLLECTION_EMAIL)
144
-			->willReturn($barAccountPropertyCollection);
145
-
146
-		$this->accountManager
147
-			->expects($this->exactly(2))
148
-			->method('getAccount')
149
-			->willReturnMap([
150
-				[$fooUser, $fooAccount],
151
-				[$barUser, $barAccount],
152
-			]);
153
-
154
-		$expectedResponse = [
155
-			0 => [
156
-				'uri' => 'principals/users/foo',
157
-				'{DAV:}displayname' => 'Dr. Foo-Bar',
158
-				'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
159
-				'{http://nextcloud.com/ns}language' => 'de',
160
-			],
161
-			1 => [
162
-				'uri' => 'principals/users/bar',
163
-				'{DAV:}displayname' => 'bar',
164
-				'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
165
-				'{http://nextcloud.com/ns}language' => 'en',
166
-				'{http://sabredav.org/ns}email-address' => '[email protected]',
167
-				'{DAV:}alternate-URI-set' => ['mailto:[email protected]', 'mailto:[email protected]']
168
-			]
169
-		];
170
-		$response = $this->connector->getPrincipalsByPrefix('principals/users');
171
-		$this->assertSame($expectedResponse, $response);
172
-	}
173
-
174
-	public function testGetPrincipalsByPrefixEmpty(): void {
175
-		$this->userManager
176
-			->expects($this->once())
177
-			->method('search')
178
-			->with('')
179
-			->willReturn([]);
180
-
181
-		$response = $this->connector->getPrincipalsByPrefix('principals/users');
182
-		$this->assertSame([], $response);
183
-	}
184
-
185
-	public function testGetPrincipalsByPathWithoutMail(): void {
186
-		$fooUser = $this->createMock(User::class);
187
-		$fooUser
188
-			->expects($this->once())
189
-			->method('getUID')
190
-			->willReturn('foo');
191
-		$this->userManager
192
-			->expects($this->once())
193
-			->method('get')
194
-			->with('foo')
195
-			->willReturn($fooUser);
196
-
197
-		$this->languageFactory
198
-			->expects($this->once())
199
-			->method('getUserLanguage')
200
-			->with($fooUser)
201
-			->willReturn('de');
202
-
203
-		$expectedResponse = [
204
-			'uri' => 'principals/users/foo',
205
-			'{DAV:}displayname' => 'foo',
206
-			'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
207
-			'{http://nextcloud.com/ns}language' => 'de'
208
-		];
209
-		$response = $this->connector->getPrincipalByPath('principals/users/foo');
210
-		$this->assertSame($expectedResponse, $response);
211
-	}
212
-
213
-	public function testGetPrincipalsByPathWithMail(): void {
214
-		$fooUser = $this->createMock(User::class);
215
-		$fooUser
216
-			->expects($this->once())
217
-			->method('getSystemEMailAddress')
218
-			->willReturn('[email protected]');
219
-		$fooUser
220
-			->expects($this->once())
221
-			->method('getUID')
222
-			->willReturn('foo');
223
-		$this->userManager
224
-			->expects($this->once())
225
-			->method('get')
226
-			->with('foo')
227
-			->willReturn($fooUser);
228
-
229
-		$this->languageFactory
230
-			->expects($this->once())
231
-			->method('getUserLanguage')
232
-			->with($fooUser)
233
-			->willReturn('de');
234
-
235
-		$expectedResponse = [
236
-			'uri' => 'principals/users/foo',
237
-			'{DAV:}displayname' => 'foo',
238
-			'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
239
-			'{http://nextcloud.com/ns}language' => 'de',
240
-			'{http://sabredav.org/ns}email-address' => '[email protected]',
241
-		];
242
-		$response = $this->connector->getPrincipalByPath('principals/users/foo');
243
-		$this->assertSame($expectedResponse, $response);
244
-	}
245
-
246
-	public function testGetPrincipalsByPathEmpty(): void {
247
-		$this->userManager
248
-			->expects($this->once())
249
-			->method('get')
250
-			->with('foo')
251
-			->willReturn(null);
252
-
253
-		$response = $this->connector->getPrincipalByPath('principals/users/foo');
254
-		$this->assertNull($response);
255
-	}
256
-
257
-	public function testGetGroupMemberSet(): void {
258
-		$response = $this->connector->getGroupMemberSet('principals/users/foo');
259
-		$this->assertSame([], $response);
260
-	}
261
-
262
-
263
-	public function testGetGroupMemberSetEmpty(): void {
264
-		$this->expectException(Exception::class);
265
-		$this->expectExceptionMessage('Principal not found');
266
-
267
-		$this->userManager
268
-			->expects($this->once())
269
-			->method('get')
270
-			->with('foo')
271
-			->willReturn(null);
272
-
273
-		$this->connector->getGroupMemberSet('principals/users/foo/calendar-proxy-read');
274
-	}
275
-
276
-	public function testGetGroupMemberSetProxyRead(): void {
277
-		$fooUser = $this->createMock(User::class);
278
-		$fooUser
279
-			->expects($this->once())
280
-			->method('getUID')
281
-			->willReturn('foo');
282
-		$this->userManager
283
-			->expects($this->once())
284
-			->method('get')
285
-			->with('foo')
286
-			->willReturn($fooUser);
287
-
288
-		$proxy1 = new Proxy();
289
-		$proxy1->setProxyId('proxyId1');
290
-		$proxy1->setPermissions(1);
291
-
292
-		$proxy2 = new Proxy();
293
-		$proxy2->setProxyId('proxyId2');
294
-		$proxy2->setPermissions(3);
295
-
296
-		$proxy3 = new Proxy();
297
-		$proxy3->setProxyId('proxyId3');
298
-		$proxy3->setPermissions(3);
299
-
300
-		$this->proxyMapper->expects($this->once())
301
-			->method('getProxiesOf')
302
-			->with('principals/users/foo')
303
-			->willReturn([$proxy1, $proxy2, $proxy3]);
304
-
305
-		$this->assertEquals(['proxyId1'], $this->connector->getGroupMemberSet('principals/users/foo/calendar-proxy-read'));
306
-	}
307
-
308
-	public function testGetGroupMemberSetProxyWrite(): void {
309
-		$fooUser = $this->createMock(User::class);
310
-		$fooUser
311
-			->expects($this->once())
312
-			->method('getUID')
313
-			->willReturn('foo');
314
-		$this->userManager
315
-			->expects($this->once())
316
-			->method('get')
317
-			->with('foo')
318
-			->willReturn($fooUser);
319
-
320
-		$proxy1 = new Proxy();
321
-		$proxy1->setProxyId('proxyId1');
322
-		$proxy1->setPermissions(1);
323
-
324
-		$proxy2 = new Proxy();
325
-		$proxy2->setProxyId('proxyId2');
326
-		$proxy2->setPermissions(3);
327
-
328
-		$proxy3 = new Proxy();
329
-		$proxy3->setProxyId('proxyId3');
330
-		$proxy3->setPermissions(3);
331
-
332
-		$this->proxyMapper->expects($this->once())
333
-			->method('getProxiesOf')
334
-			->with('principals/users/foo')
335
-			->willReturn([$proxy1, $proxy2, $proxy3]);
336
-
337
-		$this->assertEquals(['proxyId2', 'proxyId3'], $this->connector->getGroupMemberSet('principals/users/foo/calendar-proxy-write'));
338
-	}
339
-
340
-	public function testGetGroupMembership(): void {
341
-		$fooUser = $this->createMock(User::class);
342
-		$group1 = $this->createMock(IGroup::class);
343
-		$group1->expects($this->once())
344
-			->method('getGID')
345
-			->willReturn('group1');
346
-		$group2 = $this->createMock(IGroup::class);
347
-		$group2->expects($this->once())
348
-			->method('getGID')
349
-			->willReturn('foo/bar');
350
-		$this->userManager
351
-			->expects($this->exactly(2))
352
-			->method('get')
353
-			->with('foo')
354
-			->willReturn($fooUser);
355
-		$this->groupManager
356
-			->expects($this->once())
357
-			->method('getUserGroups')
358
-			->with($fooUser)
359
-			->willReturn([
360
-				$group1,
361
-				$group2,
362
-			]);
363
-
364
-		$proxy1 = new Proxy();
365
-		$proxy1->setOwnerId('proxyId1');
366
-		$proxy1->setPermissions(1);
367
-
368
-		$proxy2 = new Proxy();
369
-		$proxy2->setOwnerId('proxyId2');
370
-		$proxy2->setPermissions(3);
371
-
372
-		$this->proxyMapper->expects($this->once())
373
-			->method('getProxiesFor')
374
-			->with('principals/users/foo')
375
-			->willReturn([$proxy1, $proxy2]);
376
-
377
-		$expectedResponse = [
378
-			'principals/groups/group1',
379
-			'principals/groups/foo%2Fbar',
380
-			'proxyId1/calendar-proxy-read',
381
-			'proxyId2/calendar-proxy-write',
382
-		];
383
-		$response = $this->connector->getGroupMembership('principals/users/foo');
384
-		$this->assertSame($expectedResponse, $response);
385
-	}
386
-
387
-
388
-	public function testGetGroupMembershipEmpty(): void {
389
-		$this->expectException(Exception::class);
390
-		$this->expectExceptionMessage('Principal not found');
391
-
392
-		$this->userManager
393
-			->expects($this->once())
394
-			->method('get')
395
-			->with('foo')
396
-			->willReturn(null);
397
-
398
-		$this->connector->getGroupMembership('principals/users/foo');
399
-	}
400
-
401
-
402
-	public function testSetGroupMembership(): void {
403
-		$this->expectException(Exception::class);
404
-		$this->expectExceptionMessage('Setting members of the group is not supported yet');
405
-
406
-		$this->connector->setGroupMemberSet('principals/users/foo', ['foo']);
407
-	}
408
-
409
-	public function testSetGroupMembershipProxy(): void {
410
-		$fooUser = $this->createMock(User::class);
411
-		$fooUser
412
-			->expects($this->once())
413
-			->method('getUID')
414
-			->willReturn('foo');
415
-		$barUser = $this->createMock(User::class);
416
-		$barUser
417
-			->expects($this->once())
418
-			->method('getUID')
419
-			->willReturn('bar');
420
-		$this->userManager
421
-			->expects($this->exactly(2))
422
-			->method('get')
423
-			->willReturnMap([
424
-				['foo', $fooUser],
425
-				['bar', $barUser],
426
-			]);
427
-
428
-		$this->proxyMapper->expects($this->once())
429
-			->method('getProxiesOf')
430
-			->with('principals/users/foo')
431
-			->willReturn([]);
432
-
433
-		$this->proxyMapper->expects($this->once())
434
-			->method('insert')
435
-			->with($this->callback(function ($proxy) {
436
-				/** @var Proxy $proxy */
437
-				if ($proxy->getOwnerId() !== 'principals/users/foo') {
438
-					return false;
439
-				}
440
-				if ($proxy->getProxyId() !== 'principals/users/bar') {
441
-					return false;
442
-				}
443
-				if ($proxy->getPermissions() !== 3) {
444
-					return false;
445
-				}
446
-
447
-				return true;
448
-			}));
449
-
450
-		$this->connector->setGroupMemberSet('principals/users/foo/calendar-proxy-write', ['principals/users/bar']);
451
-	}
452
-
453
-	public function testUpdatePrincipal(): void {
454
-		$this->assertSame(0, $this->connector->updatePrincipal('foo', new PropPatch([])));
455
-	}
456
-
457
-	public function testSearchPrincipalsWithEmptySearchProperties(): void {
458
-		$this->assertSame([], $this->connector->searchPrincipals('principals/users', []));
459
-	}
460
-
461
-	public function testSearchPrincipalsWithWrongPrefixPath(): void {
462
-		$this->assertSame([], $this->connector->searchPrincipals('principals/groups',
463
-			['{http://sabredav.org/ns}email-address' => 'foo']));
464
-	}
465
-
466
-	#[\PHPUnit\Framework\Attributes\DataProvider('searchPrincipalsDataProvider')]
467
-	public function testSearchPrincipals(bool $sharingEnabled, bool $groupsOnly, string $test, array $result): void {
468
-		$this->shareManager->expects($this->once())
469
-			->method('shareAPIEnabled')
470
-			->willReturn($sharingEnabled);
471
-
472
-		$getUserGroupIdsReturnMap = [];
473
-
474
-		if ($sharingEnabled) {
475
-			$this->shareManager->expects($this->once())
476
-				->method('allowEnumeration')
477
-				->willReturn(true);
478
-
479
-			$this->shareManager->expects($this->once())
480
-				->method('shareWithGroupMembersOnly')
481
-				->willReturn($groupsOnly);
482
-
483
-			if ($groupsOnly) {
484
-				$user = $this->createMock(IUser::class);
485
-				$this->userSession->expects($this->atLeastOnce())
486
-					->method('getUser')
487
-					->willReturn($user);
488
-
489
-				$getUserGroupIdsReturnMap[] = [$user, ['group1', 'group2', 'group5']];
490
-			}
491
-		} else {
492
-			$this->config->expects($this->never())
493
-				->method('getAppValue');
494
-			$this->shareManager->expects($this->never())
495
-				->method('shareWithGroupMembersOnly');
496
-			$this->groupManager->expects($this->never())
497
-				->method($this->anything());
498
-		}
499
-
500
-		$user2 = $this->createMock(IUser::class);
501
-		$user2->method('getUID')->willReturn('user2');
502
-		$user3 = $this->createMock(IUser::class);
503
-		$user3->method('getUID')->willReturn('user3');
504
-		$user4 = $this->createMock(IUser::class);
505
-		$user4->method('getUID')->willReturn('user4');
506
-
507
-		if ($sharingEnabled) {
508
-			$this->userManager->expects($this->once())
509
-				->method('getByEmail')
510
-				->with('[email protected]')
511
-				->willReturn([$user2, $user3]);
512
-
513
-			$this->userManager->expects($this->once())
514
-				->method('searchDisplayName')
515
-				->with('User 12')
516
-				->willReturn([$user3, $user4]);
517
-		} else {
518
-			$this->userManager->expects($this->never())
519
-				->method('getByEmail');
520
-
521
-			$this->userManager->expects($this->never())
522
-				->method('searchDisplayName');
523
-		}
524
-
525
-		if ($sharingEnabled && $groupsOnly) {
526
-			$getUserGroupIdsReturnMap[] = [$user2, ['group1', 'group3']];
527
-			$getUserGroupIdsReturnMap[] = [$user3, ['group3', 'group4']];
528
-			$getUserGroupIdsReturnMap[] = [$user4, ['group4', 'group5']];
529
-		}
530
-
531
-		$this->groupManager->expects($this->any())
532
-			->method('getUserGroupIds')
533
-			->willReturnMap($getUserGroupIdsReturnMap);
534
-
535
-
536
-		$this->assertEquals($result, $this->connector->searchPrincipals('principals/users',
537
-			['{http://sabredav.org/ns}email-address' => '[email protected]',
538
-				'{DAV:}displayname' => 'User 12'], $test));
539
-	}
540
-
541
-	public static function searchPrincipalsDataProvider(): array {
542
-		return [
543
-			[true, false, 'allof', ['principals/users/user3']],
544
-			[true, false, 'anyof', ['principals/users/user2', 'principals/users/user3', 'principals/users/user4']],
545
-			[true, true, 'allof', []],
546
-			[true, true, 'anyof', ['principals/users/user2', 'principals/users/user4']],
547
-			[false, false, 'allof', []],
548
-			[false, false, 'anyof', []],
549
-		];
550
-	}
551
-
552
-	public function testSearchPrincipalByCalendarUserAddressSet(): void {
553
-		$this->shareManager->expects($this->exactly(2))
554
-			->method('shareAPIEnabled')
555
-			->willReturn(true);
556
-
557
-		$this->shareManager->expects($this->exactly(2))
558
-			->method('allowEnumeration')
559
-			->willReturn(true);
560
-
561
-		$this->shareManager->expects($this->exactly(2))
562
-			->method('shareWithGroupMembersOnly')
563
-			->willReturn(false);
564
-
565
-		$user2 = $this->createMock(IUser::class);
566
-		$user2->method('getUID')->willReturn('user2');
567
-		$user3 = $this->createMock(IUser::class);
568
-		$user3->method('getUID')->willReturn('user3');
569
-
570
-		$this->userManager->expects($this->once())
571
-			->method('getByEmail')
572
-			->with('[email protected]')
573
-			->willReturn([$user2, $user3]);
574
-
575
-		$this->assertEquals([
576
-			'principals/users/user2',
577
-			'principals/users/user3',
578
-		], $this->connector->searchPrincipals('principals/users',
579
-			['{urn:ietf:params:xml:ns:caldav}calendar-user-address-set' => '[email protected]']));
580
-	}
581
-
582
-	public function testSearchPrincipalWithEnumerationDisabledDisplayname(): void {
583
-		$this->shareManager->expects($this->once())
584
-			->method('shareAPIEnabled')
585
-			->willReturn(true);
586
-
587
-		$this->shareManager->expects($this->once())
588
-			->method('allowEnumeration')
589
-			->willReturn(false);
590
-
591
-		$this->shareManager->expects($this->once())
592
-			->method('shareWithGroupMembersOnly')
593
-			->willReturn(false);
594
-
595
-		$this->shareManager->expects($this->once())
596
-			->method('allowEnumerationFullMatch')
597
-			->willReturn(true);
598
-
599
-		$user2 = $this->createMock(IUser::class);
600
-		$user2->method('getUID')->willReturn('user2');
601
-		$user2->method('getDisplayName')->willReturn('User 2');
602
-		$user2->method('getSystemEMailAddress')->willReturn('[email protected]');
603
-		$user3 = $this->createMock(IUser::class);
604
-		$user3->method('getUID')->willReturn('user3');
605
-		$user3->method('getDisplayName')->willReturn('User 22');
606
-		$user3->method('getSystemEMailAddress')->willReturn('[email protected]');
607
-		$user4 = $this->createMock(IUser::class);
608
-		$user4->method('getUID')->willReturn('user4');
609
-		$user4->method('getDisplayName')->willReturn('User 222');
610
-		$user4->method('getSystemEMailAddress')->willReturn('[email protected]');
611
-
612
-		$this->userManager->expects($this->once())
613
-			->method('searchDisplayName')
614
-			->with('User 2')
615
-			->willReturn([$user2, $user3, $user4]);
616
-
617
-		$this->assertEquals(['principals/users/user2'], $this->connector->searchPrincipals('principals/users',
618
-			['{DAV:}displayname' => 'User 2']));
619
-	}
620
-
621
-	public function testSearchPrincipalWithEnumerationDisabledDisplaynameOnFullMatch(): void {
622
-		$this->shareManager->expects($this->once())
623
-			->method('shareAPIEnabled')
624
-			->willReturn(true);
625
-
626
-		$this->shareManager->expects($this->once())
627
-			->method('allowEnumeration')
628
-			->willReturn(false);
629
-
630
-		$this->shareManager->expects($this->once())
631
-			->method('shareWithGroupMembersOnly')
632
-			->willReturn(false);
633
-
634
-		$this->shareManager->expects($this->once())
635
-			->method('allowEnumerationFullMatch')
636
-			->willReturn(false);
637
-
638
-		$this->assertEquals([], $this->connector->searchPrincipals('principals/users',
639
-			['{DAV:}displayname' => 'User 2']));
640
-	}
641
-
642
-	public function testSearchPrincipalWithEnumerationDisabledEmail(): void {
643
-		$this->shareManager->expects($this->once())
644
-			->method('shareAPIEnabled')
645
-			->willReturn(true);
646
-
647
-		$this->shareManager->expects($this->once())
648
-			->method('allowEnumeration')
649
-			->willReturn(false);
650
-
651
-		$this->shareManager->expects($this->once())
652
-			->method('shareWithGroupMembersOnly')
653
-			->willReturn(false);
654
-
655
-		$this->shareManager->expects($this->once())
656
-			->method('allowEnumerationFullMatch')
657
-			->willReturn(true);
658
-
659
-		$this->shareManager->expects($this->once())
660
-			->method('matchEmail')
661
-			->willReturn(true);
662
-
663
-		$user2 = $this->createMock(IUser::class);
664
-		$user2->method('getUID')->willReturn('user2');
665
-		$user2->method('getDisplayName')->willReturn('User 2');
666
-		$user2->method('getSystemEMailAddress')->willReturn('[email protected]');
667
-		$user3 = $this->createMock(IUser::class);
668
-		$user3->method('getUID')->willReturn('user3');
669
-		$user2->method('getDisplayName')->willReturn('User 22');
670
-		$user2->method('getSystemEMailAddress')->willReturn('[email protected]');
671
-		$user4 = $this->createMock(IUser::class);
672
-		$user4->method('getUID')->willReturn('user4');
673
-		$user2->method('getDisplayName')->willReturn('User 222');
674
-		$user2->method('getSystemEMailAddress')->willReturn('[email protected]');
675
-
676
-		$this->userManager->expects($this->once())
677
-			->method('getByEmail')
678
-			->with('[email protected]')
679
-			->willReturn([$user2]);
680
-
681
-		$this->assertEquals(['principals/users/user2'], $this->connector->searchPrincipals('principals/users',
682
-			['{http://sabredav.org/ns}email-address' => '[email protected]']));
683
-	}
684
-
685
-	public function testSearchPrincipalWithEnumerationDisabledEmailOnFullMatch(): void {
686
-		$this->shareManager->expects($this->once())
687
-			->method('shareAPIEnabled')
688
-			->willReturn(true);
689
-
690
-		$this->shareManager->expects($this->once())
691
-			->method('allowEnumeration')
692
-			->willReturn(false);
693
-
694
-		$this->shareManager->expects($this->once())
695
-			->method('shareWithGroupMembersOnly')
696
-			->willReturn(false);
697
-
698
-		$this->shareManager->expects($this->once())
699
-			->method('allowEnumerationFullMatch')
700
-			->willReturn(false);
701
-
702
-
703
-		$this->assertEquals([], $this->connector->searchPrincipals('principals/users',
704
-			['{http://sabredav.org/ns}email-address' => '[email protected]']));
705
-	}
706
-
707
-	public function testSearchPrincipalWithEnumerationLimitedDisplayname(): void {
708
-		$this->shareManager->expects($this->once())
709
-			->method('shareAPIEnabled')
710
-			->willReturn(true);
711
-
712
-		$this->shareManager->expects($this->once())
713
-			->method('allowEnumeration')
714
-			->willReturn(true);
715
-
716
-		$this->shareManager->expects($this->once())
717
-			->method('limitEnumerationToGroups')
718
-			->willReturn(true);
719
-
720
-		$this->shareManager->expects($this->once())
721
-			->method('shareWithGroupMembersOnly')
722
-			->willReturn(false);
723
-
724
-		$user2 = $this->createMock(IUser::class);
725
-		$user2->method('getUID')->willReturn('user2');
726
-		$user2->method('getDisplayName')->willReturn('User 2');
727
-		$user2->method('getSystemEMailAddress')->willReturn('[email protected]');
728
-		$user3 = $this->createMock(IUser::class);
729
-		$user3->method('getUID')->willReturn('user3');
730
-		$user3->method('getDisplayName')->willReturn('User 22');
731
-		$user3->method('getSystemEMailAddress')->willReturn('[email protected]');
732
-		$user4 = $this->createMock(IUser::class);
733
-		$user4->method('getUID')->willReturn('user4');
734
-		$user4->method('getDisplayName')->willReturn('User 222');
735
-		$user4->method('getSystemEMailAddress')->willReturn('[email protected]');
736
-
737
-
738
-		$this->userSession->expects($this->once())
739
-			->method('getUser')
740
-			->willReturn($user2);
741
-
742
-		$this->groupManager->expects($this->exactly(4))
743
-			->method('getUserGroupIds')
744
-			->willReturnMap([
745
-				[$user2, ['group1']],
746
-				[$user3, ['group1']],
747
-				[$user4, ['group2']],
748
-			]);
749
-
750
-		$this->userManager->expects($this->once())
751
-			->method('searchDisplayName')
752
-			->with('User')
753
-			->willReturn([$user2, $user3, $user4]);
754
-
755
-
756
-		$this->assertEquals([
757
-			'principals/users/user2',
758
-			'principals/users/user3',
759
-		], $this->connector->searchPrincipals('principals/users',
760
-			['{DAV:}displayname' => 'User']));
761
-	}
762
-
763
-	public function testSearchPrincipalWithEnumerationLimitedMail(): void {
764
-		$this->shareManager->expects($this->once())
765
-			->method('shareAPIEnabled')
766
-			->willReturn(true);
767
-
768
-		$this->shareManager->expects($this->once())
769
-			->method('allowEnumeration')
770
-			->willReturn(true);
771
-
772
-		$this->shareManager->expects($this->once())
773
-			->method('limitEnumerationToGroups')
774
-			->willReturn(true);
775
-
776
-		$this->shareManager->expects($this->once())
777
-			->method('shareWithGroupMembersOnly')
778
-			->willReturn(false);
779
-
780
-		$user2 = $this->createMock(IUser::class);
781
-		$user2->method('getUID')->willReturn('user2');
782
-		$user2->method('getDisplayName')->willReturn('User 2');
783
-		$user2->method('getSystemEMailAddress')->willReturn('[email protected]');
784
-		$user3 = $this->createMock(IUser::class);
785
-		$user3->method('getUID')->willReturn('user3');
786
-		$user3->method('getDisplayName')->willReturn('User 22');
787
-		$user3->method('getSystemEMailAddress')->willReturn('[email protected]');
788
-		$user4 = $this->createMock(IUser::class);
789
-		$user4->method('getUID')->willReturn('user4');
790
-		$user4->method('getDisplayName')->willReturn('User 222');
791
-		$user4->method('getSystemEMailAddress')->willReturn('[email protected]');
792
-
793
-
794
-		$this->userSession->expects($this->once())
795
-			->method('getUser')
796
-			->willReturn($user2);
797
-
798
-		$this->groupManager->expects($this->exactly(4))
799
-			->method('getUserGroupIds')
800
-			->willReturnMap([
801
-				[$user2, ['group1']],
802
-				[$user3, ['group1']],
803
-				[$user4, ['group2']],
804
-			]);
805
-
806
-		$this->userManager->expects($this->once())
807
-			->method('getByEmail')
808
-			->with('user')
809
-			->willReturn([$user2, $user3, $user4]);
810
-
811
-
812
-		$this->assertEquals([
813
-			'principals/users/user2',
814
-			'principals/users/user3'
815
-		], $this->connector->searchPrincipals('principals/users',
816
-			['{http://sabredav.org/ns}email-address' => 'user']));
817
-	}
818
-
819
-	public function testFindByUriSharingApiDisabled(): void {
820
-		$this->shareManager->expects($this->once())
821
-			->method('shareApiEnabled')
822
-			->willReturn(false);
823
-
824
-		$this->assertEquals(null, $this->connector->findByUri('mailto:[email protected]', 'principals/users'));
825
-	}
826
-
827
-	#[\PHPUnit\Framework\Attributes\DataProvider('findByUriWithGroupRestrictionDataProvider')]
828
-	public function testFindByUriWithGroupRestriction(string $uri, string $email, ?string $expects): void {
829
-		$this->shareManager->expects($this->once())
830
-			->method('shareApiEnabled')
831
-			->willReturn(true);
832
-
833
-		$this->shareManager->expects($this->once())
834
-			->method('shareWithGroupMembersOnly')
835
-			->willReturn(true);
836
-
837
-		$user = $this->createMock(IUser::class);
838
-		$this->userSession->expects($this->once())
839
-			->method('getUser')
840
-			->willReturn($user);
841
-
842
-		$user2 = $this->createMock(IUser::class);
843
-		$user2->method('getUID')->willReturn('user2');
844
-		$user3 = $this->createMock(IUser::class);
845
-		$user3->method('getUID')->willReturn('user3');
846
-
847
-		$this->userManager->expects($this->once())
848
-			->method('getByEmail')
849
-			->with($email)
850
-			->willReturn([$email === '[email protected]' ? $user2 : $user3]);
851
-
852
-		if ($email === '[email protected]') {
853
-			$this->groupManager->expects($this->exactly(2))
854
-				->method('getUserGroupIds')
855
-				->willReturnMap([
856
-					[$user, ['group1', 'group2']],
857
-					[$user2, ['group1', 'group3']],
858
-				]);
859
-		} else {
860
-			$this->groupManager->expects($this->exactly(2))
861
-				->method('getUserGroupIds')
862
-				->willReturnMap([
863
-					[$user, ['group1', 'group2']],
864
-					[$user3, ['group3', 'group3']],
865
-				]);
866
-		}
867
-
868
-		$this->assertEquals($expects, $this->connector->findByUri($uri, 'principals/users'));
869
-	}
870
-
871
-	public static function findByUriWithGroupRestrictionDataProvider(): array {
872
-		return [
873
-			['mailto:[email protected]', '[email protected]', 'principals/users/user2'],
874
-			['mailto:[email protected]', '[email protected]', null],
875
-		];
876
-	}
877
-
878
-	#[\PHPUnit\Framework\Attributes\DataProvider('findByUriWithoutGroupRestrictionDataProvider')]
879
-	public function testFindByUriWithoutGroupRestriction(string $uri, string $email, string $expects): void {
880
-		$this->shareManager->expects($this->once())
881
-			->method('shareApiEnabled')
882
-			->willReturn(true);
883
-
884
-		$this->shareManager->expects($this->once())
885
-			->method('shareWithGroupMembersOnly')
886
-			->willReturn(false);
887
-
888
-		$user2 = $this->createMock(IUser::class);
889
-		$user2->method('getUID')->willReturn('user2');
890
-		$user3 = $this->createMock(IUser::class);
891
-		$user3->method('getUID')->willReturn('user3');
892
-
893
-		$this->userManager->expects($this->once())
894
-			->method('getByEmail')
895
-			->with($email)
896
-			->willReturn([$email === '[email protected]' ? $user2 : $user3]);
897
-
898
-		$this->assertEquals($expects, $this->connector->findByUri($uri, 'principals/users'));
899
-	}
900
-
901
-	public static function findByUriWithoutGroupRestrictionDataProvider(): array {
902
-		return [
903
-			['mailto:[email protected]', '[email protected]', 'principals/users/user2'],
904
-			['mailto:[email protected]', '[email protected]', 'principals/users/user3'],
905
-		];
906
-	}
907
-
908
-	public function testGetEmailAddressesOfPrincipal(): void {
909
-		$principal = [
910
-			'{http://sabredav.org/ns}email-address' => '[email protected]',
911
-			'{DAV:}alternate-URI-set' => [
912
-				'/some/url',
913
-				'mailto:[email protected]',
914
-				'mailto:[email protected]',
915
-			],
916
-			'{urn:ietf:params:xml:ns:caldav}calendar-user-address-set' => [
917
-				'mailto:[email protected]',
918
-				'mailto:[email protected]',
919
-			],
920
-			'{http://calendarserver.org/ns/}email-address-set' => [
921
-				'mailto:[email protected]',
922
-				'mailto:[email protected]',
923
-			],
924
-		];
925
-
926
-		$expected = [
927
-			'[email protected]',
928
-			'[email protected]',
929
-			'[email protected]',
930
-			'[email protected]',
931
-			'[email protected]',
932
-			'[email protected]',
933
-		];
934
-		$actual = $this->connector->getEmailAddressesOfPrincipal($principal);
935
-		$this->assertEquals($expected, $actual);
936
-	}
35
+    private IUserManager&MockObject $userManager;
36
+    private IGroupManager&MockObject $groupManager;
37
+    private IAccountManager&MockObject $accountManager;
38
+    private IManager&MockObject $shareManager;
39
+    private IUserSession&MockObject $userSession;
40
+    private IAppManager&MockObject $appManager;
41
+    private ProxyMapper&MockObject $proxyMapper;
42
+    private KnownUserService&MockObject $knownUserService;
43
+    private IConfig&MockObject $config;
44
+    private IFactory&MockObject $languageFactory;
45
+    private Principal $connector;
46
+
47
+    protected function setUp(): void {
48
+        parent::setUp();
49
+
50
+        $this->userManager = $this->createMock(IUserManager::class);
51
+        $this->groupManager = $this->createMock(IGroupManager::class);
52
+        $this->accountManager = $this->createMock(IAccountManager::class);
53
+        $this->shareManager = $this->createMock(IManager::class);
54
+        $this->userSession = $this->createMock(IUserSession::class);
55
+        $this->appManager = $this->createMock(IAppManager::class);
56
+        $this->proxyMapper = $this->createMock(ProxyMapper::class);
57
+        $this->knownUserService = $this->createMock(KnownUserService::class);
58
+        $this->config = $this->createMock(IConfig::class);
59
+        $this->languageFactory = $this->createMock(IFactory::class);
60
+
61
+        $this->connector = new Principal(
62
+            $this->userManager,
63
+            $this->groupManager,
64
+            $this->accountManager,
65
+            $this->shareManager,
66
+            $this->userSession,
67
+            $this->appManager,
68
+            $this->proxyMapper,
69
+            $this->knownUserService,
70
+            $this->config,
71
+            $this->languageFactory
72
+        );
73
+    }
74
+
75
+    public function testGetPrincipalsByPrefixWithoutPrefix(): void {
76
+        $response = $this->connector->getPrincipalsByPrefix('');
77
+        $this->assertSame([], $response);
78
+    }
79
+
80
+    public function testGetPrincipalsByPrefixWithUsers(): void {
81
+        $fooUser = $this->createMock(User::class);
82
+        $fooUser
83
+            ->expects($this->once())
84
+            ->method('getUID')
85
+            ->willReturn('foo');
86
+        $fooUser
87
+            ->expects($this->once())
88
+            ->method('getDisplayName')
89
+            ->willReturn('Dr. Foo-Bar');
90
+        $fooUser
91
+            ->expects($this->once())
92
+            ->method('getSystemEMailAddress')
93
+            ->willReturn('');
94
+        $barUser = $this->createMock(User::class);
95
+        $barUser
96
+            ->expects($this->once())
97
+            ->method('getUID')
98
+            ->willReturn('bar');
99
+        $barUser
100
+            ->expects($this->once())
101
+            ->method('getSystemEMailAddress')
102
+            ->willReturn('[email protected]');
103
+        $this->userManager
104
+            ->expects($this->once())
105
+            ->method('search')
106
+            ->with('')
107
+            ->willReturn([$fooUser, $barUser]);
108
+
109
+        $this->languageFactory
110
+            ->expects($this->exactly(2))
111
+            ->method('getUserLanguage')
112
+            ->willReturnMap([
113
+                [$fooUser, 'de'],
114
+                [$barUser, 'en'],
115
+            ]);
116
+
117
+        $fooAccountPropertyCollection = $this->createMock(IAccountPropertyCollection::class);
118
+        $fooAccountPropertyCollection->expects($this->once())
119
+            ->method('getProperties')
120
+            ->willReturn([]);
121
+        $fooAccount = $this->createMock(IAccount::class);
122
+        $fooAccount->expects($this->once())
123
+            ->method('getPropertyCollection')
124
+            ->with(IAccountManager::COLLECTION_EMAIL)
125
+            ->willReturn($fooAccountPropertyCollection);
126
+
127
+        $emailPropertyOne = $this->createMock(IAccountProperty::class);
128
+        $emailPropertyOne->expects($this->once())
129
+            ->method('getValue')
130
+            ->willReturn('[email protected]');
131
+        $emailPropertyTwo = $this->createMock(IAccountProperty::class);
132
+        $emailPropertyTwo->expects($this->once())
133
+            ->method('getValue')
134
+            ->willReturn('[email protected]');
135
+
136
+        $barAccountPropertyCollection = $this->createMock(IAccountPropertyCollection::class);
137
+        $barAccountPropertyCollection->expects($this->once())
138
+            ->method('getProperties')
139
+            ->willReturn([$emailPropertyOne, $emailPropertyTwo]);
140
+        $barAccount = $this->createMock(IAccount::class);
141
+        $barAccount->expects($this->once())
142
+            ->method('getPropertyCollection')
143
+            ->with(IAccountManager::COLLECTION_EMAIL)
144
+            ->willReturn($barAccountPropertyCollection);
145
+
146
+        $this->accountManager
147
+            ->expects($this->exactly(2))
148
+            ->method('getAccount')
149
+            ->willReturnMap([
150
+                [$fooUser, $fooAccount],
151
+                [$barUser, $barAccount],
152
+            ]);
153
+
154
+        $expectedResponse = [
155
+            0 => [
156
+                'uri' => 'principals/users/foo',
157
+                '{DAV:}displayname' => 'Dr. Foo-Bar',
158
+                '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
159
+                '{http://nextcloud.com/ns}language' => 'de',
160
+            ],
161
+            1 => [
162
+                'uri' => 'principals/users/bar',
163
+                '{DAV:}displayname' => 'bar',
164
+                '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
165
+                '{http://nextcloud.com/ns}language' => 'en',
166
+                '{http://sabredav.org/ns}email-address' => '[email protected]',
167
+                '{DAV:}alternate-URI-set' => ['mailto:[email protected]', 'mailto:[email protected]']
168
+            ]
169
+        ];
170
+        $response = $this->connector->getPrincipalsByPrefix('principals/users');
171
+        $this->assertSame($expectedResponse, $response);
172
+    }
173
+
174
+    public function testGetPrincipalsByPrefixEmpty(): void {
175
+        $this->userManager
176
+            ->expects($this->once())
177
+            ->method('search')
178
+            ->with('')
179
+            ->willReturn([]);
180
+
181
+        $response = $this->connector->getPrincipalsByPrefix('principals/users');
182
+        $this->assertSame([], $response);
183
+    }
184
+
185
+    public function testGetPrincipalsByPathWithoutMail(): void {
186
+        $fooUser = $this->createMock(User::class);
187
+        $fooUser
188
+            ->expects($this->once())
189
+            ->method('getUID')
190
+            ->willReturn('foo');
191
+        $this->userManager
192
+            ->expects($this->once())
193
+            ->method('get')
194
+            ->with('foo')
195
+            ->willReturn($fooUser);
196
+
197
+        $this->languageFactory
198
+            ->expects($this->once())
199
+            ->method('getUserLanguage')
200
+            ->with($fooUser)
201
+            ->willReturn('de');
202
+
203
+        $expectedResponse = [
204
+            'uri' => 'principals/users/foo',
205
+            '{DAV:}displayname' => 'foo',
206
+            '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
207
+            '{http://nextcloud.com/ns}language' => 'de'
208
+        ];
209
+        $response = $this->connector->getPrincipalByPath('principals/users/foo');
210
+        $this->assertSame($expectedResponse, $response);
211
+    }
212
+
213
+    public function testGetPrincipalsByPathWithMail(): void {
214
+        $fooUser = $this->createMock(User::class);
215
+        $fooUser
216
+            ->expects($this->once())
217
+            ->method('getSystemEMailAddress')
218
+            ->willReturn('[email protected]');
219
+        $fooUser
220
+            ->expects($this->once())
221
+            ->method('getUID')
222
+            ->willReturn('foo');
223
+        $this->userManager
224
+            ->expects($this->once())
225
+            ->method('get')
226
+            ->with('foo')
227
+            ->willReturn($fooUser);
228
+
229
+        $this->languageFactory
230
+            ->expects($this->once())
231
+            ->method('getUserLanguage')
232
+            ->with($fooUser)
233
+            ->willReturn('de');
234
+
235
+        $expectedResponse = [
236
+            'uri' => 'principals/users/foo',
237
+            '{DAV:}displayname' => 'foo',
238
+            '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'INDIVIDUAL',
239
+            '{http://nextcloud.com/ns}language' => 'de',
240
+            '{http://sabredav.org/ns}email-address' => '[email protected]',
241
+        ];
242
+        $response = $this->connector->getPrincipalByPath('principals/users/foo');
243
+        $this->assertSame($expectedResponse, $response);
244
+    }
245
+
246
+    public function testGetPrincipalsByPathEmpty(): void {
247
+        $this->userManager
248
+            ->expects($this->once())
249
+            ->method('get')
250
+            ->with('foo')
251
+            ->willReturn(null);
252
+
253
+        $response = $this->connector->getPrincipalByPath('principals/users/foo');
254
+        $this->assertNull($response);
255
+    }
256
+
257
+    public function testGetGroupMemberSet(): void {
258
+        $response = $this->connector->getGroupMemberSet('principals/users/foo');
259
+        $this->assertSame([], $response);
260
+    }
261
+
262
+
263
+    public function testGetGroupMemberSetEmpty(): void {
264
+        $this->expectException(Exception::class);
265
+        $this->expectExceptionMessage('Principal not found');
266
+
267
+        $this->userManager
268
+            ->expects($this->once())
269
+            ->method('get')
270
+            ->with('foo')
271
+            ->willReturn(null);
272
+
273
+        $this->connector->getGroupMemberSet('principals/users/foo/calendar-proxy-read');
274
+    }
275
+
276
+    public function testGetGroupMemberSetProxyRead(): void {
277
+        $fooUser = $this->createMock(User::class);
278
+        $fooUser
279
+            ->expects($this->once())
280
+            ->method('getUID')
281
+            ->willReturn('foo');
282
+        $this->userManager
283
+            ->expects($this->once())
284
+            ->method('get')
285
+            ->with('foo')
286
+            ->willReturn($fooUser);
287
+
288
+        $proxy1 = new Proxy();
289
+        $proxy1->setProxyId('proxyId1');
290
+        $proxy1->setPermissions(1);
291
+
292
+        $proxy2 = new Proxy();
293
+        $proxy2->setProxyId('proxyId2');
294
+        $proxy2->setPermissions(3);
295
+
296
+        $proxy3 = new Proxy();
297
+        $proxy3->setProxyId('proxyId3');
298
+        $proxy3->setPermissions(3);
299
+
300
+        $this->proxyMapper->expects($this->once())
301
+            ->method('getProxiesOf')
302
+            ->with('principals/users/foo')
303
+            ->willReturn([$proxy1, $proxy2, $proxy3]);
304
+
305
+        $this->assertEquals(['proxyId1'], $this->connector->getGroupMemberSet('principals/users/foo/calendar-proxy-read'));
306
+    }
307
+
308
+    public function testGetGroupMemberSetProxyWrite(): void {
309
+        $fooUser = $this->createMock(User::class);
310
+        $fooUser
311
+            ->expects($this->once())
312
+            ->method('getUID')
313
+            ->willReturn('foo');
314
+        $this->userManager
315
+            ->expects($this->once())
316
+            ->method('get')
317
+            ->with('foo')
318
+            ->willReturn($fooUser);
319
+
320
+        $proxy1 = new Proxy();
321
+        $proxy1->setProxyId('proxyId1');
322
+        $proxy1->setPermissions(1);
323
+
324
+        $proxy2 = new Proxy();
325
+        $proxy2->setProxyId('proxyId2');
326
+        $proxy2->setPermissions(3);
327
+
328
+        $proxy3 = new Proxy();
329
+        $proxy3->setProxyId('proxyId3');
330
+        $proxy3->setPermissions(3);
331
+
332
+        $this->proxyMapper->expects($this->once())
333
+            ->method('getProxiesOf')
334
+            ->with('principals/users/foo')
335
+            ->willReturn([$proxy1, $proxy2, $proxy3]);
336
+
337
+        $this->assertEquals(['proxyId2', 'proxyId3'], $this->connector->getGroupMemberSet('principals/users/foo/calendar-proxy-write'));
338
+    }
339
+
340
+    public function testGetGroupMembership(): void {
341
+        $fooUser = $this->createMock(User::class);
342
+        $group1 = $this->createMock(IGroup::class);
343
+        $group1->expects($this->once())
344
+            ->method('getGID')
345
+            ->willReturn('group1');
346
+        $group2 = $this->createMock(IGroup::class);
347
+        $group2->expects($this->once())
348
+            ->method('getGID')
349
+            ->willReturn('foo/bar');
350
+        $this->userManager
351
+            ->expects($this->exactly(2))
352
+            ->method('get')
353
+            ->with('foo')
354
+            ->willReturn($fooUser);
355
+        $this->groupManager
356
+            ->expects($this->once())
357
+            ->method('getUserGroups')
358
+            ->with($fooUser)
359
+            ->willReturn([
360
+                $group1,
361
+                $group2,
362
+            ]);
363
+
364
+        $proxy1 = new Proxy();
365
+        $proxy1->setOwnerId('proxyId1');
366
+        $proxy1->setPermissions(1);
367
+
368
+        $proxy2 = new Proxy();
369
+        $proxy2->setOwnerId('proxyId2');
370
+        $proxy2->setPermissions(3);
371
+
372
+        $this->proxyMapper->expects($this->once())
373
+            ->method('getProxiesFor')
374
+            ->with('principals/users/foo')
375
+            ->willReturn([$proxy1, $proxy2]);
376
+
377
+        $expectedResponse = [
378
+            'principals/groups/group1',
379
+            'principals/groups/foo%2Fbar',
380
+            'proxyId1/calendar-proxy-read',
381
+            'proxyId2/calendar-proxy-write',
382
+        ];
383
+        $response = $this->connector->getGroupMembership('principals/users/foo');
384
+        $this->assertSame($expectedResponse, $response);
385
+    }
386
+
387
+
388
+    public function testGetGroupMembershipEmpty(): void {
389
+        $this->expectException(Exception::class);
390
+        $this->expectExceptionMessage('Principal not found');
391
+
392
+        $this->userManager
393
+            ->expects($this->once())
394
+            ->method('get')
395
+            ->with('foo')
396
+            ->willReturn(null);
397
+
398
+        $this->connector->getGroupMembership('principals/users/foo');
399
+    }
400
+
401
+
402
+    public function testSetGroupMembership(): void {
403
+        $this->expectException(Exception::class);
404
+        $this->expectExceptionMessage('Setting members of the group is not supported yet');
405
+
406
+        $this->connector->setGroupMemberSet('principals/users/foo', ['foo']);
407
+    }
408
+
409
+    public function testSetGroupMembershipProxy(): void {
410
+        $fooUser = $this->createMock(User::class);
411
+        $fooUser
412
+            ->expects($this->once())
413
+            ->method('getUID')
414
+            ->willReturn('foo');
415
+        $barUser = $this->createMock(User::class);
416
+        $barUser
417
+            ->expects($this->once())
418
+            ->method('getUID')
419
+            ->willReturn('bar');
420
+        $this->userManager
421
+            ->expects($this->exactly(2))
422
+            ->method('get')
423
+            ->willReturnMap([
424
+                ['foo', $fooUser],
425
+                ['bar', $barUser],
426
+            ]);
427
+
428
+        $this->proxyMapper->expects($this->once())
429
+            ->method('getProxiesOf')
430
+            ->with('principals/users/foo')
431
+            ->willReturn([]);
432
+
433
+        $this->proxyMapper->expects($this->once())
434
+            ->method('insert')
435
+            ->with($this->callback(function ($proxy) {
436
+                /** @var Proxy $proxy */
437
+                if ($proxy->getOwnerId() !== 'principals/users/foo') {
438
+                    return false;
439
+                }
440
+                if ($proxy->getProxyId() !== 'principals/users/bar') {
441
+                    return false;
442
+                }
443
+                if ($proxy->getPermissions() !== 3) {
444
+                    return false;
445
+                }
446
+
447
+                return true;
448
+            }));
449
+
450
+        $this->connector->setGroupMemberSet('principals/users/foo/calendar-proxy-write', ['principals/users/bar']);
451
+    }
452
+
453
+    public function testUpdatePrincipal(): void {
454
+        $this->assertSame(0, $this->connector->updatePrincipal('foo', new PropPatch([])));
455
+    }
456
+
457
+    public function testSearchPrincipalsWithEmptySearchProperties(): void {
458
+        $this->assertSame([], $this->connector->searchPrincipals('principals/users', []));
459
+    }
460
+
461
+    public function testSearchPrincipalsWithWrongPrefixPath(): void {
462
+        $this->assertSame([], $this->connector->searchPrincipals('principals/groups',
463
+            ['{http://sabredav.org/ns}email-address' => 'foo']));
464
+    }
465
+
466
+    #[\PHPUnit\Framework\Attributes\DataProvider('searchPrincipalsDataProvider')]
467
+    public function testSearchPrincipals(bool $sharingEnabled, bool $groupsOnly, string $test, array $result): void {
468
+        $this->shareManager->expects($this->once())
469
+            ->method('shareAPIEnabled')
470
+            ->willReturn($sharingEnabled);
471
+
472
+        $getUserGroupIdsReturnMap = [];
473
+
474
+        if ($sharingEnabled) {
475
+            $this->shareManager->expects($this->once())
476
+                ->method('allowEnumeration')
477
+                ->willReturn(true);
478
+
479
+            $this->shareManager->expects($this->once())
480
+                ->method('shareWithGroupMembersOnly')
481
+                ->willReturn($groupsOnly);
482
+
483
+            if ($groupsOnly) {
484
+                $user = $this->createMock(IUser::class);
485
+                $this->userSession->expects($this->atLeastOnce())
486
+                    ->method('getUser')
487
+                    ->willReturn($user);
488
+
489
+                $getUserGroupIdsReturnMap[] = [$user, ['group1', 'group2', 'group5']];
490
+            }
491
+        } else {
492
+            $this->config->expects($this->never())
493
+                ->method('getAppValue');
494
+            $this->shareManager->expects($this->never())
495
+                ->method('shareWithGroupMembersOnly');
496
+            $this->groupManager->expects($this->never())
497
+                ->method($this->anything());
498
+        }
499
+
500
+        $user2 = $this->createMock(IUser::class);
501
+        $user2->method('getUID')->willReturn('user2');
502
+        $user3 = $this->createMock(IUser::class);
503
+        $user3->method('getUID')->willReturn('user3');
504
+        $user4 = $this->createMock(IUser::class);
505
+        $user4->method('getUID')->willReturn('user4');
506
+
507
+        if ($sharingEnabled) {
508
+            $this->userManager->expects($this->once())
509
+                ->method('getByEmail')
510
+                ->with('[email protected]')
511
+                ->willReturn([$user2, $user3]);
512
+
513
+            $this->userManager->expects($this->once())
514
+                ->method('searchDisplayName')
515
+                ->with('User 12')
516
+                ->willReturn([$user3, $user4]);
517
+        } else {
518
+            $this->userManager->expects($this->never())
519
+                ->method('getByEmail');
520
+
521
+            $this->userManager->expects($this->never())
522
+                ->method('searchDisplayName');
523
+        }
524
+
525
+        if ($sharingEnabled && $groupsOnly) {
526
+            $getUserGroupIdsReturnMap[] = [$user2, ['group1', 'group3']];
527
+            $getUserGroupIdsReturnMap[] = [$user3, ['group3', 'group4']];
528
+            $getUserGroupIdsReturnMap[] = [$user4, ['group4', 'group5']];
529
+        }
530
+
531
+        $this->groupManager->expects($this->any())
532
+            ->method('getUserGroupIds')
533
+            ->willReturnMap($getUserGroupIdsReturnMap);
534
+
535
+
536
+        $this->assertEquals($result, $this->connector->searchPrincipals('principals/users',
537
+            ['{http://sabredav.org/ns}email-address' => '[email protected]',
538
+                '{DAV:}displayname' => 'User 12'], $test));
539
+    }
540
+
541
+    public static function searchPrincipalsDataProvider(): array {
542
+        return [
543
+            [true, false, 'allof', ['principals/users/user3']],
544
+            [true, false, 'anyof', ['principals/users/user2', 'principals/users/user3', 'principals/users/user4']],
545
+            [true, true, 'allof', []],
546
+            [true, true, 'anyof', ['principals/users/user2', 'principals/users/user4']],
547
+            [false, false, 'allof', []],
548
+            [false, false, 'anyof', []],
549
+        ];
550
+    }
551
+
552
+    public function testSearchPrincipalByCalendarUserAddressSet(): void {
553
+        $this->shareManager->expects($this->exactly(2))
554
+            ->method('shareAPIEnabled')
555
+            ->willReturn(true);
556
+
557
+        $this->shareManager->expects($this->exactly(2))
558
+            ->method('allowEnumeration')
559
+            ->willReturn(true);
560
+
561
+        $this->shareManager->expects($this->exactly(2))
562
+            ->method('shareWithGroupMembersOnly')
563
+            ->willReturn(false);
564
+
565
+        $user2 = $this->createMock(IUser::class);
566
+        $user2->method('getUID')->willReturn('user2');
567
+        $user3 = $this->createMock(IUser::class);
568
+        $user3->method('getUID')->willReturn('user3');
569
+
570
+        $this->userManager->expects($this->once())
571
+            ->method('getByEmail')
572
+            ->with('[email protected]')
573
+            ->willReturn([$user2, $user3]);
574
+
575
+        $this->assertEquals([
576
+            'principals/users/user2',
577
+            'principals/users/user3',
578
+        ], $this->connector->searchPrincipals('principals/users',
579
+            ['{urn:ietf:params:xml:ns:caldav}calendar-user-address-set' => '[email protected]']));
580
+    }
581
+
582
+    public function testSearchPrincipalWithEnumerationDisabledDisplayname(): void {
583
+        $this->shareManager->expects($this->once())
584
+            ->method('shareAPIEnabled')
585
+            ->willReturn(true);
586
+
587
+        $this->shareManager->expects($this->once())
588
+            ->method('allowEnumeration')
589
+            ->willReturn(false);
590
+
591
+        $this->shareManager->expects($this->once())
592
+            ->method('shareWithGroupMembersOnly')
593
+            ->willReturn(false);
594
+
595
+        $this->shareManager->expects($this->once())
596
+            ->method('allowEnumerationFullMatch')
597
+            ->willReturn(true);
598
+
599
+        $user2 = $this->createMock(IUser::class);
600
+        $user2->method('getUID')->willReturn('user2');
601
+        $user2->method('getDisplayName')->willReturn('User 2');
602
+        $user2->method('getSystemEMailAddress')->willReturn('[email protected]');
603
+        $user3 = $this->createMock(IUser::class);
604
+        $user3->method('getUID')->willReturn('user3');
605
+        $user3->method('getDisplayName')->willReturn('User 22');
606
+        $user3->method('getSystemEMailAddress')->willReturn('[email protected]');
607
+        $user4 = $this->createMock(IUser::class);
608
+        $user4->method('getUID')->willReturn('user4');
609
+        $user4->method('getDisplayName')->willReturn('User 222');
610
+        $user4->method('getSystemEMailAddress')->willReturn('[email protected]');
611
+
612
+        $this->userManager->expects($this->once())
613
+            ->method('searchDisplayName')
614
+            ->with('User 2')
615
+            ->willReturn([$user2, $user3, $user4]);
616
+
617
+        $this->assertEquals(['principals/users/user2'], $this->connector->searchPrincipals('principals/users',
618
+            ['{DAV:}displayname' => 'User 2']));
619
+    }
620
+
621
+    public function testSearchPrincipalWithEnumerationDisabledDisplaynameOnFullMatch(): void {
622
+        $this->shareManager->expects($this->once())
623
+            ->method('shareAPIEnabled')
624
+            ->willReturn(true);
625
+
626
+        $this->shareManager->expects($this->once())
627
+            ->method('allowEnumeration')
628
+            ->willReturn(false);
629
+
630
+        $this->shareManager->expects($this->once())
631
+            ->method('shareWithGroupMembersOnly')
632
+            ->willReturn(false);
633
+
634
+        $this->shareManager->expects($this->once())
635
+            ->method('allowEnumerationFullMatch')
636
+            ->willReturn(false);
637
+
638
+        $this->assertEquals([], $this->connector->searchPrincipals('principals/users',
639
+            ['{DAV:}displayname' => 'User 2']));
640
+    }
641
+
642
+    public function testSearchPrincipalWithEnumerationDisabledEmail(): void {
643
+        $this->shareManager->expects($this->once())
644
+            ->method('shareAPIEnabled')
645
+            ->willReturn(true);
646
+
647
+        $this->shareManager->expects($this->once())
648
+            ->method('allowEnumeration')
649
+            ->willReturn(false);
650
+
651
+        $this->shareManager->expects($this->once())
652
+            ->method('shareWithGroupMembersOnly')
653
+            ->willReturn(false);
654
+
655
+        $this->shareManager->expects($this->once())
656
+            ->method('allowEnumerationFullMatch')
657
+            ->willReturn(true);
658
+
659
+        $this->shareManager->expects($this->once())
660
+            ->method('matchEmail')
661
+            ->willReturn(true);
662
+
663
+        $user2 = $this->createMock(IUser::class);
664
+        $user2->method('getUID')->willReturn('user2');
665
+        $user2->method('getDisplayName')->willReturn('User 2');
666
+        $user2->method('getSystemEMailAddress')->willReturn('[email protected]');
667
+        $user3 = $this->createMock(IUser::class);
668
+        $user3->method('getUID')->willReturn('user3');
669
+        $user2->method('getDisplayName')->willReturn('User 22');
670
+        $user2->method('getSystemEMailAddress')->willReturn('[email protected]');
671
+        $user4 = $this->createMock(IUser::class);
672
+        $user4->method('getUID')->willReturn('user4');
673
+        $user2->method('getDisplayName')->willReturn('User 222');
674
+        $user2->method('getSystemEMailAddress')->willReturn('[email protected]');
675
+
676
+        $this->userManager->expects($this->once())
677
+            ->method('getByEmail')
678
+            ->with('[email protected]')
679
+            ->willReturn([$user2]);
680
+
681
+        $this->assertEquals(['principals/users/user2'], $this->connector->searchPrincipals('principals/users',
682
+            ['{http://sabredav.org/ns}email-address' => '[email protected]']));
683
+    }
684
+
685
+    public function testSearchPrincipalWithEnumerationDisabledEmailOnFullMatch(): void {
686
+        $this->shareManager->expects($this->once())
687
+            ->method('shareAPIEnabled')
688
+            ->willReturn(true);
689
+
690
+        $this->shareManager->expects($this->once())
691
+            ->method('allowEnumeration')
692
+            ->willReturn(false);
693
+
694
+        $this->shareManager->expects($this->once())
695
+            ->method('shareWithGroupMembersOnly')
696
+            ->willReturn(false);
697
+
698
+        $this->shareManager->expects($this->once())
699
+            ->method('allowEnumerationFullMatch')
700
+            ->willReturn(false);
701
+
702
+
703
+        $this->assertEquals([], $this->connector->searchPrincipals('principals/users',
704
+            ['{http://sabredav.org/ns}email-address' => '[email protected]']));
705
+    }
706
+
707
+    public function testSearchPrincipalWithEnumerationLimitedDisplayname(): void {
708
+        $this->shareManager->expects($this->once())
709
+            ->method('shareAPIEnabled')
710
+            ->willReturn(true);
711
+
712
+        $this->shareManager->expects($this->once())
713
+            ->method('allowEnumeration')
714
+            ->willReturn(true);
715
+
716
+        $this->shareManager->expects($this->once())
717
+            ->method('limitEnumerationToGroups')
718
+            ->willReturn(true);
719
+
720
+        $this->shareManager->expects($this->once())
721
+            ->method('shareWithGroupMembersOnly')
722
+            ->willReturn(false);
723
+
724
+        $user2 = $this->createMock(IUser::class);
725
+        $user2->method('getUID')->willReturn('user2');
726
+        $user2->method('getDisplayName')->willReturn('User 2');
727
+        $user2->method('getSystemEMailAddress')->willReturn('[email protected]');
728
+        $user3 = $this->createMock(IUser::class);
729
+        $user3->method('getUID')->willReturn('user3');
730
+        $user3->method('getDisplayName')->willReturn('User 22');
731
+        $user3->method('getSystemEMailAddress')->willReturn('[email protected]');
732
+        $user4 = $this->createMock(IUser::class);
733
+        $user4->method('getUID')->willReturn('user4');
734
+        $user4->method('getDisplayName')->willReturn('User 222');
735
+        $user4->method('getSystemEMailAddress')->willReturn('[email protected]');
736
+
737
+
738
+        $this->userSession->expects($this->once())
739
+            ->method('getUser')
740
+            ->willReturn($user2);
741
+
742
+        $this->groupManager->expects($this->exactly(4))
743
+            ->method('getUserGroupIds')
744
+            ->willReturnMap([
745
+                [$user2, ['group1']],
746
+                [$user3, ['group1']],
747
+                [$user4, ['group2']],
748
+            ]);
749
+
750
+        $this->userManager->expects($this->once())
751
+            ->method('searchDisplayName')
752
+            ->with('User')
753
+            ->willReturn([$user2, $user3, $user4]);
754
+
755
+
756
+        $this->assertEquals([
757
+            'principals/users/user2',
758
+            'principals/users/user3',
759
+        ], $this->connector->searchPrincipals('principals/users',
760
+            ['{DAV:}displayname' => 'User']));
761
+    }
762
+
763
+    public function testSearchPrincipalWithEnumerationLimitedMail(): void {
764
+        $this->shareManager->expects($this->once())
765
+            ->method('shareAPIEnabled')
766
+            ->willReturn(true);
767
+
768
+        $this->shareManager->expects($this->once())
769
+            ->method('allowEnumeration')
770
+            ->willReturn(true);
771
+
772
+        $this->shareManager->expects($this->once())
773
+            ->method('limitEnumerationToGroups')
774
+            ->willReturn(true);
775
+
776
+        $this->shareManager->expects($this->once())
777
+            ->method('shareWithGroupMembersOnly')
778
+            ->willReturn(false);
779
+
780
+        $user2 = $this->createMock(IUser::class);
781
+        $user2->method('getUID')->willReturn('user2');
782
+        $user2->method('getDisplayName')->willReturn('User 2');
783
+        $user2->method('getSystemEMailAddress')->willReturn('[email protected]');
784
+        $user3 = $this->createMock(IUser::class);
785
+        $user3->method('getUID')->willReturn('user3');
786
+        $user3->method('getDisplayName')->willReturn('User 22');
787
+        $user3->method('getSystemEMailAddress')->willReturn('[email protected]');
788
+        $user4 = $this->createMock(IUser::class);
789
+        $user4->method('getUID')->willReturn('user4');
790
+        $user4->method('getDisplayName')->willReturn('User 222');
791
+        $user4->method('getSystemEMailAddress')->willReturn('[email protected]');
792
+
793
+
794
+        $this->userSession->expects($this->once())
795
+            ->method('getUser')
796
+            ->willReturn($user2);
797
+
798
+        $this->groupManager->expects($this->exactly(4))
799
+            ->method('getUserGroupIds')
800
+            ->willReturnMap([
801
+                [$user2, ['group1']],
802
+                [$user3, ['group1']],
803
+                [$user4, ['group2']],
804
+            ]);
805
+
806
+        $this->userManager->expects($this->once())
807
+            ->method('getByEmail')
808
+            ->with('user')
809
+            ->willReturn([$user2, $user3, $user4]);
810
+
811
+
812
+        $this->assertEquals([
813
+            'principals/users/user2',
814
+            'principals/users/user3'
815
+        ], $this->connector->searchPrincipals('principals/users',
816
+            ['{http://sabredav.org/ns}email-address' => 'user']));
817
+    }
818
+
819
+    public function testFindByUriSharingApiDisabled(): void {
820
+        $this->shareManager->expects($this->once())
821
+            ->method('shareApiEnabled')
822
+            ->willReturn(false);
823
+
824
+        $this->assertEquals(null, $this->connector->findByUri('mailto:[email protected]', 'principals/users'));
825
+    }
826
+
827
+    #[\PHPUnit\Framework\Attributes\DataProvider('findByUriWithGroupRestrictionDataProvider')]
828
+    public function testFindByUriWithGroupRestriction(string $uri, string $email, ?string $expects): void {
829
+        $this->shareManager->expects($this->once())
830
+            ->method('shareApiEnabled')
831
+            ->willReturn(true);
832
+
833
+        $this->shareManager->expects($this->once())
834
+            ->method('shareWithGroupMembersOnly')
835
+            ->willReturn(true);
836
+
837
+        $user = $this->createMock(IUser::class);
838
+        $this->userSession->expects($this->once())
839
+            ->method('getUser')
840
+            ->willReturn($user);
841
+
842
+        $user2 = $this->createMock(IUser::class);
843
+        $user2->method('getUID')->willReturn('user2');
844
+        $user3 = $this->createMock(IUser::class);
845
+        $user3->method('getUID')->willReturn('user3');
846
+
847
+        $this->userManager->expects($this->once())
848
+            ->method('getByEmail')
849
+            ->with($email)
850
+            ->willReturn([$email === '[email protected]' ? $user2 : $user3]);
851
+
852
+        if ($email === '[email protected]') {
853
+            $this->groupManager->expects($this->exactly(2))
854
+                ->method('getUserGroupIds')
855
+                ->willReturnMap([
856
+                    [$user, ['group1', 'group2']],
857
+                    [$user2, ['group1', 'group3']],
858
+                ]);
859
+        } else {
860
+            $this->groupManager->expects($this->exactly(2))
861
+                ->method('getUserGroupIds')
862
+                ->willReturnMap([
863
+                    [$user, ['group1', 'group2']],
864
+                    [$user3, ['group3', 'group3']],
865
+                ]);
866
+        }
867
+
868
+        $this->assertEquals($expects, $this->connector->findByUri($uri, 'principals/users'));
869
+    }
870
+
871
+    public static function findByUriWithGroupRestrictionDataProvider(): array {
872
+        return [
873
+            ['mailto:[email protected]', '[email protected]', 'principals/users/user2'],
874
+            ['mailto:[email protected]', '[email protected]', null],
875
+        ];
876
+    }
877
+
878
+    #[\PHPUnit\Framework\Attributes\DataProvider('findByUriWithoutGroupRestrictionDataProvider')]
879
+    public function testFindByUriWithoutGroupRestriction(string $uri, string $email, string $expects): void {
880
+        $this->shareManager->expects($this->once())
881
+            ->method('shareApiEnabled')
882
+            ->willReturn(true);
883
+
884
+        $this->shareManager->expects($this->once())
885
+            ->method('shareWithGroupMembersOnly')
886
+            ->willReturn(false);
887
+
888
+        $user2 = $this->createMock(IUser::class);
889
+        $user2->method('getUID')->willReturn('user2');
890
+        $user3 = $this->createMock(IUser::class);
891
+        $user3->method('getUID')->willReturn('user3');
892
+
893
+        $this->userManager->expects($this->once())
894
+            ->method('getByEmail')
895
+            ->with($email)
896
+            ->willReturn([$email === '[email protected]' ? $user2 : $user3]);
897
+
898
+        $this->assertEquals($expects, $this->connector->findByUri($uri, 'principals/users'));
899
+    }
900
+
901
+    public static function findByUriWithoutGroupRestrictionDataProvider(): array {
902
+        return [
903
+            ['mailto:[email protected]', '[email protected]', 'principals/users/user2'],
904
+            ['mailto:[email protected]', '[email protected]', 'principals/users/user3'],
905
+        ];
906
+    }
907
+
908
+    public function testGetEmailAddressesOfPrincipal(): void {
909
+        $principal = [
910
+            '{http://sabredav.org/ns}email-address' => '[email protected]',
911
+            '{DAV:}alternate-URI-set' => [
912
+                '/some/url',
913
+                'mailto:[email protected]',
914
+                'mailto:[email protected]',
915
+            ],
916
+            '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set' => [
917
+                'mailto:[email protected]',
918
+                'mailto:[email protected]',
919
+            ],
920
+            '{http://calendarserver.org/ns/}email-address-set' => [
921
+                'mailto:[email protected]',
922
+                'mailto:[email protected]',
923
+            ],
924
+        ];
925
+
926
+        $expected = [
927
+            '[email protected]',
928
+            '[email protected]',
929
+            '[email protected]',
930
+            '[email protected]',
931
+            '[email protected]',
932
+            '[email protected]',
933
+        ];
934
+        $actual = $this->connector->getEmailAddressesOfPrincipal($principal);
935
+        $this->assertEquals($expected, $actual);
936
+    }
937 937
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Connector/Sabre/QuotaPluginTest.php 1 patch
Indentation   +135 added lines, -135 removed lines patch added patch discarded remove patch
@@ -14,139 +14,139 @@
 block discarded – undo
14 14
 use Test\TestCase;
15 15
 
16 16
 class QuotaPluginTest extends TestCase {
17
-	private \Sabre\DAV\Server $server;
18
-
19
-	private QuotaPlugin $plugin;
20
-
21
-	private function init(int $quota, string $checkedPath = ''): void {
22
-		$view = $this->buildFileViewMock((string)$quota, $checkedPath);
23
-		$this->server = new \Sabre\DAV\Server();
24
-		$this->plugin = new QuotaPlugin($view);
25
-		$this->plugin->initialize($this->server);
26
-	}
27
-
28
-	#[\PHPUnit\Framework\Attributes\DataProvider('lengthProvider')]
29
-	public function testLength(?int $expected, array $headers): void {
30
-		$this->init(0);
31
-
32
-		$this->server->httpRequest = new \Sabre\HTTP\Request('POST', 'dummy.file', $headers);
33
-		$length = $this->plugin->getLength();
34
-		$this->assertEquals($expected, $length);
35
-	}
36
-
37
-	#[\PHPUnit\Framework\Attributes\DataProvider('quotaOkayProvider')]
38
-	public function testCheckQuota(int $quota, array $headers): void {
39
-		$this->init($quota);
40
-
41
-		$this->server->httpRequest = new \Sabre\HTTP\Request('POST', 'dummy.file', $headers);
42
-		$result = $this->plugin->checkQuota('');
43
-		$this->assertTrue($result);
44
-	}
45
-
46
-	#[\PHPUnit\Framework\Attributes\DataProvider('quotaExceededProvider')]
47
-	public function testCheckExceededQuota(int $quota, array $headers): void {
48
-		$this->expectException(\Sabre\DAV\Exception\InsufficientStorage::class);
49
-
50
-		$this->init($quota);
51
-
52
-		$this->server->httpRequest = new \Sabre\HTTP\Request('POST', 'dummy.file', $headers);
53
-		$this->plugin->checkQuota('');
54
-	}
55
-
56
-	#[\PHPUnit\Framework\Attributes\DataProvider('quotaOkayProvider')]
57
-	public function testCheckQuotaOnPath(int $quota, array $headers): void {
58
-		$this->init($quota, 'sub/test.txt');
59
-
60
-		$this->server->httpRequest = new \Sabre\HTTP\Request('POST', 'dummy.file', $headers);
61
-		$result = $this->plugin->checkQuota('/sub/test.txt');
62
-		$this->assertTrue($result);
63
-	}
64
-
65
-	public static function quotaOkayProvider(): array {
66
-		return [
67
-			[1024, []],
68
-			[1024, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
69
-			[1024, ['CONTENT-LENGTH' => '512']],
70
-			[1024, ['OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512']],
71
-
72
-			[FileInfo::SPACE_UNKNOWN, []],
73
-			[FileInfo::SPACE_UNKNOWN, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
74
-			[FileInfo::SPACE_UNKNOWN, ['CONTENT-LENGTH' => '512']],
75
-			[FileInfo::SPACE_UNKNOWN, ['OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512']],
76
-
77
-			[FileInfo::SPACE_UNLIMITED, []],
78
-			[FileInfo::SPACE_UNLIMITED, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
79
-			[FileInfo::SPACE_UNLIMITED, ['CONTENT-LENGTH' => '512']],
80
-			[FileInfo::SPACE_UNLIMITED, ['OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512']],
81
-		];
82
-	}
83
-
84
-	public static function quotaExceededProvider(): array {
85
-		return [
86
-			[1023, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
87
-			[511, ['CONTENT-LENGTH' => '512']],
88
-			[2047, ['OC-TOTAL-LENGTH' => '2048', 'CONTENT-LENGTH' => '1024']],
89
-		];
90
-	}
91
-
92
-	public static function lengthProvider(): array {
93
-		return [
94
-			[null, []],
95
-			[1024, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
96
-			[512, ['CONTENT-LENGTH' => '512']],
97
-			[2048, ['OC-TOTAL-LENGTH' => '2048', 'CONTENT-LENGTH' => '1024']],
98
-			[4096, ['OC-TOTAL-LENGTH' => '2048', 'X-EXPECTED-ENTITY-LENGTH' => '4096']],
99
-			[null, ['X-EXPECTED-ENTITY-LENGTH' => 'A']],
100
-			[null, ['CONTENT-LENGTH' => 'A']],
101
-			[1024, ['OC-TOTAL-LENGTH' => 'A', 'CONTENT-LENGTH' => '1024']],
102
-			[1024, ['OC-TOTAL-LENGTH' => 'A', 'X-EXPECTED-ENTITY-LENGTH' => '1024']],
103
-			[2048, ['OC-TOTAL-LENGTH' => '2048', 'X-EXPECTED-ENTITY-LENGTH' => 'A']],
104
-			[2048, ['OC-TOTAL-LENGTH' => '2048', 'CONTENT-LENGTH' => 'A']],
105
-		];
106
-	}
107
-
108
-	public static function quotaChunkedOkProvider(): array {
109
-		return [
110
-			[1024, 0, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
111
-			[1024, 0, ['CONTENT-LENGTH' => '512']],
112
-			[1024, 0, ['OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512']],
113
-			// with existing chunks (allowed size = total length - chunk total size)
114
-			[400, 128, ['X-EXPECTED-ENTITY-LENGTH' => '512']],
115
-			[400, 128, ['CONTENT-LENGTH' => '512']],
116
-			[400, 128, ['OC-TOTAL-LENGTH' => '512', 'CONTENT-LENGTH' => '500']],
117
-			// \OCP\Files\FileInfo::SPACE-UNKNOWN = -2
118
-			[-2, 0, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
119
-			[-2, 0, ['CONTENT-LENGTH' => '512']],
120
-			[-2, 0, ['OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512']],
121
-			[-2, 128, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
122
-			[-2, 128, ['CONTENT-LENGTH' => '512']],
123
-			[-2, 128, ['OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512']],
124
-		];
125
-	}
126
-
127
-	public static function quotaChunkedFailProvider(): array {
128
-		return [
129
-			[400, 0, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
130
-			[400, 0, ['CONTENT-LENGTH' => '512']],
131
-			[400, 0, ['OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512']],
132
-			// with existing chunks (allowed size = total length - chunk total size)
133
-			[380, 128, ['X-EXPECTED-ENTITY-LENGTH' => '512']],
134
-			[380, 128, ['CONTENT-LENGTH' => '512']],
135
-			[380, 128, ['OC-TOTAL-LENGTH' => '512', 'CONTENT-LENGTH' => '500']],
136
-		];
137
-	}
138
-
139
-	private function buildFileViewMock(string $quota, string $checkedPath): View {
140
-		// mock filesystem
141
-		$view = $this->getMockBuilder(View::class)
142
-			->onlyMethods(['free_space'])
143
-			->disableOriginalConstructor()
144
-			->getMock();
145
-		$view->expects($this->any())
146
-			->method('free_space')
147
-			->with($checkedPath)
148
-			->willReturn($quota);
149
-
150
-		return $view;
151
-	}
17
+    private \Sabre\DAV\Server $server;
18
+
19
+    private QuotaPlugin $plugin;
20
+
21
+    private function init(int $quota, string $checkedPath = ''): void {
22
+        $view = $this->buildFileViewMock((string)$quota, $checkedPath);
23
+        $this->server = new \Sabre\DAV\Server();
24
+        $this->plugin = new QuotaPlugin($view);
25
+        $this->plugin->initialize($this->server);
26
+    }
27
+
28
+    #[\PHPUnit\Framework\Attributes\DataProvider('lengthProvider')]
29
+    public function testLength(?int $expected, array $headers): void {
30
+        $this->init(0);
31
+
32
+        $this->server->httpRequest = new \Sabre\HTTP\Request('POST', 'dummy.file', $headers);
33
+        $length = $this->plugin->getLength();
34
+        $this->assertEquals($expected, $length);
35
+    }
36
+
37
+    #[\PHPUnit\Framework\Attributes\DataProvider('quotaOkayProvider')]
38
+    public function testCheckQuota(int $quota, array $headers): void {
39
+        $this->init($quota);
40
+
41
+        $this->server->httpRequest = new \Sabre\HTTP\Request('POST', 'dummy.file', $headers);
42
+        $result = $this->plugin->checkQuota('');
43
+        $this->assertTrue($result);
44
+    }
45
+
46
+    #[\PHPUnit\Framework\Attributes\DataProvider('quotaExceededProvider')]
47
+    public function testCheckExceededQuota(int $quota, array $headers): void {
48
+        $this->expectException(\Sabre\DAV\Exception\InsufficientStorage::class);
49
+
50
+        $this->init($quota);
51
+
52
+        $this->server->httpRequest = new \Sabre\HTTP\Request('POST', 'dummy.file', $headers);
53
+        $this->plugin->checkQuota('');
54
+    }
55
+
56
+    #[\PHPUnit\Framework\Attributes\DataProvider('quotaOkayProvider')]
57
+    public function testCheckQuotaOnPath(int $quota, array $headers): void {
58
+        $this->init($quota, 'sub/test.txt');
59
+
60
+        $this->server->httpRequest = new \Sabre\HTTP\Request('POST', 'dummy.file', $headers);
61
+        $result = $this->plugin->checkQuota('/sub/test.txt');
62
+        $this->assertTrue($result);
63
+    }
64
+
65
+    public static function quotaOkayProvider(): array {
66
+        return [
67
+            [1024, []],
68
+            [1024, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
69
+            [1024, ['CONTENT-LENGTH' => '512']],
70
+            [1024, ['OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512']],
71
+
72
+            [FileInfo::SPACE_UNKNOWN, []],
73
+            [FileInfo::SPACE_UNKNOWN, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
74
+            [FileInfo::SPACE_UNKNOWN, ['CONTENT-LENGTH' => '512']],
75
+            [FileInfo::SPACE_UNKNOWN, ['OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512']],
76
+
77
+            [FileInfo::SPACE_UNLIMITED, []],
78
+            [FileInfo::SPACE_UNLIMITED, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
79
+            [FileInfo::SPACE_UNLIMITED, ['CONTENT-LENGTH' => '512']],
80
+            [FileInfo::SPACE_UNLIMITED, ['OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512']],
81
+        ];
82
+    }
83
+
84
+    public static function quotaExceededProvider(): array {
85
+        return [
86
+            [1023, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
87
+            [511, ['CONTENT-LENGTH' => '512']],
88
+            [2047, ['OC-TOTAL-LENGTH' => '2048', 'CONTENT-LENGTH' => '1024']],
89
+        ];
90
+    }
91
+
92
+    public static function lengthProvider(): array {
93
+        return [
94
+            [null, []],
95
+            [1024, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
96
+            [512, ['CONTENT-LENGTH' => '512']],
97
+            [2048, ['OC-TOTAL-LENGTH' => '2048', 'CONTENT-LENGTH' => '1024']],
98
+            [4096, ['OC-TOTAL-LENGTH' => '2048', 'X-EXPECTED-ENTITY-LENGTH' => '4096']],
99
+            [null, ['X-EXPECTED-ENTITY-LENGTH' => 'A']],
100
+            [null, ['CONTENT-LENGTH' => 'A']],
101
+            [1024, ['OC-TOTAL-LENGTH' => 'A', 'CONTENT-LENGTH' => '1024']],
102
+            [1024, ['OC-TOTAL-LENGTH' => 'A', 'X-EXPECTED-ENTITY-LENGTH' => '1024']],
103
+            [2048, ['OC-TOTAL-LENGTH' => '2048', 'X-EXPECTED-ENTITY-LENGTH' => 'A']],
104
+            [2048, ['OC-TOTAL-LENGTH' => '2048', 'CONTENT-LENGTH' => 'A']],
105
+        ];
106
+    }
107
+
108
+    public static function quotaChunkedOkProvider(): array {
109
+        return [
110
+            [1024, 0, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
111
+            [1024, 0, ['CONTENT-LENGTH' => '512']],
112
+            [1024, 0, ['OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512']],
113
+            // with existing chunks (allowed size = total length - chunk total size)
114
+            [400, 128, ['X-EXPECTED-ENTITY-LENGTH' => '512']],
115
+            [400, 128, ['CONTENT-LENGTH' => '512']],
116
+            [400, 128, ['OC-TOTAL-LENGTH' => '512', 'CONTENT-LENGTH' => '500']],
117
+            // \OCP\Files\FileInfo::SPACE-UNKNOWN = -2
118
+            [-2, 0, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
119
+            [-2, 0, ['CONTENT-LENGTH' => '512']],
120
+            [-2, 0, ['OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512']],
121
+            [-2, 128, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
122
+            [-2, 128, ['CONTENT-LENGTH' => '512']],
123
+            [-2, 128, ['OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512']],
124
+        ];
125
+    }
126
+
127
+    public static function quotaChunkedFailProvider(): array {
128
+        return [
129
+            [400, 0, ['X-EXPECTED-ENTITY-LENGTH' => '1024']],
130
+            [400, 0, ['CONTENT-LENGTH' => '512']],
131
+            [400, 0, ['OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512']],
132
+            // with existing chunks (allowed size = total length - chunk total size)
133
+            [380, 128, ['X-EXPECTED-ENTITY-LENGTH' => '512']],
134
+            [380, 128, ['CONTENT-LENGTH' => '512']],
135
+            [380, 128, ['OC-TOTAL-LENGTH' => '512', 'CONTENT-LENGTH' => '500']],
136
+        ];
137
+    }
138
+
139
+    private function buildFileViewMock(string $quota, string $checkedPath): View {
140
+        // mock filesystem
141
+        $view = $this->getMockBuilder(View::class)
142
+            ->onlyMethods(['free_space'])
143
+            ->disableOriginalConstructor()
144
+            ->getMock();
145
+        $view->expects($this->any())
146
+            ->method('free_space')
147
+            ->with($checkedPath)
148
+            ->willReturn($quota);
149
+
150
+        return $view;
151
+    }
152 152
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Connector/Sabre/FileTest.php 1 patch
Indentation   +964 added lines, -964 removed lines patch added patch discarded remove patch
@@ -51,981 +51,981 @@
 block discarded – undo
51 51
  * @package OCA\DAV\Tests\unit\Connector\Sabre
52 52
  */
53 53
 class FileTest extends TestCase {
54
-	use MountProviderTrait;
55
-	use UserTrait;
56
-
57
-	private string $user;
58
-	protected IConfig&MockObject $config;
59
-	protected IRequestId&MockObject $requestId;
60
-
61
-	protected function setUp(): void {
62
-		parent::setUp();
63
-
64
-		\OC_Hook::clear();
65
-
66
-		$this->user = 'test_user';
67
-		$this->createUser($this->user, 'pass');
68
-
69
-		self::loginAsUser($this->user);
70
-
71
-		$this->config = $this->createMock(IConfig::class);
72
-		$this->requestId = $this->createMock(IRequestId::class);
73
-	}
74
-
75
-	protected function tearDown(): void {
76
-		$userManager = Server::get(IUserManager::class);
77
-		$userManager->get($this->user)->delete();
78
-
79
-		parent::tearDown();
80
-	}
81
-
82
-	private function getMockStorage(): MockObject&IStorage {
83
-		$storage = $this->createMock(IStorage::class);
84
-		$storage->method('getId')
85
-			->willReturn('home::someuser');
86
-		return $storage;
87
-	}
88
-
89
-	private function getStream(string $string) {
90
-		$stream = fopen('php://temp', 'r+');
91
-		fwrite($stream, $string);
92
-		fseek($stream, 0);
93
-		return $stream;
94
-	}
95
-
96
-
97
-	public static function fopenFailuresProvider(): array {
98
-		return [
99
-			[
100
-				// return false
101
-				null,
102
-				'\Sabre\Dav\Exception',
103
-				false
104
-			],
105
-			[
106
-				new NotPermittedException(),
107
-				'Sabre\DAV\Exception\Forbidden'
108
-			],
109
-			[
110
-				new EntityTooLargeException(),
111
-				'OCA\DAV\Connector\Sabre\Exception\EntityTooLarge'
112
-			],
113
-			[
114
-				new InvalidContentException(),
115
-				'OCA\DAV\Connector\Sabre\Exception\UnsupportedMediaType'
116
-			],
117
-			[
118
-				new InvalidPathException(),
119
-				'Sabre\DAV\Exception\Forbidden'
120
-			],
121
-			[
122
-				new ForbiddenException('', true),
123
-				'OCA\DAV\Connector\Sabre\Exception\Forbidden'
124
-			],
125
-			[
126
-				new LockNotAcquiredException('/test.txt', 1),
127
-				'OCA\DAV\Connector\Sabre\Exception\FileLocked'
128
-			],
129
-			[
130
-				new LockedException('/test.txt'),
131
-				'OCA\DAV\Connector\Sabre\Exception\FileLocked'
132
-			],
133
-			[
134
-				new GenericEncryptionException(),
135
-				'Sabre\DAV\Exception\ServiceUnavailable'
136
-			],
137
-			[
138
-				new StorageNotAvailableException(),
139
-				'Sabre\DAV\Exception\ServiceUnavailable'
140
-			],
141
-			[
142
-				new \Sabre\DAV\Exception('Generic sabre exception'),
143
-				'Sabre\DAV\Exception',
144
-				false
145
-			],
146
-			[
147
-				new \Exception('Generic exception'),
148
-				'Sabre\DAV\Exception'
149
-			],
150
-		];
151
-	}
152
-
153
-	#[\PHPUnit\Framework\Attributes\DataProvider('fopenFailuresProvider')]
154
-	public function testSimplePutFails(?\Throwable $thrownException, string $expectedException, bool $checkPreviousClass = true): void {
155
-		// setup
156
-		$storage = $this->getMockBuilder(Local::class)
157
-			->onlyMethods(['writeStream'])
158
-			->setConstructorArgs([['datadir' => Server::get(ITempManager::class)->getTemporaryFolder()]])
159
-			->getMock();
160
-		Filesystem::mount($storage, [], $this->user . '/');
161
-		/** @var View&MockObject $view */
162
-		$view = $this->getMockBuilder(View::class)
163
-			->onlyMethods(['getRelativePath', 'resolvePath'])
164
-			->getMock();
165
-		$view->expects($this->atLeastOnce())
166
-			->method('resolvePath')
167
-			->willReturnCallback(
168
-				function ($path) use ($storage) {
169
-					return [$storage, $path];
170
-				}
171
-			);
172
-
173
-		if ($thrownException !== null) {
174
-			$storage->expects($this->once())
175
-				->method('writeStream')
176
-				->willThrowException($thrownException);
177
-		} else {
178
-			$storage->expects($this->once())
179
-				->method('writeStream')
180
-				->willReturn(0);
181
-		}
182
-
183
-		$view->expects($this->any())
184
-			->method('getRelativePath')
185
-			->willReturnArgument(0);
186
-
187
-		$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
188
-			'permissions' => Constants::PERMISSION_ALL,
189
-			'type' => FileInfo::TYPE_FOLDER,
190
-		], null);
191
-
192
-		$file = new File($view, $info);
193
-
194
-		// action
195
-		$caughtException = null;
196
-		try {
197
-			$file->put('test data');
198
-		} catch (\Exception $e) {
199
-			$caughtException = $e;
200
-		}
201
-
202
-		$this->assertInstanceOf($expectedException, $caughtException);
203
-		if ($checkPreviousClass) {
204
-			$this->assertInstanceOf(get_class($thrownException), $caughtException->getPrevious());
205
-		}
206
-
207
-		$this->assertEmpty($this->listPartFiles($view, ''), 'No stray part files');
208
-	}
209
-
210
-	/**
211
-	 * Simulate putting a file to the given path.
212
-	 *
213
-	 * @param string $path path to put the file into
214
-	 * @param ?string $viewRoot root to use for the view
215
-	 * @param null|Request $request the HTTP request
216
-	 *
217
-	 * @return null|string of the PUT operation which is usually the etag
218
-	 */
219
-	private function doPut(string $path, ?string $viewRoot = null, ?Request $request = null) {
220
-		$view = Filesystem::getView();
221
-		if (!is_null($viewRoot)) {
222
-			$view = new View($viewRoot);
223
-		} else {
224
-			$viewRoot = '/' . $this->user . '/files';
225
-		}
226
-
227
-		$info = new \OC\Files\FileInfo(
228
-			$viewRoot . '/' . ltrim($path, '/'),
229
-			$this->getMockStorage(),
230
-			null,
231
-			[
232
-				'permissions' => Constants::PERMISSION_ALL,
233
-				'type' => FileInfo::TYPE_FOLDER,
234
-			],
235
-			null
236
-		);
237
-
238
-		/** @var File&MockObject $file */
239
-		$file = $this->getMockBuilder(File::class)
240
-			->setConstructorArgs([$view, $info, null, $request])
241
-			->onlyMethods(['header'])
242
-			->getMock();
243
-
244
-		// beforeMethod locks
245
-		$view->lockFile($path, ILockingProvider::LOCK_SHARED);
246
-
247
-		$result = $file->put($this->getStream('test data'));
248
-
249
-		// afterMethod unlocks
250
-		$view->unlockFile($path, ILockingProvider::LOCK_SHARED);
251
-
252
-		return $result;
253
-	}
254
-
255
-	/**
256
-	 * Test putting a single file
257
-	 */
258
-	public function testPutSingleFile(): void {
259
-		$this->assertNotEmpty($this->doPut('/foo.txt'));
260
-	}
261
-
262
-	public static function legalMtimeProvider(): array {
263
-		return [
264
-			'string' => [
265
-				'requestMtime' => 'string',
266
-				'resultMtime' => null
267
-			],
268
-			'castable string (int)' => [
269
-				'requestMtime' => '987654321',
270
-				'resultMtime' => 987654321
271
-			],
272
-			'castable string (float)' => [
273
-				'requestMtime' => '123456789.56',
274
-				'resultMtime' => 123456789
275
-			],
276
-			'float' => [
277
-				'requestMtime' => 123456789.56,
278
-				'resultMtime' => 123456789
279
-			],
280
-			'zero' => [
281
-				'requestMtime' => 0,
282
-				'resultMtime' => null
283
-			],
284
-			'zero string' => [
285
-				'requestMtime' => '0',
286
-				'resultMtime' => null
287
-			],
288
-			'negative zero string' => [
289
-				'requestMtime' => '-0',
290
-				'resultMtime' => null
291
-			],
292
-			'string starting with number following by char' => [
293
-				'requestMtime' => '2345asdf',
294
-				'resultMtime' => null
295
-			],
296
-			'string castable hex int' => [
297
-				'requestMtime' => '0x45adf',
298
-				'resultMtime' => null
299
-			],
300
-			'string that looks like invalid hex int' => [
301
-				'requestMtime' => '0x123g',
302
-				'resultMtime' => null
303
-			],
304
-			'negative int' => [
305
-				'requestMtime' => -34,
306
-				'resultMtime' => null
307
-			],
308
-			'negative float' => [
309
-				'requestMtime' => -34.43,
310
-				'resultMtime' => null
311
-			],
312
-		];
313
-	}
314
-
315
-	/**
316
-	 * Test putting a file with string Mtime
317
-	 */
318
-	#[\PHPUnit\Framework\Attributes\DataProvider('legalMtimeProvider')]
319
-	public function testPutSingleFileLegalMtime(mixed $requestMtime, ?int $resultMtime): void {
320
-		$request = new Request([
321
-			'server' => [
322
-				'HTTP_X_OC_MTIME' => (string)$requestMtime,
323
-			]
324
-		], $this->requestId, $this->config, null);
325
-		$file = 'foo.txt';
326
-
327
-		if ($resultMtime === null) {
328
-			$this->expectException(\InvalidArgumentException::class);
329
-		}
330
-
331
-		$this->doPut($file, null, $request);
332
-
333
-		if ($resultMtime !== null) {
334
-			$this->assertEquals($resultMtime, $this->getFileInfos($file)['mtime']);
335
-		}
336
-	}
337
-
338
-	/**
339
-	 * Test that putting a file triggers create hooks
340
-	 */
341
-	public function testPutSingleFileTriggersHooks(): void {
342
-		HookHelper::setUpHooks();
343
-
344
-		$this->assertNotEmpty($this->doPut('/foo.txt'));
345
-
346
-		$this->assertCount(4, HookHelper::$hookCalls);
347
-		$this->assertHookCall(
348
-			HookHelper::$hookCalls[0],
349
-			Filesystem::signal_create,
350
-			'/foo.txt'
351
-		);
352
-		$this->assertHookCall(
353
-			HookHelper::$hookCalls[1],
354
-			Filesystem::signal_write,
355
-			'/foo.txt'
356
-		);
357
-		$this->assertHookCall(
358
-			HookHelper::$hookCalls[2],
359
-			Filesystem::signal_post_create,
360
-			'/foo.txt'
361
-		);
362
-		$this->assertHookCall(
363
-			HookHelper::$hookCalls[3],
364
-			Filesystem::signal_post_write,
365
-			'/foo.txt'
366
-		);
367
-	}
368
-
369
-	/**
370
-	 * Test that putting a file triggers update hooks
371
-	 */
372
-	public function testPutOverwriteFileTriggersHooks(): void {
373
-		$view = Filesystem::getView();
374
-		$view->file_put_contents('/foo.txt', 'some content that will be replaced');
375
-
376
-		HookHelper::setUpHooks();
377
-
378
-		$this->assertNotEmpty($this->doPut('/foo.txt'));
379
-
380
-		$this->assertCount(4, HookHelper::$hookCalls);
381
-		$this->assertHookCall(
382
-			HookHelper::$hookCalls[0],
383
-			Filesystem::signal_update,
384
-			'/foo.txt'
385
-		);
386
-		$this->assertHookCall(
387
-			HookHelper::$hookCalls[1],
388
-			Filesystem::signal_write,
389
-			'/foo.txt'
390
-		);
391
-		$this->assertHookCall(
392
-			HookHelper::$hookCalls[2],
393
-			Filesystem::signal_post_update,
394
-			'/foo.txt'
395
-		);
396
-		$this->assertHookCall(
397
-			HookHelper::$hookCalls[3],
398
-			Filesystem::signal_post_write,
399
-			'/foo.txt'
400
-		);
401
-	}
402
-
403
-	/**
404
-	 * Test that putting a file triggers hooks with the correct path
405
-	 * if the passed view was chrooted (can happen with public webdav
406
-	 * where the root is the share root)
407
-	 */
408
-	public function testPutSingleFileTriggersHooksDifferentRoot(): void {
409
-		$view = Filesystem::getView();
410
-		$view->mkdir('noderoot');
411
-
412
-		HookHelper::setUpHooks();
413
-
414
-		// happens with public webdav where the view root is the share root
415
-		$this->assertNotEmpty($this->doPut('/foo.txt', '/' . $this->user . '/files/noderoot'));
416
-
417
-		$this->assertCount(4, HookHelper::$hookCalls);
418
-		$this->assertHookCall(
419
-			HookHelper::$hookCalls[0],
420
-			Filesystem::signal_create,
421
-			'/noderoot/foo.txt'
422
-		);
423
-		$this->assertHookCall(
424
-			HookHelper::$hookCalls[1],
425
-			Filesystem::signal_write,
426
-			'/noderoot/foo.txt'
427
-		);
428
-		$this->assertHookCall(
429
-			HookHelper::$hookCalls[2],
430
-			Filesystem::signal_post_create,
431
-			'/noderoot/foo.txt'
432
-		);
433
-		$this->assertHookCall(
434
-			HookHelper::$hookCalls[3],
435
-			Filesystem::signal_post_write,
436
-			'/noderoot/foo.txt'
437
-		);
438
-	}
439
-
440
-	public static function cancellingHook($params): void {
441
-		self::$hookCalls[] = [
442
-			'signal' => Filesystem::signal_post_create,
443
-			'params' => $params
444
-		];
445
-	}
446
-
447
-	/**
448
-	 * Test put file with cancelled hook
449
-	 */
450
-	public function testPutSingleFileCancelPreHook(): void {
451
-		Util::connectHook(
452
-			Filesystem::CLASSNAME,
453
-			Filesystem::signal_create,
454
-			'\Test\HookHelper',
455
-			'cancellingCallback'
456
-		);
457
-
458
-		// action
459
-		$thrown = false;
460
-		try {
461
-			$this->doPut('/foo.txt');
462
-		} catch (\Sabre\DAV\Exception $e) {
463
-			$thrown = true;
464
-		}
465
-
466
-		$this->assertTrue($thrown);
467
-		$this->assertEmpty($this->listPartFiles(), 'No stray part files');
468
-	}
469
-
470
-	/**
471
-	 * Test exception when the uploaded size did not match
472
-	 */
473
-	public function testSimplePutFailsSizeCheck(): void {
474
-		// setup
475
-		/** @var View&MockObject */
476
-		$view = $this->getMockBuilder(View::class)
477
-			->onlyMethods(['rename', 'getRelativePath', 'filesize'])
478
-			->getMock();
479
-		$view->expects($this->any())
480
-			->method('rename')
481
-			->withAnyParameters()
482
-			->willReturn(false);
483
-		$view->expects($this->any())
484
-			->method('getRelativePath')
485
-			->willReturnArgument(0);
486
-
487
-		$view->expects($this->any())
488
-			->method('filesize')
489
-			->willReturn(123456);
490
-
491
-		$request = new Request([
492
-			'server' => [
493
-				'CONTENT_LENGTH' => '123456',
494
-			],
495
-			'method' => 'PUT',
496
-		], $this->requestId, $this->config, null);
497
-
498
-		$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
499
-			'permissions' => Constants::PERMISSION_ALL,
500
-			'type' => FileInfo::TYPE_FOLDER,
501
-		], null);
502
-
503
-		$file = new File($view, $info, null, $request);
504
-
505
-		// action
506
-		$thrown = false;
507
-		try {
508
-			// beforeMethod locks
509
-			$file->acquireLock(ILockingProvider::LOCK_SHARED);
510
-
511
-			$file->put($this->getStream('test data'));
512
-
513
-			// afterMethod unlocks
514
-			$file->releaseLock(ILockingProvider::LOCK_SHARED);
515
-		} catch (\Sabre\DAV\Exception\BadRequest $e) {
516
-			$thrown = true;
517
-		}
518
-
519
-		$this->assertTrue($thrown);
520
-		$this->assertEmpty($this->listPartFiles($view, ''), 'No stray part files');
521
-	}
522
-
523
-	/**
524
-	 * Test exception during final rename in simple upload mode
525
-	 */
526
-	public function testSimplePutFailsMoveFromStorage(): void {
527
-		$view = new View('/' . $this->user . '/files');
528
-
529
-		// simulate situation where the target file is locked
530
-		$view->lockFile('/test.txt', ILockingProvider::LOCK_EXCLUSIVE);
531
-
532
-		$info = new \OC\Files\FileInfo('/' . $this->user . '/files/test.txt', $this->getMockStorage(), null, [
533
-			'permissions' => Constants::PERMISSION_ALL,
534
-			'type' => FileInfo::TYPE_FOLDER,
535
-		], null);
536
-
537
-		$file = new File($view, $info);
538
-
539
-		// action
540
-		$thrown = false;
541
-		try {
542
-			// beforeMethod locks
543
-			$view->lockFile($info->getPath(), ILockingProvider::LOCK_SHARED);
544
-
545
-			$file->put($this->getStream('test data'));
546
-
547
-			// afterMethod unlocks
548
-			$view->unlockFile($info->getPath(), ILockingProvider::LOCK_SHARED);
549
-		} catch (FileLocked $e) {
550
-			$thrown = true;
551
-		}
552
-
553
-		$this->assertTrue($thrown);
554
-		$this->assertEmpty($this->listPartFiles($view, ''), 'No stray part files');
555
-	}
556
-
557
-	/**
558
-	 * Test put file with invalid chars
559
-	 */
560
-	public function testSimplePutInvalidChars(): void {
561
-		// setup
562
-		/** @var View&MockObject */
563
-		$view = $this->getMockBuilder(View::class)
564
-			->onlyMethods(['getRelativePath'])
565
-			->getMock();
566
-		$view->expects($this->any())
567
-			->method('getRelativePath')
568
-			->willReturnArgument(0);
569
-
570
-		$info = new \OC\Files\FileInfo("/i\nvalid", $this->getMockStorage(), null, [
571
-			'permissions' => Constants::PERMISSION_ALL,
572
-			'type' => FileInfo::TYPE_FOLDER,
573
-		], null);
574
-		$file = new File($view, $info);
575
-
576
-		// action
577
-		$thrown = false;
578
-		try {
579
-			// beforeMethod locks
580
-			$view->lockFile($info->getPath(), ILockingProvider::LOCK_SHARED);
581
-
582
-			$file->put($this->getStream('test data'));
583
-
584
-			// afterMethod unlocks
585
-			$view->unlockFile($info->getPath(), ILockingProvider::LOCK_SHARED);
586
-		} catch (InvalidPath $e) {
587
-			$thrown = true;
588
-		}
589
-
590
-		$this->assertTrue($thrown);
591
-		$this->assertEmpty($this->listPartFiles($view, ''), 'No stray part files');
592
-	}
593
-
594
-	/**
595
-	 * Test setting name with setName() with invalid chars
596
-	 *
597
-	 */
598
-	public function testSetNameInvalidChars(): void {
599
-		$this->expectException(InvalidPath::class);
600
-
601
-		// setup
602
-		/** @var View&MockObject */
603
-		$view = $this->getMockBuilder(View::class)
604
-			->onlyMethods(['getRelativePath'])
605
-			->getMock();
606
-
607
-		$view->expects($this->any())
608
-			->method('getRelativePath')
609
-			->willReturnArgument(0);
610
-
611
-		$info = new \OC\Files\FileInfo('/valid', $this->getMockStorage(), null, [
612
-			'permissions' => Constants::PERMISSION_ALL,
613
-			'type' => FileInfo::TYPE_FOLDER,
614
-		], null);
615
-		$file = new File($view, $info);
616
-
617
-		$file->setName("/i\nvalid");
618
-	}
619
-
620
-
621
-	public function testUploadAbort(): void {
622
-		// setup
623
-		/** @var View&MockObject */
624
-		$view = $this->getMockBuilder(View::class)
625
-			->onlyMethods(['rename', 'getRelativePath', 'filesize'])
626
-			->getMock();
627
-		$view->expects($this->any())
628
-			->method('rename')
629
-			->withAnyParameters()
630
-			->willReturn(false);
631
-		$view->expects($this->any())
632
-			->method('getRelativePath')
633
-			->willReturnArgument(0);
634
-		$view->expects($this->any())
635
-			->method('filesize')
636
-			->willReturn(123456);
637
-
638
-		$request = new Request([
639
-			'server' => [
640
-				'CONTENT_LENGTH' => '123456',
641
-			],
642
-			'method' => 'PUT',
643
-		], $this->requestId, $this->config, null);
644
-
645
-		$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
646
-			'permissions' => Constants::PERMISSION_ALL,
647
-			'type' => FileInfo::TYPE_FOLDER,
648
-		], null);
649
-
650
-		$file = new File($view, $info, null, $request);
651
-
652
-		// action
653
-		$thrown = false;
654
-		try {
655
-			// beforeMethod locks
656
-			$view->lockFile($info->getPath(), ILockingProvider::LOCK_SHARED);
657
-
658
-			$file->put($this->getStream('test data'));
659
-
660
-			// afterMethod unlocks
661
-			$view->unlockFile($info->getPath(), ILockingProvider::LOCK_SHARED);
662
-		} catch (\Sabre\DAV\Exception\BadRequest $e) {
663
-			$thrown = true;
664
-		}
665
-
666
-		$this->assertTrue($thrown);
667
-		$this->assertEmpty($this->listPartFiles($view, ''), 'No stray part files');
668
-	}
669
-
670
-
671
-	public function testDeleteWhenAllowed(): void {
672
-		// setup
673
-		/** @var View&MockObject */
674
-		$view = $this->getMockBuilder(View::class)
675
-			->getMock();
676
-
677
-		$view->expects($this->once())
678
-			->method('unlink')
679
-			->willReturn(true);
680
-
681
-		$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
682
-			'permissions' => Constants::PERMISSION_ALL,
683
-			'type' => FileInfo::TYPE_FOLDER,
684
-		], null);
685
-
686
-		$file = new File($view, $info);
687
-
688
-		// action
689
-		$file->delete();
690
-	}
691
-
692
-
693
-	public function testDeleteThrowsWhenDeletionNotAllowed(): void {
694
-		$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
695
-
696
-		// setup
697
-		/** @var View&MockObject */
698
-		$view = $this->getMockBuilder(View::class)
699
-			->getMock();
700
-
701
-		$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
702
-			'permissions' => 0,
703
-			'type' => FileInfo::TYPE_FOLDER,
704
-		], null);
705
-
706
-		$file = new File($view, $info);
707
-
708
-		// action
709
-		$file->delete();
710
-	}
711
-
712
-
713
-	public function testDeleteThrowsWhenDeletionFailed(): void {
714
-		$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
715
-
716
-		// setup
717
-		/** @var View&MockObject */
718
-		$view = $this->getMockBuilder(View::class)
719
-			->getMock();
720
-
721
-		// but fails
722
-		$view->expects($this->once())
723
-			->method('unlink')
724
-			->willReturn(false);
725
-
726
-		$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
727
-			'permissions' => Constants::PERMISSION_ALL,
728
-			'type' => FileInfo::TYPE_FOLDER,
729
-		], null);
730
-
731
-		$file = new File($view, $info);
732
-
733
-		// action
734
-		$file->delete();
735
-	}
736
-
737
-
738
-	public function testDeleteThrowsWhenDeletionThrows(): void {
739
-		$this->expectException(Forbidden::class);
740
-
741
-		// setup
742
-		/** @var View&MockObject */
743
-		$view = $this->getMockBuilder(View::class)
744
-			->getMock();
745
-
746
-		// but fails
747
-		$view->expects($this->once())
748
-			->method('unlink')
749
-			->willThrowException(new ForbiddenException('', true));
750
-
751
-		$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
752
-			'permissions' => Constants::PERMISSION_ALL,
753
-			'type' => FileInfo::TYPE_FOLDER,
754
-		], null);
755
-
756
-		$file = new File($view, $info);
757
-
758
-		// action
759
-		$file->delete();
760
-	}
761
-
762
-	/**
763
-	 * Asserts hook call
764
-	 *
765
-	 * @param array $callData hook call data to check
766
-	 * @param string $signal signal name
767
-	 * @param string $hookPath hook path
768
-	 */
769
-	protected function assertHookCall($callData, $signal, $hookPath) {
770
-		$this->assertEquals($signal, $callData['signal']);
771
-		$params = $callData['params'];
772
-		$this->assertEquals(
773
-			$hookPath,
774
-			$params[Filesystem::signal_param_path]
775
-		);
776
-	}
777
-
778
-	/**
779
-	 * Test whether locks are set before and after the operation
780
-	 */
781
-	public function testPutLocking(): void {
782
-		$view = new View('/' . $this->user . '/files/');
783
-
784
-		$path = 'test-locking.txt';
785
-		$info = new \OC\Files\FileInfo(
786
-			'/' . $this->user . '/files/' . $path,
787
-			$this->getMockStorage(),
788
-			null,
789
-			[
790
-				'permissions' => Constants::PERMISSION_ALL,
791
-				'type' => FileInfo::TYPE_FOLDER,
792
-			],
793
-			null
794
-		);
795
-
796
-		$file = new File($view, $info);
797
-
798
-		$this->assertFalse(
799
-			$this->isFileLocked($view, $path, ILockingProvider::LOCK_SHARED),
800
-			'File unlocked before put'
801
-		);
802
-		$this->assertFalse(
803
-			$this->isFileLocked($view, $path, ILockingProvider::LOCK_EXCLUSIVE),
804
-			'File unlocked before put'
805
-		);
806
-
807
-		$wasLockedPre = false;
808
-		$wasLockedPost = false;
809
-		$eventHandler = $this->getMockBuilder(\stdclass::class)
810
-			->addMethods(['writeCallback', 'postWriteCallback'])
811
-			->getMock();
812
-
813
-		// both pre and post hooks might need access to the file,
814
-		// so only shared lock is acceptable
815
-		$eventHandler->expects($this->once())
816
-			->method('writeCallback')
817
-			->willReturnCallback(
818
-				function () use ($view, $path, &$wasLockedPre): void {
819
-					$wasLockedPre = $this->isFileLocked($view, $path, ILockingProvider::LOCK_SHARED);
820
-					$wasLockedPre = $wasLockedPre && !$this->isFileLocked($view, $path, ILockingProvider::LOCK_EXCLUSIVE);
821
-				}
822
-			);
823
-		$eventHandler->expects($this->once())
824
-			->method('postWriteCallback')
825
-			->willReturnCallback(
826
-				function () use ($view, $path, &$wasLockedPost): void {
827
-					$wasLockedPost = $this->isFileLocked($view, $path, ILockingProvider::LOCK_SHARED);
828
-					$wasLockedPost = $wasLockedPost && !$this->isFileLocked($view, $path, ILockingProvider::LOCK_EXCLUSIVE);
829
-				}
830
-			);
831
-
832
-		Util::connectHook(
833
-			Filesystem::CLASSNAME,
834
-			Filesystem::signal_write,
835
-			$eventHandler,
836
-			'writeCallback'
837
-		);
838
-		Util::connectHook(
839
-			Filesystem::CLASSNAME,
840
-			Filesystem::signal_post_write,
841
-			$eventHandler,
842
-			'postWriteCallback'
843
-		);
844
-
845
-		// beforeMethod locks
846
-		$view->lockFile($path, ILockingProvider::LOCK_SHARED);
847
-
848
-		$this->assertNotEmpty($file->put($this->getStream('test data')));
849
-
850
-		// afterMethod unlocks
851
-		$view->unlockFile($path, ILockingProvider::LOCK_SHARED);
852
-
853
-		$this->assertTrue($wasLockedPre, 'File was locked during pre-hooks');
854
-		$this->assertTrue($wasLockedPost, 'File was locked during post-hooks');
855
-
856
-		$this->assertFalse(
857
-			$this->isFileLocked($view, $path, ILockingProvider::LOCK_SHARED),
858
-			'File unlocked after put'
859
-		);
860
-		$this->assertFalse(
861
-			$this->isFileLocked($view, $path, ILockingProvider::LOCK_EXCLUSIVE),
862
-			'File unlocked after put'
863
-		);
864
-	}
865
-
866
-	/**
867
-	 * Returns part files in the given path
868
-	 *
869
-	 * @param \OC\Files\View view which root is the current user's "files" folder
870
-	 * @param string $path path for which to list part files
871
-	 *
872
-	 * @return array list of part files
873
-	 */
874
-	private function listPartFiles(?View $userView = null, $path = '') {
875
-		if ($userView === null) {
876
-			$userView = Filesystem::getView();
877
-		}
878
-		$files = [];
879
-		[$storage, $internalPath] = $userView->resolvePath($path);
880
-		if ($storage instanceof Local) {
881
-			$realPath = $storage->getSourcePath($internalPath);
882
-			$dh = opendir($realPath);
883
-			while (($file = readdir($dh)) !== false) {
884
-				if (str_ends_with($file, '.part')) {
885
-					$files[] = $file;
886
-				}
887
-			}
888
-			closedir($dh);
889
-		}
890
-		return $files;
891
-	}
892
-
893
-	/**
894
-	 * returns an array of file information filesize, mtime, filetype,  mimetype
895
-	 *
896
-	 * @param string $path
897
-	 * @param View $userView
898
-	 * @return array
899
-	 */
900
-	private function getFileInfos($path = '', ?View $userView = null) {
901
-		if ($userView === null) {
902
-			$userView = Filesystem::getView();
903
-		}
904
-		return [
905
-			'filesize' => $userView->filesize($path),
906
-			'mtime' => $userView->filemtime($path),
907
-			'filetype' => $userView->filetype($path),
908
-			'mimetype' => $userView->getMimeType($path)
909
-		];
910
-	}
911
-
912
-
913
-	public function testGetFopenFails(): void {
914
-		$this->expectException(\Sabre\DAV\Exception\ServiceUnavailable::class);
915
-
916
-		/** @var View&MockObject */
917
-		$view = $this->getMockBuilder(View::class)
918
-			->onlyMethods(['fopen'])
919
-			->getMock();
920
-		$view->expects($this->atLeastOnce())
921
-			->method('fopen')
922
-			->willReturn(false);
923
-
924
-		$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
925
-			'permissions' => Constants::PERMISSION_ALL,
926
-			'type' => FileInfo::TYPE_FILE,
927
-		], null);
928
-
929
-		$file = new File($view, $info);
930
-
931
-		$file->get();
932
-	}
933
-
934
-
935
-	public function testGetFopenThrows(): void {
936
-		$this->expectException(Forbidden::class);
937
-
938
-		/** @var View&MockObject */
939
-		$view = $this->getMockBuilder(View::class)
940
-			->onlyMethods(['fopen'])
941
-			->getMock();
942
-		$view->expects($this->atLeastOnce())
943
-			->method('fopen')
944
-			->willThrowException(new ForbiddenException('', true));
945
-
946
-		$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
947
-			'permissions' => Constants::PERMISSION_ALL,
948
-			'type' => FileInfo::TYPE_FILE,
949
-		], null);
950
-
951
-		$file = new File($view, $info);
952
-
953
-		$file->get();
954
-	}
955
-
956
-
957
-	public function testGetThrowsIfNoPermission(): void {
958
-		$this->expectException(\Sabre\DAV\Exception\NotFound::class);
959
-
960
-		/** @var View&MockObject */
961
-		$view = $this->getMockBuilder(View::class)
962
-			->onlyMethods(['fopen'])
963
-			->getMock();
964
-		$view->expects($this->never())
965
-			->method('fopen');
966
-
967
-		$info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
968
-			'permissions' => Constants::PERMISSION_CREATE, // no read perm
969
-			'type' => FileInfo::TYPE_FOLDER,
970
-		], null);
971
-
972
-		$file = new  File($view, $info);
973
-
974
-		$file->get();
975
-	}
976
-
977
-	public function testSimplePutNoCreatePermissions(): void {
978
-		$this->logout();
979
-
980
-		$storage = new Temporary([]);
981
-		$storage->file_put_contents('file.txt', 'old content');
982
-		$noCreateStorage = new PermissionsMask([
983
-			'storage' => $storage,
984
-			'mask' => Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE
985
-		]);
986
-
987
-		$this->registerMount($this->user, $noCreateStorage, '/' . $this->user . '/files/root');
54
+    use MountProviderTrait;
55
+    use UserTrait;
56
+
57
+    private string $user;
58
+    protected IConfig&MockObject $config;
59
+    protected IRequestId&MockObject $requestId;
60
+
61
+    protected function setUp(): void {
62
+        parent::setUp();
63
+
64
+        \OC_Hook::clear();
65
+
66
+        $this->user = 'test_user';
67
+        $this->createUser($this->user, 'pass');
68
+
69
+        self::loginAsUser($this->user);
70
+
71
+        $this->config = $this->createMock(IConfig::class);
72
+        $this->requestId = $this->createMock(IRequestId::class);
73
+    }
74
+
75
+    protected function tearDown(): void {
76
+        $userManager = Server::get(IUserManager::class);
77
+        $userManager->get($this->user)->delete();
78
+
79
+        parent::tearDown();
80
+    }
81
+
82
+    private function getMockStorage(): MockObject&IStorage {
83
+        $storage = $this->createMock(IStorage::class);
84
+        $storage->method('getId')
85
+            ->willReturn('home::someuser');
86
+        return $storage;
87
+    }
88
+
89
+    private function getStream(string $string) {
90
+        $stream = fopen('php://temp', 'r+');
91
+        fwrite($stream, $string);
92
+        fseek($stream, 0);
93
+        return $stream;
94
+    }
95
+
96
+
97
+    public static function fopenFailuresProvider(): array {
98
+        return [
99
+            [
100
+                // return false
101
+                null,
102
+                '\Sabre\Dav\Exception',
103
+                false
104
+            ],
105
+            [
106
+                new NotPermittedException(),
107
+                'Sabre\DAV\Exception\Forbidden'
108
+            ],
109
+            [
110
+                new EntityTooLargeException(),
111
+                'OCA\DAV\Connector\Sabre\Exception\EntityTooLarge'
112
+            ],
113
+            [
114
+                new InvalidContentException(),
115
+                'OCA\DAV\Connector\Sabre\Exception\UnsupportedMediaType'
116
+            ],
117
+            [
118
+                new InvalidPathException(),
119
+                'Sabre\DAV\Exception\Forbidden'
120
+            ],
121
+            [
122
+                new ForbiddenException('', true),
123
+                'OCA\DAV\Connector\Sabre\Exception\Forbidden'
124
+            ],
125
+            [
126
+                new LockNotAcquiredException('/test.txt', 1),
127
+                'OCA\DAV\Connector\Sabre\Exception\FileLocked'
128
+            ],
129
+            [
130
+                new LockedException('/test.txt'),
131
+                'OCA\DAV\Connector\Sabre\Exception\FileLocked'
132
+            ],
133
+            [
134
+                new GenericEncryptionException(),
135
+                'Sabre\DAV\Exception\ServiceUnavailable'
136
+            ],
137
+            [
138
+                new StorageNotAvailableException(),
139
+                'Sabre\DAV\Exception\ServiceUnavailable'
140
+            ],
141
+            [
142
+                new \Sabre\DAV\Exception('Generic sabre exception'),
143
+                'Sabre\DAV\Exception',
144
+                false
145
+            ],
146
+            [
147
+                new \Exception('Generic exception'),
148
+                'Sabre\DAV\Exception'
149
+            ],
150
+        ];
151
+    }
152
+
153
+    #[\PHPUnit\Framework\Attributes\DataProvider('fopenFailuresProvider')]
154
+    public function testSimplePutFails(?\Throwable $thrownException, string $expectedException, bool $checkPreviousClass = true): void {
155
+        // setup
156
+        $storage = $this->getMockBuilder(Local::class)
157
+            ->onlyMethods(['writeStream'])
158
+            ->setConstructorArgs([['datadir' => Server::get(ITempManager::class)->getTemporaryFolder()]])
159
+            ->getMock();
160
+        Filesystem::mount($storage, [], $this->user . '/');
161
+        /** @var View&MockObject $view */
162
+        $view = $this->getMockBuilder(View::class)
163
+            ->onlyMethods(['getRelativePath', 'resolvePath'])
164
+            ->getMock();
165
+        $view->expects($this->atLeastOnce())
166
+            ->method('resolvePath')
167
+            ->willReturnCallback(
168
+                function ($path) use ($storage) {
169
+                    return [$storage, $path];
170
+                }
171
+            );
172
+
173
+        if ($thrownException !== null) {
174
+            $storage->expects($this->once())
175
+                ->method('writeStream')
176
+                ->willThrowException($thrownException);
177
+        } else {
178
+            $storage->expects($this->once())
179
+                ->method('writeStream')
180
+                ->willReturn(0);
181
+        }
182
+
183
+        $view->expects($this->any())
184
+            ->method('getRelativePath')
185
+            ->willReturnArgument(0);
186
+
187
+        $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
188
+            'permissions' => Constants::PERMISSION_ALL,
189
+            'type' => FileInfo::TYPE_FOLDER,
190
+        ], null);
191
+
192
+        $file = new File($view, $info);
193
+
194
+        // action
195
+        $caughtException = null;
196
+        try {
197
+            $file->put('test data');
198
+        } catch (\Exception $e) {
199
+            $caughtException = $e;
200
+        }
201
+
202
+        $this->assertInstanceOf($expectedException, $caughtException);
203
+        if ($checkPreviousClass) {
204
+            $this->assertInstanceOf(get_class($thrownException), $caughtException->getPrevious());
205
+        }
206
+
207
+        $this->assertEmpty($this->listPartFiles($view, ''), 'No stray part files');
208
+    }
209
+
210
+    /**
211
+     * Simulate putting a file to the given path.
212
+     *
213
+     * @param string $path path to put the file into
214
+     * @param ?string $viewRoot root to use for the view
215
+     * @param null|Request $request the HTTP request
216
+     *
217
+     * @return null|string of the PUT operation which is usually the etag
218
+     */
219
+    private function doPut(string $path, ?string $viewRoot = null, ?Request $request = null) {
220
+        $view = Filesystem::getView();
221
+        if (!is_null($viewRoot)) {
222
+            $view = new View($viewRoot);
223
+        } else {
224
+            $viewRoot = '/' . $this->user . '/files';
225
+        }
226
+
227
+        $info = new \OC\Files\FileInfo(
228
+            $viewRoot . '/' . ltrim($path, '/'),
229
+            $this->getMockStorage(),
230
+            null,
231
+            [
232
+                'permissions' => Constants::PERMISSION_ALL,
233
+                'type' => FileInfo::TYPE_FOLDER,
234
+            ],
235
+            null
236
+        );
237
+
238
+        /** @var File&MockObject $file */
239
+        $file = $this->getMockBuilder(File::class)
240
+            ->setConstructorArgs([$view, $info, null, $request])
241
+            ->onlyMethods(['header'])
242
+            ->getMock();
243
+
244
+        // beforeMethod locks
245
+        $view->lockFile($path, ILockingProvider::LOCK_SHARED);
246
+
247
+        $result = $file->put($this->getStream('test data'));
248
+
249
+        // afterMethod unlocks
250
+        $view->unlockFile($path, ILockingProvider::LOCK_SHARED);
251
+
252
+        return $result;
253
+    }
254
+
255
+    /**
256
+     * Test putting a single file
257
+     */
258
+    public function testPutSingleFile(): void {
259
+        $this->assertNotEmpty($this->doPut('/foo.txt'));
260
+    }
261
+
262
+    public static function legalMtimeProvider(): array {
263
+        return [
264
+            'string' => [
265
+                'requestMtime' => 'string',
266
+                'resultMtime' => null
267
+            ],
268
+            'castable string (int)' => [
269
+                'requestMtime' => '987654321',
270
+                'resultMtime' => 987654321
271
+            ],
272
+            'castable string (float)' => [
273
+                'requestMtime' => '123456789.56',
274
+                'resultMtime' => 123456789
275
+            ],
276
+            'float' => [
277
+                'requestMtime' => 123456789.56,
278
+                'resultMtime' => 123456789
279
+            ],
280
+            'zero' => [
281
+                'requestMtime' => 0,
282
+                'resultMtime' => null
283
+            ],
284
+            'zero string' => [
285
+                'requestMtime' => '0',
286
+                'resultMtime' => null
287
+            ],
288
+            'negative zero string' => [
289
+                'requestMtime' => '-0',
290
+                'resultMtime' => null
291
+            ],
292
+            'string starting with number following by char' => [
293
+                'requestMtime' => '2345asdf',
294
+                'resultMtime' => null
295
+            ],
296
+            'string castable hex int' => [
297
+                'requestMtime' => '0x45adf',
298
+                'resultMtime' => null
299
+            ],
300
+            'string that looks like invalid hex int' => [
301
+                'requestMtime' => '0x123g',
302
+                'resultMtime' => null
303
+            ],
304
+            'negative int' => [
305
+                'requestMtime' => -34,
306
+                'resultMtime' => null
307
+            ],
308
+            'negative float' => [
309
+                'requestMtime' => -34.43,
310
+                'resultMtime' => null
311
+            ],
312
+        ];
313
+    }
314
+
315
+    /**
316
+     * Test putting a file with string Mtime
317
+     */
318
+    #[\PHPUnit\Framework\Attributes\DataProvider('legalMtimeProvider')]
319
+    public function testPutSingleFileLegalMtime(mixed $requestMtime, ?int $resultMtime): void {
320
+        $request = new Request([
321
+            'server' => [
322
+                'HTTP_X_OC_MTIME' => (string)$requestMtime,
323
+            ]
324
+        ], $this->requestId, $this->config, null);
325
+        $file = 'foo.txt';
326
+
327
+        if ($resultMtime === null) {
328
+            $this->expectException(\InvalidArgumentException::class);
329
+        }
330
+
331
+        $this->doPut($file, null, $request);
332
+
333
+        if ($resultMtime !== null) {
334
+            $this->assertEquals($resultMtime, $this->getFileInfos($file)['mtime']);
335
+        }
336
+    }
337
+
338
+    /**
339
+     * Test that putting a file triggers create hooks
340
+     */
341
+    public function testPutSingleFileTriggersHooks(): void {
342
+        HookHelper::setUpHooks();
343
+
344
+        $this->assertNotEmpty($this->doPut('/foo.txt'));
345
+
346
+        $this->assertCount(4, HookHelper::$hookCalls);
347
+        $this->assertHookCall(
348
+            HookHelper::$hookCalls[0],
349
+            Filesystem::signal_create,
350
+            '/foo.txt'
351
+        );
352
+        $this->assertHookCall(
353
+            HookHelper::$hookCalls[1],
354
+            Filesystem::signal_write,
355
+            '/foo.txt'
356
+        );
357
+        $this->assertHookCall(
358
+            HookHelper::$hookCalls[2],
359
+            Filesystem::signal_post_create,
360
+            '/foo.txt'
361
+        );
362
+        $this->assertHookCall(
363
+            HookHelper::$hookCalls[3],
364
+            Filesystem::signal_post_write,
365
+            '/foo.txt'
366
+        );
367
+    }
368
+
369
+    /**
370
+     * Test that putting a file triggers update hooks
371
+     */
372
+    public function testPutOverwriteFileTriggersHooks(): void {
373
+        $view = Filesystem::getView();
374
+        $view->file_put_contents('/foo.txt', 'some content that will be replaced');
375
+
376
+        HookHelper::setUpHooks();
377
+
378
+        $this->assertNotEmpty($this->doPut('/foo.txt'));
379
+
380
+        $this->assertCount(4, HookHelper::$hookCalls);
381
+        $this->assertHookCall(
382
+            HookHelper::$hookCalls[0],
383
+            Filesystem::signal_update,
384
+            '/foo.txt'
385
+        );
386
+        $this->assertHookCall(
387
+            HookHelper::$hookCalls[1],
388
+            Filesystem::signal_write,
389
+            '/foo.txt'
390
+        );
391
+        $this->assertHookCall(
392
+            HookHelper::$hookCalls[2],
393
+            Filesystem::signal_post_update,
394
+            '/foo.txt'
395
+        );
396
+        $this->assertHookCall(
397
+            HookHelper::$hookCalls[3],
398
+            Filesystem::signal_post_write,
399
+            '/foo.txt'
400
+        );
401
+    }
402
+
403
+    /**
404
+     * Test that putting a file triggers hooks with the correct path
405
+     * if the passed view was chrooted (can happen with public webdav
406
+     * where the root is the share root)
407
+     */
408
+    public function testPutSingleFileTriggersHooksDifferentRoot(): void {
409
+        $view = Filesystem::getView();
410
+        $view->mkdir('noderoot');
411
+
412
+        HookHelper::setUpHooks();
413
+
414
+        // happens with public webdav where the view root is the share root
415
+        $this->assertNotEmpty($this->doPut('/foo.txt', '/' . $this->user . '/files/noderoot'));
416
+
417
+        $this->assertCount(4, HookHelper::$hookCalls);
418
+        $this->assertHookCall(
419
+            HookHelper::$hookCalls[0],
420
+            Filesystem::signal_create,
421
+            '/noderoot/foo.txt'
422
+        );
423
+        $this->assertHookCall(
424
+            HookHelper::$hookCalls[1],
425
+            Filesystem::signal_write,
426
+            '/noderoot/foo.txt'
427
+        );
428
+        $this->assertHookCall(
429
+            HookHelper::$hookCalls[2],
430
+            Filesystem::signal_post_create,
431
+            '/noderoot/foo.txt'
432
+        );
433
+        $this->assertHookCall(
434
+            HookHelper::$hookCalls[3],
435
+            Filesystem::signal_post_write,
436
+            '/noderoot/foo.txt'
437
+        );
438
+    }
439
+
440
+    public static function cancellingHook($params): void {
441
+        self::$hookCalls[] = [
442
+            'signal' => Filesystem::signal_post_create,
443
+            'params' => $params
444
+        ];
445
+    }
446
+
447
+    /**
448
+     * Test put file with cancelled hook
449
+     */
450
+    public function testPutSingleFileCancelPreHook(): void {
451
+        Util::connectHook(
452
+            Filesystem::CLASSNAME,
453
+            Filesystem::signal_create,
454
+            '\Test\HookHelper',
455
+            'cancellingCallback'
456
+        );
457
+
458
+        // action
459
+        $thrown = false;
460
+        try {
461
+            $this->doPut('/foo.txt');
462
+        } catch (\Sabre\DAV\Exception $e) {
463
+            $thrown = true;
464
+        }
465
+
466
+        $this->assertTrue($thrown);
467
+        $this->assertEmpty($this->listPartFiles(), 'No stray part files');
468
+    }
469
+
470
+    /**
471
+     * Test exception when the uploaded size did not match
472
+     */
473
+    public function testSimplePutFailsSizeCheck(): void {
474
+        // setup
475
+        /** @var View&MockObject */
476
+        $view = $this->getMockBuilder(View::class)
477
+            ->onlyMethods(['rename', 'getRelativePath', 'filesize'])
478
+            ->getMock();
479
+        $view->expects($this->any())
480
+            ->method('rename')
481
+            ->withAnyParameters()
482
+            ->willReturn(false);
483
+        $view->expects($this->any())
484
+            ->method('getRelativePath')
485
+            ->willReturnArgument(0);
486
+
487
+        $view->expects($this->any())
488
+            ->method('filesize')
489
+            ->willReturn(123456);
490
+
491
+        $request = new Request([
492
+            'server' => [
493
+                'CONTENT_LENGTH' => '123456',
494
+            ],
495
+            'method' => 'PUT',
496
+        ], $this->requestId, $this->config, null);
497
+
498
+        $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
499
+            'permissions' => Constants::PERMISSION_ALL,
500
+            'type' => FileInfo::TYPE_FOLDER,
501
+        ], null);
502
+
503
+        $file = new File($view, $info, null, $request);
504
+
505
+        // action
506
+        $thrown = false;
507
+        try {
508
+            // beforeMethod locks
509
+            $file->acquireLock(ILockingProvider::LOCK_SHARED);
510
+
511
+            $file->put($this->getStream('test data'));
512
+
513
+            // afterMethod unlocks
514
+            $file->releaseLock(ILockingProvider::LOCK_SHARED);
515
+        } catch (\Sabre\DAV\Exception\BadRequest $e) {
516
+            $thrown = true;
517
+        }
518
+
519
+        $this->assertTrue($thrown);
520
+        $this->assertEmpty($this->listPartFiles($view, ''), 'No stray part files');
521
+    }
522
+
523
+    /**
524
+     * Test exception during final rename in simple upload mode
525
+     */
526
+    public function testSimplePutFailsMoveFromStorage(): void {
527
+        $view = new View('/' . $this->user . '/files');
528
+
529
+        // simulate situation where the target file is locked
530
+        $view->lockFile('/test.txt', ILockingProvider::LOCK_EXCLUSIVE);
531
+
532
+        $info = new \OC\Files\FileInfo('/' . $this->user . '/files/test.txt', $this->getMockStorage(), null, [
533
+            'permissions' => Constants::PERMISSION_ALL,
534
+            'type' => FileInfo::TYPE_FOLDER,
535
+        ], null);
536
+
537
+        $file = new File($view, $info);
538
+
539
+        // action
540
+        $thrown = false;
541
+        try {
542
+            // beforeMethod locks
543
+            $view->lockFile($info->getPath(), ILockingProvider::LOCK_SHARED);
544
+
545
+            $file->put($this->getStream('test data'));
546
+
547
+            // afterMethod unlocks
548
+            $view->unlockFile($info->getPath(), ILockingProvider::LOCK_SHARED);
549
+        } catch (FileLocked $e) {
550
+            $thrown = true;
551
+        }
552
+
553
+        $this->assertTrue($thrown);
554
+        $this->assertEmpty($this->listPartFiles($view, ''), 'No stray part files');
555
+    }
556
+
557
+    /**
558
+     * Test put file with invalid chars
559
+     */
560
+    public function testSimplePutInvalidChars(): void {
561
+        // setup
562
+        /** @var View&MockObject */
563
+        $view = $this->getMockBuilder(View::class)
564
+            ->onlyMethods(['getRelativePath'])
565
+            ->getMock();
566
+        $view->expects($this->any())
567
+            ->method('getRelativePath')
568
+            ->willReturnArgument(0);
569
+
570
+        $info = new \OC\Files\FileInfo("/i\nvalid", $this->getMockStorage(), null, [
571
+            'permissions' => Constants::PERMISSION_ALL,
572
+            'type' => FileInfo::TYPE_FOLDER,
573
+        ], null);
574
+        $file = new File($view, $info);
575
+
576
+        // action
577
+        $thrown = false;
578
+        try {
579
+            // beforeMethod locks
580
+            $view->lockFile($info->getPath(), ILockingProvider::LOCK_SHARED);
581
+
582
+            $file->put($this->getStream('test data'));
583
+
584
+            // afterMethod unlocks
585
+            $view->unlockFile($info->getPath(), ILockingProvider::LOCK_SHARED);
586
+        } catch (InvalidPath $e) {
587
+            $thrown = true;
588
+        }
589
+
590
+        $this->assertTrue($thrown);
591
+        $this->assertEmpty($this->listPartFiles($view, ''), 'No stray part files');
592
+    }
593
+
594
+    /**
595
+     * Test setting name with setName() with invalid chars
596
+     *
597
+     */
598
+    public function testSetNameInvalidChars(): void {
599
+        $this->expectException(InvalidPath::class);
600
+
601
+        // setup
602
+        /** @var View&MockObject */
603
+        $view = $this->getMockBuilder(View::class)
604
+            ->onlyMethods(['getRelativePath'])
605
+            ->getMock();
606
+
607
+        $view->expects($this->any())
608
+            ->method('getRelativePath')
609
+            ->willReturnArgument(0);
610
+
611
+        $info = new \OC\Files\FileInfo('/valid', $this->getMockStorage(), null, [
612
+            'permissions' => Constants::PERMISSION_ALL,
613
+            'type' => FileInfo::TYPE_FOLDER,
614
+        ], null);
615
+        $file = new File($view, $info);
616
+
617
+        $file->setName("/i\nvalid");
618
+    }
619
+
620
+
621
+    public function testUploadAbort(): void {
622
+        // setup
623
+        /** @var View&MockObject */
624
+        $view = $this->getMockBuilder(View::class)
625
+            ->onlyMethods(['rename', 'getRelativePath', 'filesize'])
626
+            ->getMock();
627
+        $view->expects($this->any())
628
+            ->method('rename')
629
+            ->withAnyParameters()
630
+            ->willReturn(false);
631
+        $view->expects($this->any())
632
+            ->method('getRelativePath')
633
+            ->willReturnArgument(0);
634
+        $view->expects($this->any())
635
+            ->method('filesize')
636
+            ->willReturn(123456);
637
+
638
+        $request = new Request([
639
+            'server' => [
640
+                'CONTENT_LENGTH' => '123456',
641
+            ],
642
+            'method' => 'PUT',
643
+        ], $this->requestId, $this->config, null);
644
+
645
+        $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
646
+            'permissions' => Constants::PERMISSION_ALL,
647
+            'type' => FileInfo::TYPE_FOLDER,
648
+        ], null);
649
+
650
+        $file = new File($view, $info, null, $request);
651
+
652
+        // action
653
+        $thrown = false;
654
+        try {
655
+            // beforeMethod locks
656
+            $view->lockFile($info->getPath(), ILockingProvider::LOCK_SHARED);
657
+
658
+            $file->put($this->getStream('test data'));
659
+
660
+            // afterMethod unlocks
661
+            $view->unlockFile($info->getPath(), ILockingProvider::LOCK_SHARED);
662
+        } catch (\Sabre\DAV\Exception\BadRequest $e) {
663
+            $thrown = true;
664
+        }
665
+
666
+        $this->assertTrue($thrown);
667
+        $this->assertEmpty($this->listPartFiles($view, ''), 'No stray part files');
668
+    }
669
+
670
+
671
+    public function testDeleteWhenAllowed(): void {
672
+        // setup
673
+        /** @var View&MockObject */
674
+        $view = $this->getMockBuilder(View::class)
675
+            ->getMock();
676
+
677
+        $view->expects($this->once())
678
+            ->method('unlink')
679
+            ->willReturn(true);
680
+
681
+        $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
682
+            'permissions' => Constants::PERMISSION_ALL,
683
+            'type' => FileInfo::TYPE_FOLDER,
684
+        ], null);
685
+
686
+        $file = new File($view, $info);
687
+
688
+        // action
689
+        $file->delete();
690
+    }
691
+
692
+
693
+    public function testDeleteThrowsWhenDeletionNotAllowed(): void {
694
+        $this->expectException(\Sabre\DAV\Exception\Forbidden::class);
695
+
696
+        // setup
697
+        /** @var View&MockObject */
698
+        $view = $this->getMockBuilder(View::class)
699
+            ->getMock();
700
+
701
+        $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
702
+            'permissions' => 0,
703
+            'type' => FileInfo::TYPE_FOLDER,
704
+        ], null);
705
+
706
+        $file = new File($view, $info);
707
+
708
+        // action
709
+        $file->delete();
710
+    }
711
+
712
+
713
+    public function testDeleteThrowsWhenDeletionFailed(): void {
714
+        $this->expectException(\Sabre\DAV\Exception\Forbidden::class);
715
+
716
+        // setup
717
+        /** @var View&MockObject */
718
+        $view = $this->getMockBuilder(View::class)
719
+            ->getMock();
720
+
721
+        // but fails
722
+        $view->expects($this->once())
723
+            ->method('unlink')
724
+            ->willReturn(false);
725
+
726
+        $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
727
+            'permissions' => Constants::PERMISSION_ALL,
728
+            'type' => FileInfo::TYPE_FOLDER,
729
+        ], null);
730
+
731
+        $file = new File($view, $info);
732
+
733
+        // action
734
+        $file->delete();
735
+    }
736
+
737
+
738
+    public function testDeleteThrowsWhenDeletionThrows(): void {
739
+        $this->expectException(Forbidden::class);
740
+
741
+        // setup
742
+        /** @var View&MockObject */
743
+        $view = $this->getMockBuilder(View::class)
744
+            ->getMock();
745
+
746
+        // but fails
747
+        $view->expects($this->once())
748
+            ->method('unlink')
749
+            ->willThrowException(new ForbiddenException('', true));
750
+
751
+        $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
752
+            'permissions' => Constants::PERMISSION_ALL,
753
+            'type' => FileInfo::TYPE_FOLDER,
754
+        ], null);
755
+
756
+        $file = new File($view, $info);
757
+
758
+        // action
759
+        $file->delete();
760
+    }
761
+
762
+    /**
763
+     * Asserts hook call
764
+     *
765
+     * @param array $callData hook call data to check
766
+     * @param string $signal signal name
767
+     * @param string $hookPath hook path
768
+     */
769
+    protected function assertHookCall($callData, $signal, $hookPath) {
770
+        $this->assertEquals($signal, $callData['signal']);
771
+        $params = $callData['params'];
772
+        $this->assertEquals(
773
+            $hookPath,
774
+            $params[Filesystem::signal_param_path]
775
+        );
776
+    }
777
+
778
+    /**
779
+     * Test whether locks are set before and after the operation
780
+     */
781
+    public function testPutLocking(): void {
782
+        $view = new View('/' . $this->user . '/files/');
783
+
784
+        $path = 'test-locking.txt';
785
+        $info = new \OC\Files\FileInfo(
786
+            '/' . $this->user . '/files/' . $path,
787
+            $this->getMockStorage(),
788
+            null,
789
+            [
790
+                'permissions' => Constants::PERMISSION_ALL,
791
+                'type' => FileInfo::TYPE_FOLDER,
792
+            ],
793
+            null
794
+        );
795
+
796
+        $file = new File($view, $info);
797
+
798
+        $this->assertFalse(
799
+            $this->isFileLocked($view, $path, ILockingProvider::LOCK_SHARED),
800
+            'File unlocked before put'
801
+        );
802
+        $this->assertFalse(
803
+            $this->isFileLocked($view, $path, ILockingProvider::LOCK_EXCLUSIVE),
804
+            'File unlocked before put'
805
+        );
806
+
807
+        $wasLockedPre = false;
808
+        $wasLockedPost = false;
809
+        $eventHandler = $this->getMockBuilder(\stdclass::class)
810
+            ->addMethods(['writeCallback', 'postWriteCallback'])
811
+            ->getMock();
812
+
813
+        // both pre and post hooks might need access to the file,
814
+        // so only shared lock is acceptable
815
+        $eventHandler->expects($this->once())
816
+            ->method('writeCallback')
817
+            ->willReturnCallback(
818
+                function () use ($view, $path, &$wasLockedPre): void {
819
+                    $wasLockedPre = $this->isFileLocked($view, $path, ILockingProvider::LOCK_SHARED);
820
+                    $wasLockedPre = $wasLockedPre && !$this->isFileLocked($view, $path, ILockingProvider::LOCK_EXCLUSIVE);
821
+                }
822
+            );
823
+        $eventHandler->expects($this->once())
824
+            ->method('postWriteCallback')
825
+            ->willReturnCallback(
826
+                function () use ($view, $path, &$wasLockedPost): void {
827
+                    $wasLockedPost = $this->isFileLocked($view, $path, ILockingProvider::LOCK_SHARED);
828
+                    $wasLockedPost = $wasLockedPost && !$this->isFileLocked($view, $path, ILockingProvider::LOCK_EXCLUSIVE);
829
+                }
830
+            );
831
+
832
+        Util::connectHook(
833
+            Filesystem::CLASSNAME,
834
+            Filesystem::signal_write,
835
+            $eventHandler,
836
+            'writeCallback'
837
+        );
838
+        Util::connectHook(
839
+            Filesystem::CLASSNAME,
840
+            Filesystem::signal_post_write,
841
+            $eventHandler,
842
+            'postWriteCallback'
843
+        );
844
+
845
+        // beforeMethod locks
846
+        $view->lockFile($path, ILockingProvider::LOCK_SHARED);
847
+
848
+        $this->assertNotEmpty($file->put($this->getStream('test data')));
849
+
850
+        // afterMethod unlocks
851
+        $view->unlockFile($path, ILockingProvider::LOCK_SHARED);
852
+
853
+        $this->assertTrue($wasLockedPre, 'File was locked during pre-hooks');
854
+        $this->assertTrue($wasLockedPost, 'File was locked during post-hooks');
855
+
856
+        $this->assertFalse(
857
+            $this->isFileLocked($view, $path, ILockingProvider::LOCK_SHARED),
858
+            'File unlocked after put'
859
+        );
860
+        $this->assertFalse(
861
+            $this->isFileLocked($view, $path, ILockingProvider::LOCK_EXCLUSIVE),
862
+            'File unlocked after put'
863
+        );
864
+    }
865
+
866
+    /**
867
+     * Returns part files in the given path
868
+     *
869
+     * @param \OC\Files\View view which root is the current user's "files" folder
870
+     * @param string $path path for which to list part files
871
+     *
872
+     * @return array list of part files
873
+     */
874
+    private function listPartFiles(?View $userView = null, $path = '') {
875
+        if ($userView === null) {
876
+            $userView = Filesystem::getView();
877
+        }
878
+        $files = [];
879
+        [$storage, $internalPath] = $userView->resolvePath($path);
880
+        if ($storage instanceof Local) {
881
+            $realPath = $storage->getSourcePath($internalPath);
882
+            $dh = opendir($realPath);
883
+            while (($file = readdir($dh)) !== false) {
884
+                if (str_ends_with($file, '.part')) {
885
+                    $files[] = $file;
886
+                }
887
+            }
888
+            closedir($dh);
889
+        }
890
+        return $files;
891
+    }
892
+
893
+    /**
894
+     * returns an array of file information filesize, mtime, filetype,  mimetype
895
+     *
896
+     * @param string $path
897
+     * @param View $userView
898
+     * @return array
899
+     */
900
+    private function getFileInfos($path = '', ?View $userView = null) {
901
+        if ($userView === null) {
902
+            $userView = Filesystem::getView();
903
+        }
904
+        return [
905
+            'filesize' => $userView->filesize($path),
906
+            'mtime' => $userView->filemtime($path),
907
+            'filetype' => $userView->filetype($path),
908
+            'mimetype' => $userView->getMimeType($path)
909
+        ];
910
+    }
911
+
912
+
913
+    public function testGetFopenFails(): void {
914
+        $this->expectException(\Sabre\DAV\Exception\ServiceUnavailable::class);
915
+
916
+        /** @var View&MockObject */
917
+        $view = $this->getMockBuilder(View::class)
918
+            ->onlyMethods(['fopen'])
919
+            ->getMock();
920
+        $view->expects($this->atLeastOnce())
921
+            ->method('fopen')
922
+            ->willReturn(false);
923
+
924
+        $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
925
+            'permissions' => Constants::PERMISSION_ALL,
926
+            'type' => FileInfo::TYPE_FILE,
927
+        ], null);
928
+
929
+        $file = new File($view, $info);
930
+
931
+        $file->get();
932
+    }
933
+
934
+
935
+    public function testGetFopenThrows(): void {
936
+        $this->expectException(Forbidden::class);
937
+
938
+        /** @var View&MockObject */
939
+        $view = $this->getMockBuilder(View::class)
940
+            ->onlyMethods(['fopen'])
941
+            ->getMock();
942
+        $view->expects($this->atLeastOnce())
943
+            ->method('fopen')
944
+            ->willThrowException(new ForbiddenException('', true));
945
+
946
+        $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
947
+            'permissions' => Constants::PERMISSION_ALL,
948
+            'type' => FileInfo::TYPE_FILE,
949
+        ], null);
950
+
951
+        $file = new File($view, $info);
952
+
953
+        $file->get();
954
+    }
955
+
956
+
957
+    public function testGetThrowsIfNoPermission(): void {
958
+        $this->expectException(\Sabre\DAV\Exception\NotFound::class);
959
+
960
+        /** @var View&MockObject */
961
+        $view = $this->getMockBuilder(View::class)
962
+            ->onlyMethods(['fopen'])
963
+            ->getMock();
964
+        $view->expects($this->never())
965
+            ->method('fopen');
966
+
967
+        $info = new \OC\Files\FileInfo('/test.txt', $this->getMockStorage(), null, [
968
+            'permissions' => Constants::PERMISSION_CREATE, // no read perm
969
+            'type' => FileInfo::TYPE_FOLDER,
970
+        ], null);
971
+
972
+        $file = new  File($view, $info);
973
+
974
+        $file->get();
975
+    }
976
+
977
+    public function testSimplePutNoCreatePermissions(): void {
978
+        $this->logout();
979
+
980
+        $storage = new Temporary([]);
981
+        $storage->file_put_contents('file.txt', 'old content');
982
+        $noCreateStorage = new PermissionsMask([
983
+            'storage' => $storage,
984
+            'mask' => Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE
985
+        ]);
986
+
987
+        $this->registerMount($this->user, $noCreateStorage, '/' . $this->user . '/files/root');
988 988
 
989
-		$this->loginAsUser($this->user);
989
+        $this->loginAsUser($this->user);
990 990
 
991
-		$view = new View('/' . $this->user . '/files');
991
+        $view = new View('/' . $this->user . '/files');
992 992
 
993
-		$info = $view->getFileInfo('root/file.txt');
993
+        $info = $view->getFileInfo('root/file.txt');
994 994
 
995
-		$file = new File($view, $info);
995
+        $file = new File($view, $info);
996 996
 
997
-		// beforeMethod locks
998
-		$view->lockFile('root/file.txt', ILockingProvider::LOCK_SHARED);
997
+        // beforeMethod locks
998
+        $view->lockFile('root/file.txt', ILockingProvider::LOCK_SHARED);
999 999
 
1000
-		$file->put($this->getStream('new content'));
1000
+        $file->put($this->getStream('new content'));
1001 1001
 
1002
-		// afterMethod unlocks
1003
-		$view->unlockFile('root/file.txt', ILockingProvider::LOCK_SHARED);
1002
+        // afterMethod unlocks
1003
+        $view->unlockFile('root/file.txt', ILockingProvider::LOCK_SHARED);
1004 1004
 
1005
-		$this->assertEquals('new content', $view->file_get_contents('root/file.txt'));
1006
-	}
1005
+        $this->assertEquals('new content', $view->file_get_contents('root/file.txt'));
1006
+    }
1007 1007
 
1008
-	public function testPutLockExpired(): void {
1009
-		$view = new View('/' . $this->user . '/files/');
1008
+    public function testPutLockExpired(): void {
1009
+        $view = new View('/' . $this->user . '/files/');
1010 1010
 
1011
-		$path = 'test-locking.txt';
1012
-		$info = new \OC\Files\FileInfo(
1013
-			'/' . $this->user . '/files/' . $path,
1014
-			$this->getMockStorage(),
1015
-			null,
1016
-			[
1017
-				'permissions' => Constants::PERMISSION_ALL,
1018
-				'type' => FileInfo::TYPE_FOLDER,
1019
-			],
1020
-			null
1021
-		);
1011
+        $path = 'test-locking.txt';
1012
+        $info = new \OC\Files\FileInfo(
1013
+            '/' . $this->user . '/files/' . $path,
1014
+            $this->getMockStorage(),
1015
+            null,
1016
+            [
1017
+                'permissions' => Constants::PERMISSION_ALL,
1018
+                'type' => FileInfo::TYPE_FOLDER,
1019
+            ],
1020
+            null
1021
+        );
1022 1022
 
1023
-		$file = new File($view, $info);
1023
+        $file = new File($view, $info);
1024 1024
 
1025
-		// don't lock before the PUT to simulate an expired shared lock
1026
-		$this->assertNotEmpty($file->put($this->getStream('test data')));
1025
+        // don't lock before the PUT to simulate an expired shared lock
1026
+        $this->assertNotEmpty($file->put($this->getStream('test data')));
1027 1027
 
1028
-		// afterMethod unlocks
1029
-		$view->unlockFile($path, ILockingProvider::LOCK_SHARED);
1030
-	}
1028
+        // afterMethod unlocks
1029
+        $view->unlockFile($path, ILockingProvider::LOCK_SHARED);
1030
+    }
1031 1031
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php 1 patch
Indentation   +812 added lines, -812 removed lines patch added patch discarded remove patch
@@ -38,816 +38,816 @@
 block discarded – undo
38 38
 
39 39
 class FilesReportPluginTest extends \Test\TestCase {
40 40
 
41
-	private \Sabre\DAV\Server&MockObject $server;
42
-	private Tree&MockObject $tree;
43
-	private ISystemTagObjectMapper&MockObject $tagMapper;
44
-	private ISystemTagManager&MockObject $tagManager;
45
-	private ITags&MockObject $privateTags;
46
-	private ITagManager&MockObject $privateTagManager;
47
-	private IUserSession&MockObject $userSession;
48
-	private FilesReportPluginImplementation $plugin;
49
-	private View&MockObject $view;
50
-	private IGroupManager&MockObject $groupManager;
51
-	private Folder&MockObject $userFolder;
52
-	private IPreview&MockObject $previewManager;
53
-	private IAppManager&MockObject $appManager;
54
-
55
-	protected function setUp(): void {
56
-		parent::setUp();
57
-
58
-		$this->tree = $this->createMock(Tree::class);
59
-		$this->view = $this->createMock(View::class);
60
-
61
-		$this->server = $this->getMockBuilder(Server::class)
62
-			->setConstructorArgs([$this->tree])
63
-			->onlyMethods(['getRequestUri', 'getBaseUri'])
64
-			->getMock();
65
-
66
-		$this->server->expects($this->any())
67
-			->method('getBaseUri')
68
-			->willReturn('http://example.com/owncloud/remote.php/dav');
69
-
70
-		$this->groupManager = $this->createMock(IGroupManager::class);
71
-		$this->userFolder = $this->createMock(Folder::class);
72
-		$this->previewManager = $this->createMock(IPreview::class);
73
-		$this->appManager = $this->createMock(IAppManager::class);
74
-		$this->tagManager = $this->createMock(ISystemTagManager::class);
75
-		$this->tagMapper = $this->createMock(ISystemTagObjectMapper::class);
76
-		$this->userSession = $this->createMock(IUserSession::class);
77
-		$this->privateTags = $this->createMock(ITags::class);
78
-		$this->privateTagManager = $this->createMock(ITagManager::class);
79
-		$this->privateTagManager->expects($this->any())
80
-			->method('load')
81
-			->with('files')
82
-			->willReturn($this->privateTags);
83
-
84
-		$user = $this->createMock(IUser::class);
85
-		$user->expects($this->any())
86
-			->method('getUID')
87
-			->willReturn('testuser');
88
-		$this->userSession->expects($this->any())
89
-			->method('getUser')
90
-			->willReturn($user);
91
-
92
-		$this->plugin = new FilesReportPluginImplementation(
93
-			$this->tree,
94
-			$this->view,
95
-			$this->tagManager,
96
-			$this->tagMapper,
97
-			$this->privateTagManager,
98
-			$this->userSession,
99
-			$this->groupManager,
100
-			$this->userFolder,
101
-			$this->appManager
102
-		);
103
-	}
104
-
105
-	public function testOnReportInvalidNode(): void {
106
-		$path = 'totally/unrelated/13';
107
-
108
-		$this->tree->expects($this->any())
109
-			->method('getNodeForPath')
110
-			->with('/' . $path)
111
-			->willReturn($this->createMock(INode::class));
112
-
113
-		$this->server->expects($this->any())
114
-			->method('getRequestUri')
115
-			->willReturn($path);
116
-		$this->plugin->initialize($this->server);
117
-
118
-		$this->assertNull($this->plugin->onReport(FilesReportPluginImplementation::REPORT_NAME, [], '/' . $path));
119
-	}
120
-
121
-	public function testOnReportInvalidReportName(): void {
122
-		$path = 'test';
123
-
124
-		$this->tree->expects($this->any())
125
-			->method('getNodeForPath')
126
-			->with('/' . $path)
127
-			->willReturn(
128
-				$this->getMockBuilder(INode::class)
129
-					->disableOriginalConstructor()
130
-					->getMock()
131
-			);
132
-
133
-		$this->server->expects($this->any())
134
-			->method('getRequestUri')
135
-			->willReturn($path);
136
-		$this->plugin->initialize($this->server);
137
-
138
-		$this->assertNull($this->plugin->onReport('{whoever}whatever', [], '/' . $path));
139
-	}
140
-
141
-	public function testOnReport(): void {
142
-		$path = 'test';
143
-
144
-		$parameters = [
145
-			[
146
-				'name' => '{DAV:}prop',
147
-				'value' => [
148
-					['name' => '{DAV:}getcontentlength', 'value' => ''],
149
-					['name' => '{http://owncloud.org/ns}size', 'value' => ''],
150
-				],
151
-			],
152
-			[
153
-				'name' => '{http://owncloud.org/ns}filter-rules',
154
-				'value' => [
155
-					['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
156
-					['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
157
-				],
158
-			],
159
-		];
160
-
161
-		$this->groupManager->expects($this->any())
162
-			->method('isAdmin')
163
-			->willReturn(true);
164
-
165
-		$reportTargetNode = $this->createMock(Directory::class);
166
-		$reportTargetNode->expects($this->any())
167
-			->method('getPath')
168
-			->willReturn('');
169
-
170
-		$response = $this->createMock(ResponseInterface::class);
171
-
172
-		$response->expects($this->once())
173
-			->method('setHeader')
174
-			->with('Content-Type', 'application/xml; charset=utf-8');
175
-
176
-		$response->expects($this->once())
177
-			->method('setStatus')
178
-			->with(207);
179
-
180
-		$response->expects($this->once())
181
-			->method('setBody');
182
-
183
-		$this->tree->expects($this->any())
184
-			->method('getNodeForPath')
185
-			->with('/' . $path)
186
-			->willReturn($reportTargetNode);
187
-
188
-		$filesNode1 = $this->createMock(File::class);
189
-		$filesNode1->expects($this->any())
190
-			->method('getSize')
191
-			->willReturn(12);
192
-		$filesNode2 = $this->createMock(Folder::class);
193
-		$filesNode2->expects($this->any())
194
-			->method('getSize')
195
-			->willReturn(10);
196
-
197
-		$tag123 = $this->createMock(ISystemTag::class);
198
-		$tag123->expects($this->any())
199
-			->method('getName')
200
-			->willReturn('OneTwoThree');
201
-		$tag123->expects($this->any())
202
-			->method('isUserVisible')
203
-			->willReturn(true);
204
-		$tag456 = $this->createMock(ISystemTag::class);
205
-		$tag456->expects($this->any())
206
-			->method('getName')
207
-			->willReturn('FourFiveSix');
208
-		$tag456->expects($this->any())
209
-			->method('isUserVisible')
210
-			->willReturn(true);
211
-
212
-		$this->tagManager->expects($this->once())
213
-			->method('getTagsByIds')
214
-			->with(['123', '456'])
215
-			->willReturn([$tag123, $tag456]);
216
-
217
-		$this->userFolder->expects($this->exactly(2))
218
-			->method('searchBySystemTag')
219
-			->willReturnMap([
220
-				['OneTwoThree', 'testuser', 0, 0, [$filesNode1]],
221
-				['FourFiveSix', 'testuser', 0, 0, [$filesNode2]],
222
-			]);
223
-
224
-		$this->server->expects($this->any())
225
-			->method('getRequestUri')
226
-			->willReturn($path);
227
-		$this->server->httpResponse = $response;
228
-		$this->plugin->initialize($this->server);
229
-
230
-		$this->assertFalse($this->plugin->onReport(FilesReportPluginImplementation::REPORT_NAME, $parameters, '/' . $path));
231
-	}
232
-
233
-	public function testFindNodesByFileIdsRoot(): void {
234
-		$filesNode1 = $this->createMock(Folder::class);
235
-		$filesNode1->expects($this->once())
236
-			->method('getName')
237
-			->willReturn('first node');
238
-
239
-		$filesNode2 = $this->createMock(File::class);
240
-		$filesNode2->expects($this->once())
241
-			->method('getName')
242
-			->willReturn('second node');
243
-
244
-		$reportTargetNode = $this->createMock(Directory::class);
245
-		$reportTargetNode->expects($this->any())
246
-			->method('getPath')
247
-			->willReturn('/');
248
-
249
-		$this->userFolder->expects($this->exactly(2))
250
-			->method('getFirstNodeById')
251
-			->willReturnMap([
252
-				[111, $filesNode1],
253
-				[222, $filesNode2],
254
-			]);
255
-
256
-		/** @var Directory&MockObject $reportTargetNode */
257
-		$result = $this->plugin->findNodesByFileIds($reportTargetNode, ['111', '222']);
258
-
259
-		$this->assertCount(2, $result);
260
-		$this->assertInstanceOf(Directory::class, $result[0]);
261
-		$this->assertEquals('first node', $result[0]->getName());
262
-		$this->assertInstanceOf(\OCA\DAV\Connector\Sabre\File::class, $result[1]);
263
-		$this->assertEquals('second node', $result[1]->getName());
264
-	}
265
-
266
-	public function testFindNodesByFileIdsSubDir(): void {
267
-		$filesNode1 = $this->createMock(Folder::class);
268
-		$filesNode1->expects($this->once())
269
-			->method('getName')
270
-			->willReturn('first node');
271
-
272
-		$filesNode2 = $this->createMock(File::class);
273
-		$filesNode2->expects($this->once())
274
-			->method('getName')
275
-			->willReturn('second node');
276
-
277
-		$reportTargetNode = $this->createMock(Directory::class);
278
-		$reportTargetNode->expects($this->any())
279
-			->method('getPath')
280
-			->willReturn('/sub1/sub2');
281
-
282
-
283
-		$subNode = $this->createMock(Folder::class);
284
-
285
-		$this->userFolder->expects($this->once())
286
-			->method('get')
287
-			->with('/sub1/sub2')
288
-			->willReturn($subNode);
289
-
290
-		$subNode->expects($this->exactly(2))
291
-			->method('getFirstNodeById')
292
-			->willReturnMap([
293
-				[111, $filesNode1],
294
-				[222, $filesNode2],
295
-			]);
296
-
297
-		/** @var Directory&MockObject $reportTargetNode */
298
-		$result = $this->plugin->findNodesByFileIds($reportTargetNode, ['111', '222']);
299
-
300
-		$this->assertCount(2, $result);
301
-		$this->assertInstanceOf(Directory::class, $result[0]);
302
-		$this->assertEquals('first node', $result[0]->getName());
303
-		$this->assertInstanceOf(\OCA\DAV\Connector\Sabre\File::class, $result[1]);
304
-		$this->assertEquals('second node', $result[1]->getName());
305
-	}
306
-
307
-	public function testPrepareResponses(): void {
308
-		$requestedProps = ['{DAV:}getcontentlength', '{http://owncloud.org/ns}fileid', '{DAV:}resourcetype'];
309
-
310
-		$fileInfo = $this->createMock(FileInfo::class);
311
-		$fileInfo->method('isReadable')->willReturn(true);
312
-
313
-		$node1 = $this->createMock(Directory::class);
314
-		$node2 = $this->createMock(\OCA\DAV\Connector\Sabre\File::class);
315
-
316
-		$node1->expects($this->once())
317
-			->method('getInternalFileId')
318
-			->willReturn('111');
319
-		$node1->expects($this->any())
320
-			->method('getPath')
321
-			->willReturn('/node1');
322
-		$node1->method('getFileInfo')->willReturn($fileInfo);
323
-		$node2->expects($this->once())
324
-			->method('getInternalFileId')
325
-			->willReturn('222');
326
-		$node2->expects($this->once())
327
-			->method('getSize')
328
-			->willReturn(1024);
329
-		$node2->expects($this->any())
330
-			->method('getPath')
331
-			->willReturn('/sub/node2');
332
-		$node2->method('getFileInfo')->willReturn($fileInfo);
333
-
334
-		$config = $this->createMock(IConfig::class);
335
-		$validator = $this->createMock(IFilenameValidator::class);
336
-		$accountManager = $this->createMock(IAccountManager::class);
337
-
338
-		$this->server->addPlugin(
339
-			new FilesPlugin(
340
-				$this->tree,
341
-				$config,
342
-				$this->createMock(IRequest::class),
343
-				$this->previewManager,
344
-				$this->createMock(IUserSession::class),
345
-				$validator,
346
-				$accountManager,
347
-			)
348
-		);
349
-		$this->plugin->initialize($this->server);
350
-		$responses = $this->plugin->prepareResponses('/files/username', $requestedProps, [$node1, $node2]);
351
-
352
-		$this->assertCount(2, $responses);
353
-
354
-		$this->assertEquals('http://example.com/owncloud/remote.php/dav/files/username/node1', $responses[0]->getHref());
355
-		$this->assertEquals('http://example.com/owncloud/remote.php/dav/files/username/sub/node2', $responses[1]->getHref());
356
-
357
-		$props1 = $responses[0]->getResponseProperties();
358
-		$this->assertEquals('111', $props1[200]['{http://owncloud.org/ns}fileid']);
359
-		$this->assertNull($props1[404]['{DAV:}getcontentlength']);
360
-		$this->assertInstanceOf('\Sabre\DAV\Xml\Property\ResourceType', $props1[200]['{DAV:}resourcetype']);
361
-		$resourceType1 = $props1[200]['{DAV:}resourcetype']->getValue();
362
-		$this->assertEquals('{DAV:}collection', $resourceType1[0]);
363
-
364
-		$props2 = $responses[1]->getResponseProperties();
365
-		$this->assertEquals('1024', $props2[200]['{DAV:}getcontentlength']);
366
-		$this->assertEquals('222', $props2[200]['{http://owncloud.org/ns}fileid']);
367
-		$this->assertInstanceOf('\Sabre\DAV\Xml\Property\ResourceType', $props2[200]['{DAV:}resourcetype']);
368
-		$this->assertCount(0, $props2[200]['{DAV:}resourcetype']->getValue());
369
-	}
370
-
371
-	public function testProcessFilterRulesSingle(): void {
372
-		$this->groupManager->expects($this->any())
373
-			->method('isAdmin')
374
-			->willReturn(true);
375
-
376
-		$rules = [
377
-			['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
378
-		];
379
-
380
-		$filesNode1 = $this->createMock(File::class);
381
-		$filesNode1->expects($this->any())
382
-			->method('getSize')
383
-			->willReturn(12);
384
-		$filesNode2 = $this->createMock(Folder::class);
385
-		$filesNode2->expects($this->any())
386
-			->method('getSize')
387
-			->willReturn(10);
388
-
389
-		$tag123 = $this->createMock(ISystemTag::class);
390
-		$tag123->expects($this->any())
391
-			->method('getName')
392
-			->willReturn('OneTwoThree');
393
-		$tag123->expects($this->any())
394
-			->method('isUserVisible')
395
-			->willReturn(true);
396
-
397
-		$this->tagManager->expects($this->once())
398
-			->method('getTagsByIds')
399
-			->with(['123'])
400
-			->willReturn([$tag123]);
401
-
402
-		$this->userFolder->expects($this->once())
403
-			->method('searchBySystemTag')
404
-			->with('OneTwoThree')
405
-			->willReturn([$filesNode1, $filesNode2]);
406
-
407
-		$this->assertEquals([$filesNode1, $filesNode2], self::invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, 0, 0]));
408
-	}
409
-
410
-	public function testProcessFilterRulesAndCondition(): void {
411
-		$this->groupManager->expects($this->any())
412
-			->method('isAdmin')
413
-			->willReturn(true);
414
-
415
-		$filesNode1 = $this->createMock(File::class);
416
-		$filesNode1->expects($this->any())
417
-			->method('getSize')
418
-			->willReturn(12);
419
-		$filesNode1->expects($this->any())
420
-			->method('getId')
421
-			->willReturn(111);
422
-		$filesNode2 = $this->createMock(Folder::class);
423
-		$filesNode2->expects($this->any())
424
-			->method('getSize')
425
-			->willReturn(10);
426
-		$filesNode2->expects($this->any())
427
-			->method('getId')
428
-			->willReturn(222);
429
-		$filesNode3 = $this->createMock(File::class);
430
-		$filesNode3->expects($this->any())
431
-			->method('getSize')
432
-			->willReturn(14);
433
-		$filesNode3->expects($this->any())
434
-			->method('getId')
435
-			->willReturn(333);
436
-
437
-		$tag123 = $this->createMock(ISystemTag::class);
438
-		$tag123->expects($this->any())
439
-			->method('getName')
440
-			->willReturn('OneTwoThree');
441
-		$tag123->expects($this->any())
442
-			->method('isUserVisible')
443
-			->willReturn(true);
444
-		$tag456 = $this->createMock(ISystemTag::class);
445
-		$tag456->expects($this->any())
446
-			->method('getName')
447
-			->willReturn('FourFiveSix');
448
-		$tag456->expects($this->any())
449
-			->method('isUserVisible')
450
-			->willReturn(true);
451
-
452
-		$this->tagManager->expects($this->once())
453
-			->method('getTagsByIds')
454
-			->with(['123', '456'])
455
-			->willReturn([$tag123, $tag456]);
456
-
457
-		$this->userFolder->expects($this->exactly(2))
458
-			->method('searchBySystemTag')
459
-			->willReturnMap([
460
-				['OneTwoThree', 'testuser', 0, 0, [$filesNode1, $filesNode2]],
461
-				['FourFiveSix', 'testuser', 0, 0, [$filesNode2, $filesNode3]],
462
-			]);
463
-
464
-		$rules = [
465
-			['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
466
-			['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
467
-		];
468
-
469
-		$this->assertEquals([$filesNode2], array_values(self::invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null])));
470
-	}
471
-
472
-	public function testProcessFilterRulesAndConditionWithOneEmptyResult(): void {
473
-		$this->groupManager->expects($this->any())
474
-			->method('isAdmin')
475
-			->willReturn(true);
476
-
477
-		$filesNode1 = $this->createMock(File::class);
478
-		$filesNode1->expects($this->any())
479
-			->method('getSize')
480
-			->willReturn(12);
481
-		$filesNode1->expects($this->any())
482
-			->method('getId')
483
-			->willReturn(111);
484
-		$filesNode2 = $this->createMock(Folder::class);
485
-		$filesNode2->expects($this->any())
486
-			->method('getSize')
487
-			->willReturn(10);
488
-		$filesNode2->expects($this->any())
489
-			->method('getId')
490
-			->willReturn(222);
491
-
492
-		$tag123 = $this->createMock(ISystemTag::class);
493
-		$tag123->expects($this->any())
494
-			->method('getName')
495
-			->willReturn('OneTwoThree');
496
-		$tag123->expects($this->any())
497
-			->method('isUserVisible')
498
-			->willReturn(true);
499
-		$tag456 = $this->createMock(ISystemTag::class);
500
-		$tag456->expects($this->any())
501
-			->method('getName')
502
-			->willReturn('FourFiveSix');
503
-		$tag456->expects($this->any())
504
-			->method('isUserVisible')
505
-			->willReturn(true);
506
-
507
-		$this->tagManager->expects($this->once())
508
-			->method('getTagsByIds')
509
-			->with(['123', '456'])
510
-			->willReturn([$tag123, $tag456]);
511
-
512
-		$this->userFolder->expects($this->exactly(2))
513
-			->method('searchBySystemTag')
514
-			->willReturnMap([
515
-				['OneTwoThree', 'testuser', 0, 0, [$filesNode1, $filesNode2]],
516
-				['FourFiveSix', 'testuser', 0, 0, []],
517
-			]);
518
-
519
-		$rules = [
520
-			['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
521
-			['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
522
-		];
523
-
524
-		$this->assertEquals([], self::invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null]));
525
-	}
526
-
527
-	public function testProcessFilterRulesAndConditionWithFirstEmptyResult(): void {
528
-		$this->groupManager->expects($this->any())
529
-			->method('isAdmin')
530
-			->willReturn(true);
531
-
532
-		$filesNode1 = $this->createMock(File::class);
533
-		$filesNode1->expects($this->any())
534
-			->method('getSize')
535
-			->willReturn(12);
536
-		$filesNode1->expects($this->any())
537
-			->method('getId')
538
-			->willReturn(111);
539
-		$filesNode2 = $this->createMock(Folder::class);
540
-		$filesNode2->expects($this->any())
541
-			->method('getSize')
542
-			->willReturn(10);
543
-		$filesNode2->expects($this->any())
544
-			->method('getId')
545
-			->willReturn(222);
546
-
547
-		$tag123 = $this->createMock(ISystemTag::class);
548
-		$tag123->expects($this->any())
549
-			->method('getName')
550
-			->willReturn('OneTwoThree');
551
-		$tag123->expects($this->any())
552
-			->method('isUserVisible')
553
-			->willReturn(true);
554
-		$tag456 = $this->createMock(ISystemTag::class);
555
-		$tag456->expects($this->any())
556
-			->method('getName')
557
-			->willReturn('FourFiveSix');
558
-		$tag456->expects($this->any())
559
-			->method('isUserVisible')
560
-			->willReturn(true);
561
-
562
-		$this->tagManager->expects($this->once())
563
-			->method('getTagsByIds')
564
-			->with(['123', '456'])
565
-			->willReturn([$tag123, $tag456]);
566
-
567
-		$this->userFolder->expects($this->once())
568
-			->method('searchBySystemTag')
569
-			->willReturnMap([
570
-				['OneTwoThree', 'testuser', 0, 0, []],
571
-			]);
572
-
573
-		$rules = [
574
-			['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
575
-			['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
576
-		];
577
-
578
-		$this->assertEquals([], self::invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null]));
579
-	}
580
-
581
-	public function testProcessFilterRulesAndConditionWithEmptyMidResult(): void {
582
-		$this->groupManager->expects($this->any())
583
-			->method('isAdmin')
584
-			->willReturn(true);
585
-
586
-		$filesNode1 = $this->createMock(File::class);
587
-		$filesNode1->expects($this->any())
588
-			->method('getSize')
589
-			->willReturn(12);
590
-		$filesNode1->expects($this->any())
591
-			->method('getId')
592
-			->willReturn(111);
593
-		$filesNode2 = $this->createMock(Folder::class);
594
-		$filesNode2->expects($this->any())
595
-			->method('getSize')
596
-			->willReturn(10);
597
-		$filesNode2->expects($this->any())
598
-			->method('getId')
599
-			->willReturn(222);
600
-		$filesNode3 = $this->createMock(Folder::class);
601
-		$filesNode3->expects($this->any())
602
-			->method('getSize')
603
-			->willReturn(13);
604
-		$filesNode3->expects($this->any())
605
-			->method('getId')
606
-			->willReturn(333);
607
-
608
-		$tag123 = $this->createMock(ISystemTag::class);
609
-		$tag123->expects($this->any())
610
-			->method('getName')
611
-			->willReturn('OneTwoThree');
612
-		$tag123->expects($this->any())
613
-			->method('isUserVisible')
614
-			->willReturn(true);
615
-		$tag456 = $this->createMock(ISystemTag::class);
616
-		$tag456->expects($this->any())
617
-			->method('getName')
618
-			->willReturn('FourFiveSix');
619
-		$tag456->expects($this->any())
620
-			->method('isUserVisible')
621
-			->willReturn(true);
622
-		$tag789 = $this->createMock(ISystemTag::class);
623
-		$tag789->expects($this->any())
624
-			->method('getName')
625
-			->willReturn('SevenEightNine');
626
-		$tag789->expects($this->any())
627
-			->method('isUserVisible')
628
-			->willReturn(true);
629
-
630
-		$this->tagManager->expects($this->once())
631
-			->method('getTagsByIds')
632
-			->with(['123', '456', '789'])
633
-			->willReturn([$tag123, $tag456, $tag789]);
634
-
635
-		$this->userFolder->expects($this->exactly(2))
636
-			->method('searchBySystemTag')
637
-			->willReturnMap([
638
-				['OneTwoThree', 'testuser', 0, 0, [$filesNode1, $filesNode2]],
639
-				['FourFiveSix', 'testuser', 0, 0, [$filesNode3]],
640
-			]);
641
-
642
-		$rules = [
643
-			['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
644
-			['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
645
-			['name' => '{http://owncloud.org/ns}systemtag', 'value' => '789'],
646
-		];
647
-
648
-		$this->assertEquals([], array_values(self::invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null])));
649
-	}
650
-
651
-	public function testProcessFilterRulesInvisibleTagAsAdmin(): void {
652
-		$this->groupManager->expects($this->any())
653
-			->method('isAdmin')
654
-			->willReturn(true);
655
-
656
-		$filesNode1 = $this->createMock(File::class);
657
-		$filesNode1->expects($this->any())
658
-			->method('getSize')
659
-			->willReturn(12);
660
-		$filesNode1->expects($this->any())
661
-			->method('getId')
662
-			->willReturn(111);
663
-		$filesNode2 = $this->createMock(Folder::class);
664
-		$filesNode2->expects($this->any())
665
-			->method('getSize')
666
-			->willReturn(10);
667
-		$filesNode2->expects($this->any())
668
-			->method('getId')
669
-			->willReturn(222);
670
-		$filesNode3 = $this->createMock(Folder::class);
671
-		$filesNode3->expects($this->any())
672
-			->method('getSize')
673
-			->willReturn(13);
674
-		$filesNode3->expects($this->any())
675
-			->method('getId')
676
-			->willReturn(333);
677
-
678
-		$tag123 = $this->createMock(ISystemTag::class);
679
-		$tag123->expects($this->any())
680
-			->method('getName')
681
-			->willReturn('OneTwoThree');
682
-		$tag123->expects($this->any())
683
-			->method('isUserVisible')
684
-			->willReturn(true);
685
-		$tag456 = $this->createMock(ISystemTag::class);
686
-		$tag456->expects($this->any())
687
-			->method('getName')
688
-			->willReturn('FourFiveSix');
689
-		$tag456->expects($this->any())
690
-			->method('isUserVisible')
691
-			->willReturn(false);
692
-
693
-		$this->tagManager->expects($this->once())
694
-			->method('getTagsByIds')
695
-			->with(['123', '456'])
696
-			->willReturn([$tag123, $tag456]);
697
-
698
-		$this->userFolder->expects($this->exactly(2))
699
-			->method('searchBySystemTag')
700
-			->willReturnMap([
701
-				['OneTwoThree', 'testuser', 0, 0, [$filesNode1, $filesNode2]],
702
-				['FourFiveSix', 'testuser', 0, 0, [$filesNode2, $filesNode3]],
703
-			]);
704
-
705
-		$rules = [
706
-			['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
707
-			['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
708
-		];
709
-
710
-		$this->assertEquals([$filesNode2], array_values(self::invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null])));
711
-	}
712
-
713
-
714
-	public function testProcessFilterRulesInvisibleTagAsUser(): void {
715
-		$this->expectException(TagNotFoundException::class);
716
-
717
-		$this->groupManager->expects($this->any())
718
-			->method('isAdmin')
719
-			->willReturn(false);
720
-
721
-		$tag123 = $this->createMock(ISystemTag::class);
722
-		$tag123->expects($this->any())
723
-			->method('getName')
724
-			->willReturn('OneTwoThree');
725
-		$tag123->expects($this->any())
726
-			->method('isUserVisible')
727
-			->willReturn(true);
728
-		$tag456 = $this->createMock(ISystemTag::class);
729
-		$tag456->expects($this->any())
730
-			->method('getName')
731
-			->willReturn('FourFiveSix');
732
-		$tag456->expects($this->any())
733
-			->method('isUserVisible')
734
-			->willReturn(false);
735
-
736
-		$this->tagManager->expects($this->once())
737
-			->method('getTagsByIds')
738
-			->with(['123', '456'])
739
-			->willThrowException(new TagNotFoundException());
740
-
741
-		$this->userFolder->expects($this->never())
742
-			->method('searchBySystemTag');
743
-
744
-		$rules = [
745
-			['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
746
-			['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
747
-		];
748
-
749
-		self::invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null]);
750
-	}
751
-
752
-	public function testProcessFilterRulesVisibleTagAsUser(): void {
753
-		$this->groupManager->expects($this->any())
754
-			->method('isAdmin')
755
-			->willReturn(false);
756
-
757
-		$tag1 = $this->createMock(ISystemTag::class);
758
-		$tag1->expects($this->any())
759
-			->method('getId')
760
-			->willReturn('123');
761
-		$tag1->expects($this->any())
762
-			->method('isUserVisible')
763
-			->willReturn(true);
764
-		$tag1->expects($this->any())
765
-			->method('getName')
766
-			->willReturn('OneTwoThree');
767
-
768
-		$tag2 = $this->createMock(ISystemTag::class);
769
-		$tag2->expects($this->any())
770
-			->method('getId')
771
-			->willReturn('123');
772
-		$tag2->expects($this->any())
773
-			->method('isUserVisible')
774
-			->willReturn(true);
775
-		$tag2->expects($this->any())
776
-			->method('getName')
777
-			->willReturn('FourFiveSix');
778
-
779
-		$this->tagManager->expects($this->once())
780
-			->method('getTagsByIds')
781
-			->with(['123', '456'])
782
-			->willReturn([$tag1, $tag2]);
783
-
784
-		$filesNode1 = $this->createMock(File::class);
785
-		$filesNode1->expects($this->any())
786
-			->method('getId')
787
-			->willReturn(111);
788
-		$filesNode1->expects($this->any())
789
-			->method('getSize')
790
-			->willReturn(12);
791
-		$filesNode2 = $this->createMock(Folder::class);
792
-		$filesNode2->expects($this->any())
793
-			->method('getId')
794
-			->willReturn(222);
795
-		$filesNode2->expects($this->any())
796
-			->method('getSize')
797
-			->willReturn(10);
798
-		$filesNode3 = $this->createMock(Folder::class);
799
-		$filesNode3->expects($this->any())
800
-			->method('getId')
801
-			->willReturn(333);
802
-		$filesNode3->expects($this->any())
803
-			->method('getSize')
804
-			->willReturn(33);
805
-
806
-		$this->tagManager->expects($this->once())
807
-			->method('getTagsByIds')
808
-			->with(['123', '456'])
809
-			->willReturn([$tag1, $tag2]);
810
-
811
-		// main assertion: only user visible tags are being passed through.
812
-		$this->userFolder->expects($this->exactly(2))
813
-			->method('searchBySystemTag')
814
-			->willReturnMap([
815
-				['OneTwoThree', 'testuser', 0, 0, [$filesNode1, $filesNode2]],
816
-				['FourFiveSix', 'testuser', 0, 0, [$filesNode2, $filesNode3]],
817
-			]);
818
-
819
-		$rules = [
820
-			['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
821
-			['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
822
-		];
823
-
824
-		$this->assertEquals([$filesNode2], array_values(self::invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null])));
825
-	}
826
-
827
-	public function testProcessFavoriteFilter(): void {
828
-		$rules = [
829
-			['name' => '{http://owncloud.org/ns}favorite', 'value' => '1'],
830
-		];
831
-
832
-		$this->privateTags->expects($this->once())
833
-			->method('getFavorites')
834
-			->willReturn(['456', '789']);
835
-
836
-		$this->assertEquals(['456', '789'], array_values(self::invokePrivate($this->plugin, 'processFilterRulesForFileIDs', [$rules])));
837
-	}
838
-
839
-	public static function filesBaseUriProvider(): array {
840
-		return [
841
-			['', '', ''],
842
-			['files/username', '', '/files/username'],
843
-			['files/username/test', '/test', '/files/username'],
844
-			['files/username/test/sub', '/test/sub', '/files/username'],
845
-			['test', '/test', ''],
846
-		];
847
-	}
848
-
849
-	#[\PHPUnit\Framework\Attributes\DataProvider('filesBaseUriProvider')]
850
-	public function testFilesBaseUri(string $uri, string $reportPath, string $expectedUri): void {
851
-		$this->assertEquals($expectedUri, self::invokePrivate($this->plugin, 'getFilesBaseUri', [$uri, $reportPath]));
852
-	}
41
+    private \Sabre\DAV\Server&MockObject $server;
42
+    private Tree&MockObject $tree;
43
+    private ISystemTagObjectMapper&MockObject $tagMapper;
44
+    private ISystemTagManager&MockObject $tagManager;
45
+    private ITags&MockObject $privateTags;
46
+    private ITagManager&MockObject $privateTagManager;
47
+    private IUserSession&MockObject $userSession;
48
+    private FilesReportPluginImplementation $plugin;
49
+    private View&MockObject $view;
50
+    private IGroupManager&MockObject $groupManager;
51
+    private Folder&MockObject $userFolder;
52
+    private IPreview&MockObject $previewManager;
53
+    private IAppManager&MockObject $appManager;
54
+
55
+    protected function setUp(): void {
56
+        parent::setUp();
57
+
58
+        $this->tree = $this->createMock(Tree::class);
59
+        $this->view = $this->createMock(View::class);
60
+
61
+        $this->server = $this->getMockBuilder(Server::class)
62
+            ->setConstructorArgs([$this->tree])
63
+            ->onlyMethods(['getRequestUri', 'getBaseUri'])
64
+            ->getMock();
65
+
66
+        $this->server->expects($this->any())
67
+            ->method('getBaseUri')
68
+            ->willReturn('http://example.com/owncloud/remote.php/dav');
69
+
70
+        $this->groupManager = $this->createMock(IGroupManager::class);
71
+        $this->userFolder = $this->createMock(Folder::class);
72
+        $this->previewManager = $this->createMock(IPreview::class);
73
+        $this->appManager = $this->createMock(IAppManager::class);
74
+        $this->tagManager = $this->createMock(ISystemTagManager::class);
75
+        $this->tagMapper = $this->createMock(ISystemTagObjectMapper::class);
76
+        $this->userSession = $this->createMock(IUserSession::class);
77
+        $this->privateTags = $this->createMock(ITags::class);
78
+        $this->privateTagManager = $this->createMock(ITagManager::class);
79
+        $this->privateTagManager->expects($this->any())
80
+            ->method('load')
81
+            ->with('files')
82
+            ->willReturn($this->privateTags);
83
+
84
+        $user = $this->createMock(IUser::class);
85
+        $user->expects($this->any())
86
+            ->method('getUID')
87
+            ->willReturn('testuser');
88
+        $this->userSession->expects($this->any())
89
+            ->method('getUser')
90
+            ->willReturn($user);
91
+
92
+        $this->plugin = new FilesReportPluginImplementation(
93
+            $this->tree,
94
+            $this->view,
95
+            $this->tagManager,
96
+            $this->tagMapper,
97
+            $this->privateTagManager,
98
+            $this->userSession,
99
+            $this->groupManager,
100
+            $this->userFolder,
101
+            $this->appManager
102
+        );
103
+    }
104
+
105
+    public function testOnReportInvalidNode(): void {
106
+        $path = 'totally/unrelated/13';
107
+
108
+        $this->tree->expects($this->any())
109
+            ->method('getNodeForPath')
110
+            ->with('/' . $path)
111
+            ->willReturn($this->createMock(INode::class));
112
+
113
+        $this->server->expects($this->any())
114
+            ->method('getRequestUri')
115
+            ->willReturn($path);
116
+        $this->plugin->initialize($this->server);
117
+
118
+        $this->assertNull($this->plugin->onReport(FilesReportPluginImplementation::REPORT_NAME, [], '/' . $path));
119
+    }
120
+
121
+    public function testOnReportInvalidReportName(): void {
122
+        $path = 'test';
123
+
124
+        $this->tree->expects($this->any())
125
+            ->method('getNodeForPath')
126
+            ->with('/' . $path)
127
+            ->willReturn(
128
+                $this->getMockBuilder(INode::class)
129
+                    ->disableOriginalConstructor()
130
+                    ->getMock()
131
+            );
132
+
133
+        $this->server->expects($this->any())
134
+            ->method('getRequestUri')
135
+            ->willReturn($path);
136
+        $this->plugin->initialize($this->server);
137
+
138
+        $this->assertNull($this->plugin->onReport('{whoever}whatever', [], '/' . $path));
139
+    }
140
+
141
+    public function testOnReport(): void {
142
+        $path = 'test';
143
+
144
+        $parameters = [
145
+            [
146
+                'name' => '{DAV:}prop',
147
+                'value' => [
148
+                    ['name' => '{DAV:}getcontentlength', 'value' => ''],
149
+                    ['name' => '{http://owncloud.org/ns}size', 'value' => ''],
150
+                ],
151
+            ],
152
+            [
153
+                'name' => '{http://owncloud.org/ns}filter-rules',
154
+                'value' => [
155
+                    ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
156
+                    ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
157
+                ],
158
+            ],
159
+        ];
160
+
161
+        $this->groupManager->expects($this->any())
162
+            ->method('isAdmin')
163
+            ->willReturn(true);
164
+
165
+        $reportTargetNode = $this->createMock(Directory::class);
166
+        $reportTargetNode->expects($this->any())
167
+            ->method('getPath')
168
+            ->willReturn('');
169
+
170
+        $response = $this->createMock(ResponseInterface::class);
171
+
172
+        $response->expects($this->once())
173
+            ->method('setHeader')
174
+            ->with('Content-Type', 'application/xml; charset=utf-8');
175
+
176
+        $response->expects($this->once())
177
+            ->method('setStatus')
178
+            ->with(207);
179
+
180
+        $response->expects($this->once())
181
+            ->method('setBody');
182
+
183
+        $this->tree->expects($this->any())
184
+            ->method('getNodeForPath')
185
+            ->with('/' . $path)
186
+            ->willReturn($reportTargetNode);
187
+
188
+        $filesNode1 = $this->createMock(File::class);
189
+        $filesNode1->expects($this->any())
190
+            ->method('getSize')
191
+            ->willReturn(12);
192
+        $filesNode2 = $this->createMock(Folder::class);
193
+        $filesNode2->expects($this->any())
194
+            ->method('getSize')
195
+            ->willReturn(10);
196
+
197
+        $tag123 = $this->createMock(ISystemTag::class);
198
+        $tag123->expects($this->any())
199
+            ->method('getName')
200
+            ->willReturn('OneTwoThree');
201
+        $tag123->expects($this->any())
202
+            ->method('isUserVisible')
203
+            ->willReturn(true);
204
+        $tag456 = $this->createMock(ISystemTag::class);
205
+        $tag456->expects($this->any())
206
+            ->method('getName')
207
+            ->willReturn('FourFiveSix');
208
+        $tag456->expects($this->any())
209
+            ->method('isUserVisible')
210
+            ->willReturn(true);
211
+
212
+        $this->tagManager->expects($this->once())
213
+            ->method('getTagsByIds')
214
+            ->with(['123', '456'])
215
+            ->willReturn([$tag123, $tag456]);
216
+
217
+        $this->userFolder->expects($this->exactly(2))
218
+            ->method('searchBySystemTag')
219
+            ->willReturnMap([
220
+                ['OneTwoThree', 'testuser', 0, 0, [$filesNode1]],
221
+                ['FourFiveSix', 'testuser', 0, 0, [$filesNode2]],
222
+            ]);
223
+
224
+        $this->server->expects($this->any())
225
+            ->method('getRequestUri')
226
+            ->willReturn($path);
227
+        $this->server->httpResponse = $response;
228
+        $this->plugin->initialize($this->server);
229
+
230
+        $this->assertFalse($this->plugin->onReport(FilesReportPluginImplementation::REPORT_NAME, $parameters, '/' . $path));
231
+    }
232
+
233
+    public function testFindNodesByFileIdsRoot(): void {
234
+        $filesNode1 = $this->createMock(Folder::class);
235
+        $filesNode1->expects($this->once())
236
+            ->method('getName')
237
+            ->willReturn('first node');
238
+
239
+        $filesNode2 = $this->createMock(File::class);
240
+        $filesNode2->expects($this->once())
241
+            ->method('getName')
242
+            ->willReturn('second node');
243
+
244
+        $reportTargetNode = $this->createMock(Directory::class);
245
+        $reportTargetNode->expects($this->any())
246
+            ->method('getPath')
247
+            ->willReturn('/');
248
+
249
+        $this->userFolder->expects($this->exactly(2))
250
+            ->method('getFirstNodeById')
251
+            ->willReturnMap([
252
+                [111, $filesNode1],
253
+                [222, $filesNode2],
254
+            ]);
255
+
256
+        /** @var Directory&MockObject $reportTargetNode */
257
+        $result = $this->plugin->findNodesByFileIds($reportTargetNode, ['111', '222']);
258
+
259
+        $this->assertCount(2, $result);
260
+        $this->assertInstanceOf(Directory::class, $result[0]);
261
+        $this->assertEquals('first node', $result[0]->getName());
262
+        $this->assertInstanceOf(\OCA\DAV\Connector\Sabre\File::class, $result[1]);
263
+        $this->assertEquals('second node', $result[1]->getName());
264
+    }
265
+
266
+    public function testFindNodesByFileIdsSubDir(): void {
267
+        $filesNode1 = $this->createMock(Folder::class);
268
+        $filesNode1->expects($this->once())
269
+            ->method('getName')
270
+            ->willReturn('first node');
271
+
272
+        $filesNode2 = $this->createMock(File::class);
273
+        $filesNode2->expects($this->once())
274
+            ->method('getName')
275
+            ->willReturn('second node');
276
+
277
+        $reportTargetNode = $this->createMock(Directory::class);
278
+        $reportTargetNode->expects($this->any())
279
+            ->method('getPath')
280
+            ->willReturn('/sub1/sub2');
281
+
282
+
283
+        $subNode = $this->createMock(Folder::class);
284
+
285
+        $this->userFolder->expects($this->once())
286
+            ->method('get')
287
+            ->with('/sub1/sub2')
288
+            ->willReturn($subNode);
289
+
290
+        $subNode->expects($this->exactly(2))
291
+            ->method('getFirstNodeById')
292
+            ->willReturnMap([
293
+                [111, $filesNode1],
294
+                [222, $filesNode2],
295
+            ]);
296
+
297
+        /** @var Directory&MockObject $reportTargetNode */
298
+        $result = $this->plugin->findNodesByFileIds($reportTargetNode, ['111', '222']);
299
+
300
+        $this->assertCount(2, $result);
301
+        $this->assertInstanceOf(Directory::class, $result[0]);
302
+        $this->assertEquals('first node', $result[0]->getName());
303
+        $this->assertInstanceOf(\OCA\DAV\Connector\Sabre\File::class, $result[1]);
304
+        $this->assertEquals('second node', $result[1]->getName());
305
+    }
306
+
307
+    public function testPrepareResponses(): void {
308
+        $requestedProps = ['{DAV:}getcontentlength', '{http://owncloud.org/ns}fileid', '{DAV:}resourcetype'];
309
+
310
+        $fileInfo = $this->createMock(FileInfo::class);
311
+        $fileInfo->method('isReadable')->willReturn(true);
312
+
313
+        $node1 = $this->createMock(Directory::class);
314
+        $node2 = $this->createMock(\OCA\DAV\Connector\Sabre\File::class);
315
+
316
+        $node1->expects($this->once())
317
+            ->method('getInternalFileId')
318
+            ->willReturn('111');
319
+        $node1->expects($this->any())
320
+            ->method('getPath')
321
+            ->willReturn('/node1');
322
+        $node1->method('getFileInfo')->willReturn($fileInfo);
323
+        $node2->expects($this->once())
324
+            ->method('getInternalFileId')
325
+            ->willReturn('222');
326
+        $node2->expects($this->once())
327
+            ->method('getSize')
328
+            ->willReturn(1024);
329
+        $node2->expects($this->any())
330
+            ->method('getPath')
331
+            ->willReturn('/sub/node2');
332
+        $node2->method('getFileInfo')->willReturn($fileInfo);
333
+
334
+        $config = $this->createMock(IConfig::class);
335
+        $validator = $this->createMock(IFilenameValidator::class);
336
+        $accountManager = $this->createMock(IAccountManager::class);
337
+
338
+        $this->server->addPlugin(
339
+            new FilesPlugin(
340
+                $this->tree,
341
+                $config,
342
+                $this->createMock(IRequest::class),
343
+                $this->previewManager,
344
+                $this->createMock(IUserSession::class),
345
+                $validator,
346
+                $accountManager,
347
+            )
348
+        );
349
+        $this->plugin->initialize($this->server);
350
+        $responses = $this->plugin->prepareResponses('/files/username', $requestedProps, [$node1, $node2]);
351
+
352
+        $this->assertCount(2, $responses);
353
+
354
+        $this->assertEquals('http://example.com/owncloud/remote.php/dav/files/username/node1', $responses[0]->getHref());
355
+        $this->assertEquals('http://example.com/owncloud/remote.php/dav/files/username/sub/node2', $responses[1]->getHref());
356
+
357
+        $props1 = $responses[0]->getResponseProperties();
358
+        $this->assertEquals('111', $props1[200]['{http://owncloud.org/ns}fileid']);
359
+        $this->assertNull($props1[404]['{DAV:}getcontentlength']);
360
+        $this->assertInstanceOf('\Sabre\DAV\Xml\Property\ResourceType', $props1[200]['{DAV:}resourcetype']);
361
+        $resourceType1 = $props1[200]['{DAV:}resourcetype']->getValue();
362
+        $this->assertEquals('{DAV:}collection', $resourceType1[0]);
363
+
364
+        $props2 = $responses[1]->getResponseProperties();
365
+        $this->assertEquals('1024', $props2[200]['{DAV:}getcontentlength']);
366
+        $this->assertEquals('222', $props2[200]['{http://owncloud.org/ns}fileid']);
367
+        $this->assertInstanceOf('\Sabre\DAV\Xml\Property\ResourceType', $props2[200]['{DAV:}resourcetype']);
368
+        $this->assertCount(0, $props2[200]['{DAV:}resourcetype']->getValue());
369
+    }
370
+
371
+    public function testProcessFilterRulesSingle(): void {
372
+        $this->groupManager->expects($this->any())
373
+            ->method('isAdmin')
374
+            ->willReturn(true);
375
+
376
+        $rules = [
377
+            ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
378
+        ];
379
+
380
+        $filesNode1 = $this->createMock(File::class);
381
+        $filesNode1->expects($this->any())
382
+            ->method('getSize')
383
+            ->willReturn(12);
384
+        $filesNode2 = $this->createMock(Folder::class);
385
+        $filesNode2->expects($this->any())
386
+            ->method('getSize')
387
+            ->willReturn(10);
388
+
389
+        $tag123 = $this->createMock(ISystemTag::class);
390
+        $tag123->expects($this->any())
391
+            ->method('getName')
392
+            ->willReturn('OneTwoThree');
393
+        $tag123->expects($this->any())
394
+            ->method('isUserVisible')
395
+            ->willReturn(true);
396
+
397
+        $this->tagManager->expects($this->once())
398
+            ->method('getTagsByIds')
399
+            ->with(['123'])
400
+            ->willReturn([$tag123]);
401
+
402
+        $this->userFolder->expects($this->once())
403
+            ->method('searchBySystemTag')
404
+            ->with('OneTwoThree')
405
+            ->willReturn([$filesNode1, $filesNode2]);
406
+
407
+        $this->assertEquals([$filesNode1, $filesNode2], self::invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, 0, 0]));
408
+    }
409
+
410
+    public function testProcessFilterRulesAndCondition(): void {
411
+        $this->groupManager->expects($this->any())
412
+            ->method('isAdmin')
413
+            ->willReturn(true);
414
+
415
+        $filesNode1 = $this->createMock(File::class);
416
+        $filesNode1->expects($this->any())
417
+            ->method('getSize')
418
+            ->willReturn(12);
419
+        $filesNode1->expects($this->any())
420
+            ->method('getId')
421
+            ->willReturn(111);
422
+        $filesNode2 = $this->createMock(Folder::class);
423
+        $filesNode2->expects($this->any())
424
+            ->method('getSize')
425
+            ->willReturn(10);
426
+        $filesNode2->expects($this->any())
427
+            ->method('getId')
428
+            ->willReturn(222);
429
+        $filesNode3 = $this->createMock(File::class);
430
+        $filesNode3->expects($this->any())
431
+            ->method('getSize')
432
+            ->willReturn(14);
433
+        $filesNode3->expects($this->any())
434
+            ->method('getId')
435
+            ->willReturn(333);
436
+
437
+        $tag123 = $this->createMock(ISystemTag::class);
438
+        $tag123->expects($this->any())
439
+            ->method('getName')
440
+            ->willReturn('OneTwoThree');
441
+        $tag123->expects($this->any())
442
+            ->method('isUserVisible')
443
+            ->willReturn(true);
444
+        $tag456 = $this->createMock(ISystemTag::class);
445
+        $tag456->expects($this->any())
446
+            ->method('getName')
447
+            ->willReturn('FourFiveSix');
448
+        $tag456->expects($this->any())
449
+            ->method('isUserVisible')
450
+            ->willReturn(true);
451
+
452
+        $this->tagManager->expects($this->once())
453
+            ->method('getTagsByIds')
454
+            ->with(['123', '456'])
455
+            ->willReturn([$tag123, $tag456]);
456
+
457
+        $this->userFolder->expects($this->exactly(2))
458
+            ->method('searchBySystemTag')
459
+            ->willReturnMap([
460
+                ['OneTwoThree', 'testuser', 0, 0, [$filesNode1, $filesNode2]],
461
+                ['FourFiveSix', 'testuser', 0, 0, [$filesNode2, $filesNode3]],
462
+            ]);
463
+
464
+        $rules = [
465
+            ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
466
+            ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
467
+        ];
468
+
469
+        $this->assertEquals([$filesNode2], array_values(self::invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null])));
470
+    }
471
+
472
+    public function testProcessFilterRulesAndConditionWithOneEmptyResult(): void {
473
+        $this->groupManager->expects($this->any())
474
+            ->method('isAdmin')
475
+            ->willReturn(true);
476
+
477
+        $filesNode1 = $this->createMock(File::class);
478
+        $filesNode1->expects($this->any())
479
+            ->method('getSize')
480
+            ->willReturn(12);
481
+        $filesNode1->expects($this->any())
482
+            ->method('getId')
483
+            ->willReturn(111);
484
+        $filesNode2 = $this->createMock(Folder::class);
485
+        $filesNode2->expects($this->any())
486
+            ->method('getSize')
487
+            ->willReturn(10);
488
+        $filesNode2->expects($this->any())
489
+            ->method('getId')
490
+            ->willReturn(222);
491
+
492
+        $tag123 = $this->createMock(ISystemTag::class);
493
+        $tag123->expects($this->any())
494
+            ->method('getName')
495
+            ->willReturn('OneTwoThree');
496
+        $tag123->expects($this->any())
497
+            ->method('isUserVisible')
498
+            ->willReturn(true);
499
+        $tag456 = $this->createMock(ISystemTag::class);
500
+        $tag456->expects($this->any())
501
+            ->method('getName')
502
+            ->willReturn('FourFiveSix');
503
+        $tag456->expects($this->any())
504
+            ->method('isUserVisible')
505
+            ->willReturn(true);
506
+
507
+        $this->tagManager->expects($this->once())
508
+            ->method('getTagsByIds')
509
+            ->with(['123', '456'])
510
+            ->willReturn([$tag123, $tag456]);
511
+
512
+        $this->userFolder->expects($this->exactly(2))
513
+            ->method('searchBySystemTag')
514
+            ->willReturnMap([
515
+                ['OneTwoThree', 'testuser', 0, 0, [$filesNode1, $filesNode2]],
516
+                ['FourFiveSix', 'testuser', 0, 0, []],
517
+            ]);
518
+
519
+        $rules = [
520
+            ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
521
+            ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
522
+        ];
523
+
524
+        $this->assertEquals([], self::invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null]));
525
+    }
526
+
527
+    public function testProcessFilterRulesAndConditionWithFirstEmptyResult(): void {
528
+        $this->groupManager->expects($this->any())
529
+            ->method('isAdmin')
530
+            ->willReturn(true);
531
+
532
+        $filesNode1 = $this->createMock(File::class);
533
+        $filesNode1->expects($this->any())
534
+            ->method('getSize')
535
+            ->willReturn(12);
536
+        $filesNode1->expects($this->any())
537
+            ->method('getId')
538
+            ->willReturn(111);
539
+        $filesNode2 = $this->createMock(Folder::class);
540
+        $filesNode2->expects($this->any())
541
+            ->method('getSize')
542
+            ->willReturn(10);
543
+        $filesNode2->expects($this->any())
544
+            ->method('getId')
545
+            ->willReturn(222);
546
+
547
+        $tag123 = $this->createMock(ISystemTag::class);
548
+        $tag123->expects($this->any())
549
+            ->method('getName')
550
+            ->willReturn('OneTwoThree');
551
+        $tag123->expects($this->any())
552
+            ->method('isUserVisible')
553
+            ->willReturn(true);
554
+        $tag456 = $this->createMock(ISystemTag::class);
555
+        $tag456->expects($this->any())
556
+            ->method('getName')
557
+            ->willReturn('FourFiveSix');
558
+        $tag456->expects($this->any())
559
+            ->method('isUserVisible')
560
+            ->willReturn(true);
561
+
562
+        $this->tagManager->expects($this->once())
563
+            ->method('getTagsByIds')
564
+            ->with(['123', '456'])
565
+            ->willReturn([$tag123, $tag456]);
566
+
567
+        $this->userFolder->expects($this->once())
568
+            ->method('searchBySystemTag')
569
+            ->willReturnMap([
570
+                ['OneTwoThree', 'testuser', 0, 0, []],
571
+            ]);
572
+
573
+        $rules = [
574
+            ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
575
+            ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
576
+        ];
577
+
578
+        $this->assertEquals([], self::invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null]));
579
+    }
580
+
581
+    public function testProcessFilterRulesAndConditionWithEmptyMidResult(): void {
582
+        $this->groupManager->expects($this->any())
583
+            ->method('isAdmin')
584
+            ->willReturn(true);
585
+
586
+        $filesNode1 = $this->createMock(File::class);
587
+        $filesNode1->expects($this->any())
588
+            ->method('getSize')
589
+            ->willReturn(12);
590
+        $filesNode1->expects($this->any())
591
+            ->method('getId')
592
+            ->willReturn(111);
593
+        $filesNode2 = $this->createMock(Folder::class);
594
+        $filesNode2->expects($this->any())
595
+            ->method('getSize')
596
+            ->willReturn(10);
597
+        $filesNode2->expects($this->any())
598
+            ->method('getId')
599
+            ->willReturn(222);
600
+        $filesNode3 = $this->createMock(Folder::class);
601
+        $filesNode3->expects($this->any())
602
+            ->method('getSize')
603
+            ->willReturn(13);
604
+        $filesNode3->expects($this->any())
605
+            ->method('getId')
606
+            ->willReturn(333);
607
+
608
+        $tag123 = $this->createMock(ISystemTag::class);
609
+        $tag123->expects($this->any())
610
+            ->method('getName')
611
+            ->willReturn('OneTwoThree');
612
+        $tag123->expects($this->any())
613
+            ->method('isUserVisible')
614
+            ->willReturn(true);
615
+        $tag456 = $this->createMock(ISystemTag::class);
616
+        $tag456->expects($this->any())
617
+            ->method('getName')
618
+            ->willReturn('FourFiveSix');
619
+        $tag456->expects($this->any())
620
+            ->method('isUserVisible')
621
+            ->willReturn(true);
622
+        $tag789 = $this->createMock(ISystemTag::class);
623
+        $tag789->expects($this->any())
624
+            ->method('getName')
625
+            ->willReturn('SevenEightNine');
626
+        $tag789->expects($this->any())
627
+            ->method('isUserVisible')
628
+            ->willReturn(true);
629
+
630
+        $this->tagManager->expects($this->once())
631
+            ->method('getTagsByIds')
632
+            ->with(['123', '456', '789'])
633
+            ->willReturn([$tag123, $tag456, $tag789]);
634
+
635
+        $this->userFolder->expects($this->exactly(2))
636
+            ->method('searchBySystemTag')
637
+            ->willReturnMap([
638
+                ['OneTwoThree', 'testuser', 0, 0, [$filesNode1, $filesNode2]],
639
+                ['FourFiveSix', 'testuser', 0, 0, [$filesNode3]],
640
+            ]);
641
+
642
+        $rules = [
643
+            ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
644
+            ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
645
+            ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '789'],
646
+        ];
647
+
648
+        $this->assertEquals([], array_values(self::invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null])));
649
+    }
650
+
651
+    public function testProcessFilterRulesInvisibleTagAsAdmin(): void {
652
+        $this->groupManager->expects($this->any())
653
+            ->method('isAdmin')
654
+            ->willReturn(true);
655
+
656
+        $filesNode1 = $this->createMock(File::class);
657
+        $filesNode1->expects($this->any())
658
+            ->method('getSize')
659
+            ->willReturn(12);
660
+        $filesNode1->expects($this->any())
661
+            ->method('getId')
662
+            ->willReturn(111);
663
+        $filesNode2 = $this->createMock(Folder::class);
664
+        $filesNode2->expects($this->any())
665
+            ->method('getSize')
666
+            ->willReturn(10);
667
+        $filesNode2->expects($this->any())
668
+            ->method('getId')
669
+            ->willReturn(222);
670
+        $filesNode3 = $this->createMock(Folder::class);
671
+        $filesNode3->expects($this->any())
672
+            ->method('getSize')
673
+            ->willReturn(13);
674
+        $filesNode3->expects($this->any())
675
+            ->method('getId')
676
+            ->willReturn(333);
677
+
678
+        $tag123 = $this->createMock(ISystemTag::class);
679
+        $tag123->expects($this->any())
680
+            ->method('getName')
681
+            ->willReturn('OneTwoThree');
682
+        $tag123->expects($this->any())
683
+            ->method('isUserVisible')
684
+            ->willReturn(true);
685
+        $tag456 = $this->createMock(ISystemTag::class);
686
+        $tag456->expects($this->any())
687
+            ->method('getName')
688
+            ->willReturn('FourFiveSix');
689
+        $tag456->expects($this->any())
690
+            ->method('isUserVisible')
691
+            ->willReturn(false);
692
+
693
+        $this->tagManager->expects($this->once())
694
+            ->method('getTagsByIds')
695
+            ->with(['123', '456'])
696
+            ->willReturn([$tag123, $tag456]);
697
+
698
+        $this->userFolder->expects($this->exactly(2))
699
+            ->method('searchBySystemTag')
700
+            ->willReturnMap([
701
+                ['OneTwoThree', 'testuser', 0, 0, [$filesNode1, $filesNode2]],
702
+                ['FourFiveSix', 'testuser', 0, 0, [$filesNode2, $filesNode3]],
703
+            ]);
704
+
705
+        $rules = [
706
+            ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
707
+            ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
708
+        ];
709
+
710
+        $this->assertEquals([$filesNode2], array_values(self::invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null])));
711
+    }
712
+
713
+
714
+    public function testProcessFilterRulesInvisibleTagAsUser(): void {
715
+        $this->expectException(TagNotFoundException::class);
716
+
717
+        $this->groupManager->expects($this->any())
718
+            ->method('isAdmin')
719
+            ->willReturn(false);
720
+
721
+        $tag123 = $this->createMock(ISystemTag::class);
722
+        $tag123->expects($this->any())
723
+            ->method('getName')
724
+            ->willReturn('OneTwoThree');
725
+        $tag123->expects($this->any())
726
+            ->method('isUserVisible')
727
+            ->willReturn(true);
728
+        $tag456 = $this->createMock(ISystemTag::class);
729
+        $tag456->expects($this->any())
730
+            ->method('getName')
731
+            ->willReturn('FourFiveSix');
732
+        $tag456->expects($this->any())
733
+            ->method('isUserVisible')
734
+            ->willReturn(false);
735
+
736
+        $this->tagManager->expects($this->once())
737
+            ->method('getTagsByIds')
738
+            ->with(['123', '456'])
739
+            ->willThrowException(new TagNotFoundException());
740
+
741
+        $this->userFolder->expects($this->never())
742
+            ->method('searchBySystemTag');
743
+
744
+        $rules = [
745
+            ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
746
+            ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
747
+        ];
748
+
749
+        self::invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null]);
750
+    }
751
+
752
+    public function testProcessFilterRulesVisibleTagAsUser(): void {
753
+        $this->groupManager->expects($this->any())
754
+            ->method('isAdmin')
755
+            ->willReturn(false);
756
+
757
+        $tag1 = $this->createMock(ISystemTag::class);
758
+        $tag1->expects($this->any())
759
+            ->method('getId')
760
+            ->willReturn('123');
761
+        $tag1->expects($this->any())
762
+            ->method('isUserVisible')
763
+            ->willReturn(true);
764
+        $tag1->expects($this->any())
765
+            ->method('getName')
766
+            ->willReturn('OneTwoThree');
767
+
768
+        $tag2 = $this->createMock(ISystemTag::class);
769
+        $tag2->expects($this->any())
770
+            ->method('getId')
771
+            ->willReturn('123');
772
+        $tag2->expects($this->any())
773
+            ->method('isUserVisible')
774
+            ->willReturn(true);
775
+        $tag2->expects($this->any())
776
+            ->method('getName')
777
+            ->willReturn('FourFiveSix');
778
+
779
+        $this->tagManager->expects($this->once())
780
+            ->method('getTagsByIds')
781
+            ->with(['123', '456'])
782
+            ->willReturn([$tag1, $tag2]);
783
+
784
+        $filesNode1 = $this->createMock(File::class);
785
+        $filesNode1->expects($this->any())
786
+            ->method('getId')
787
+            ->willReturn(111);
788
+        $filesNode1->expects($this->any())
789
+            ->method('getSize')
790
+            ->willReturn(12);
791
+        $filesNode2 = $this->createMock(Folder::class);
792
+        $filesNode2->expects($this->any())
793
+            ->method('getId')
794
+            ->willReturn(222);
795
+        $filesNode2->expects($this->any())
796
+            ->method('getSize')
797
+            ->willReturn(10);
798
+        $filesNode3 = $this->createMock(Folder::class);
799
+        $filesNode3->expects($this->any())
800
+            ->method('getId')
801
+            ->willReturn(333);
802
+        $filesNode3->expects($this->any())
803
+            ->method('getSize')
804
+            ->willReturn(33);
805
+
806
+        $this->tagManager->expects($this->once())
807
+            ->method('getTagsByIds')
808
+            ->with(['123', '456'])
809
+            ->willReturn([$tag1, $tag2]);
810
+
811
+        // main assertion: only user visible tags are being passed through.
812
+        $this->userFolder->expects($this->exactly(2))
813
+            ->method('searchBySystemTag')
814
+            ->willReturnMap([
815
+                ['OneTwoThree', 'testuser', 0, 0, [$filesNode1, $filesNode2]],
816
+                ['FourFiveSix', 'testuser', 0, 0, [$filesNode2, $filesNode3]],
817
+            ]);
818
+
819
+        $rules = [
820
+            ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'],
821
+            ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'],
822
+        ];
823
+
824
+        $this->assertEquals([$filesNode2], array_values(self::invokePrivate($this->plugin, 'processFilterRulesForFileNodes', [$rules, null, null])));
825
+    }
826
+
827
+    public function testProcessFavoriteFilter(): void {
828
+        $rules = [
829
+            ['name' => '{http://owncloud.org/ns}favorite', 'value' => '1'],
830
+        ];
831
+
832
+        $this->privateTags->expects($this->once())
833
+            ->method('getFavorites')
834
+            ->willReturn(['456', '789']);
835
+
836
+        $this->assertEquals(['456', '789'], array_values(self::invokePrivate($this->plugin, 'processFilterRulesForFileIDs', [$rules])));
837
+    }
838
+
839
+    public static function filesBaseUriProvider(): array {
840
+        return [
841
+            ['', '', ''],
842
+            ['files/username', '', '/files/username'],
843
+            ['files/username/test', '/test', '/files/username'],
844
+            ['files/username/test/sub', '/test/sub', '/files/username'],
845
+            ['test', '/test', ''],
846
+        ];
847
+    }
848
+
849
+    #[\PHPUnit\Framework\Attributes\DataProvider('filesBaseUriProvider')]
850
+    public function testFilesBaseUri(string $uri, string $reportPath, string $expectedUri): void {
851
+        $this->assertEquals($expectedUri, self::invokePrivate($this->plugin, 'getFilesBaseUri', [$uri, $reportPath]));
852
+    }
853 853
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Connector/Sabre/PublicAuthTest.php 1 patch
Indentation   +283 added lines, -283 removed lines patch added patch discarded remove patch
@@ -28,357 +28,357 @@
 block discarded – undo
28 28
  */
29 29
 class PublicAuthTest extends \Test\TestCase {
30 30
 
31
-	private ISession&MockObject $session;
32
-	private IRequest&MockObject $request;
33
-	private IManager&MockObject $shareManager;
34
-	private IThrottler&MockObject $throttler;
35
-	private LoggerInterface&MockObject $logger;
36
-	private IURLGenerator&MockObject $urlGenerator;
37
-	private PublicAuth $auth;
38
-
39
-	private bool|string $oldUser;
40
-
41
-	protected function setUp(): void {
42
-		parent::setUp();
43
-
44
-		$this->session = $this->createMock(ISession::class);
45
-		$this->request = $this->createMock(IRequest::class);
46
-		$this->shareManager = $this->createMock(IManager::class);
47
-		$this->throttler = $this->createMock(IThrottler::class);
48
-		$this->logger = $this->createMock(LoggerInterface::class);
49
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
50
-
51
-		$this->auth = new PublicAuth(
52
-			$this->request,
53
-			$this->shareManager,
54
-			$this->session,
55
-			$this->throttler,
56
-			$this->logger,
57
-			$this->urlGenerator,
58
-		);
59
-
60
-		// Store current user
61
-		$this->oldUser = \OC_User::getUser();
62
-	}
63
-
64
-	protected function tearDown(): void {
65
-		\OC_User::setIncognitoMode(false);
66
-
67
-		// Set old user
68
-		\OC_User::setUserId($this->oldUser);
69
-		if ($this->oldUser !== false) {
70
-			\OC_Util::setupFS($this->oldUser);
71
-		}
72
-
73
-		parent::tearDown();
74
-	}
75
-
76
-	public function testGetToken(): void {
77
-		$this->request->method('getPathInfo')
78
-			->willReturn('/dav/files/GX9HSGQrGE');
79
-
80
-		$result = self::invokePrivate($this->auth, 'getToken');
81
-
82
-		$this->assertSame('GX9HSGQrGE', $result);
83
-	}
84
-
85
-	public function testGetTokenInvalid(): void {
86
-		$this->request->method('getPathInfo')
87
-			->willReturn('/dav/files');
88
-
89
-		$this->expectException(\Sabre\DAV\Exception\NotFound::class);
90
-		self::invokePrivate($this->auth, 'getToken');
91
-	}
92
-
93
-	public function testCheckTokenValidShare(): void {
94
-		$this->request->method('getPathInfo')
95
-			->willReturn('/dav/files/GX9HSGQrGE');
96
-
97
-		$share = $this->createMock(IShare::class);
98
-		$share->method('getPassword')->willReturn(null);
99
-
100
-		$this->shareManager->expects($this->once())
101
-			->method('getShareByToken')
102
-			->with('GX9HSGQrGE')
103
-			->willReturn($share);
104
-
105
-		$result = self::invokePrivate($this->auth, 'checkToken');
106
-		$this->assertSame([true, 'principals/GX9HSGQrGE'], $result);
107
-	}
31
+    private ISession&MockObject $session;
32
+    private IRequest&MockObject $request;
33
+    private IManager&MockObject $shareManager;
34
+    private IThrottler&MockObject $throttler;
35
+    private LoggerInterface&MockObject $logger;
36
+    private IURLGenerator&MockObject $urlGenerator;
37
+    private PublicAuth $auth;
38
+
39
+    private bool|string $oldUser;
40
+
41
+    protected function setUp(): void {
42
+        parent::setUp();
43
+
44
+        $this->session = $this->createMock(ISession::class);
45
+        $this->request = $this->createMock(IRequest::class);
46
+        $this->shareManager = $this->createMock(IManager::class);
47
+        $this->throttler = $this->createMock(IThrottler::class);
48
+        $this->logger = $this->createMock(LoggerInterface::class);
49
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
50
+
51
+        $this->auth = new PublicAuth(
52
+            $this->request,
53
+            $this->shareManager,
54
+            $this->session,
55
+            $this->throttler,
56
+            $this->logger,
57
+            $this->urlGenerator,
58
+        );
59
+
60
+        // Store current user
61
+        $this->oldUser = \OC_User::getUser();
62
+    }
63
+
64
+    protected function tearDown(): void {
65
+        \OC_User::setIncognitoMode(false);
66
+
67
+        // Set old user
68
+        \OC_User::setUserId($this->oldUser);
69
+        if ($this->oldUser !== false) {
70
+            \OC_Util::setupFS($this->oldUser);
71
+        }
72
+
73
+        parent::tearDown();
74
+    }
75
+
76
+    public function testGetToken(): void {
77
+        $this->request->method('getPathInfo')
78
+            ->willReturn('/dav/files/GX9HSGQrGE');
79
+
80
+        $result = self::invokePrivate($this->auth, 'getToken');
81
+
82
+        $this->assertSame('GX9HSGQrGE', $result);
83
+    }
84
+
85
+    public function testGetTokenInvalid(): void {
86
+        $this->request->method('getPathInfo')
87
+            ->willReturn('/dav/files');
88
+
89
+        $this->expectException(\Sabre\DAV\Exception\NotFound::class);
90
+        self::invokePrivate($this->auth, 'getToken');
91
+    }
92
+
93
+    public function testCheckTokenValidShare(): void {
94
+        $this->request->method('getPathInfo')
95
+            ->willReturn('/dav/files/GX9HSGQrGE');
96
+
97
+        $share = $this->createMock(IShare::class);
98
+        $share->method('getPassword')->willReturn(null);
99
+
100
+        $this->shareManager->expects($this->once())
101
+            ->method('getShareByToken')
102
+            ->with('GX9HSGQrGE')
103
+            ->willReturn($share);
104
+
105
+        $result = self::invokePrivate($this->auth, 'checkToken');
106
+        $this->assertSame([true, 'principals/GX9HSGQrGE'], $result);
107
+    }
108 108
 
109
-	public function testCheckTokenInvalidShare(): void {
110
-		$this->request->method('getPathInfo')
111
-			->willReturn('/dav/files/GX9HSGQrGE');
109
+    public function testCheckTokenInvalidShare(): void {
110
+        $this->request->method('getPathInfo')
111
+            ->willReturn('/dav/files/GX9HSGQrGE');
112 112
 
113
-		$this->shareManager
114
-			->expects($this->once())
115
-			->method('getShareByToken')
116
-			->with('GX9HSGQrGE')
117
-			->willThrowException(new ShareNotFound());
118
-
119
-		$this->expectException(\Sabre\DAV\Exception\NotFound::class);
120
-		self::invokePrivate($this->auth, 'checkToken');
121
-	}
122
-
123
-	public function testCheckTokenAlreadyAuthenticated(): void {
124
-		$this->request->method('getPathInfo')
125
-			->willReturn('/dav/files/GX9HSGQrGE');
113
+        $this->shareManager
114
+            ->expects($this->once())
115
+            ->method('getShareByToken')
116
+            ->with('GX9HSGQrGE')
117
+            ->willThrowException(new ShareNotFound());
118
+
119
+        $this->expectException(\Sabre\DAV\Exception\NotFound::class);
120
+        self::invokePrivate($this->auth, 'checkToken');
121
+    }
122
+
123
+    public function testCheckTokenAlreadyAuthenticated(): void {
124
+        $this->request->method('getPathInfo')
125
+            ->willReturn('/dav/files/GX9HSGQrGE');
126 126
 
127
-		$share = $this->createMock(IShare::class);
128
-		$share->method('getShareType')->willReturn(42);
127
+        $share = $this->createMock(IShare::class);
128
+        $share->method('getShareType')->willReturn(42);
129 129
 
130
-		$this->shareManager->expects($this->once())
131
-			->method('getShareByToken')
132
-			->with('GX9HSGQrGE')
133
-			->willReturn($share);
130
+        $this->shareManager->expects($this->once())
131
+            ->method('getShareByToken')
132
+            ->with('GX9HSGQrGE')
133
+            ->willReturn($share);
134 134
 
135
-		$this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
136
-		$this->session->method('get')->with('public_link_authenticated')->willReturn('42');
135
+        $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
136
+        $this->session->method('get')->with('public_link_authenticated')->willReturn('42');
137 137
 
138
-		$result = self::invokePrivate($this->auth, 'checkToken');
139
-		$this->assertSame([true, 'principals/GX9HSGQrGE'], $result);
140
-	}
138
+        $result = self::invokePrivate($this->auth, 'checkToken');
139
+        $this->assertSame([true, 'principals/GX9HSGQrGE'], $result);
140
+    }
141 141
 
142
-	public function testCheckTokenPasswordNotAuthenticated(): void {
143
-		$this->request->method('getPathInfo')
144
-			->willReturn('/dav/files/GX9HSGQrGE');
142
+    public function testCheckTokenPasswordNotAuthenticated(): void {
143
+        $this->request->method('getPathInfo')
144
+            ->willReturn('/dav/files/GX9HSGQrGE');
145 145
 
146
-		$share = $this->createMock(IShare::class);
147
-		$share->method('getPassword')->willReturn('password');
148
-		$share->method('getShareType')->willReturn(42);
146
+        $share = $this->createMock(IShare::class);
147
+        $share->method('getPassword')->willReturn('password');
148
+        $share->method('getShareType')->willReturn(42);
149 149
 
150
-		$this->shareManager->expects($this->once())
151
-			->method('getShareByToken')
152
-			->with('GX9HSGQrGE')
153
-			->willReturn($share);
150
+        $this->shareManager->expects($this->once())
151
+            ->method('getShareByToken')
152
+            ->with('GX9HSGQrGE')
153
+            ->willReturn($share);
154 154
 
155
-		$this->session->method('exists')->with('public_link_authenticated')->willReturn(false);
155
+        $this->session->method('exists')->with('public_link_authenticated')->willReturn(false);
156 156
 
157
-		$this->expectException(\Sabre\DAV\Exception\NotAuthenticated::class);
158
-		self::invokePrivate($this->auth, 'checkToken');
159
-	}
157
+        $this->expectException(\Sabre\DAV\Exception\NotAuthenticated::class);
158
+        self::invokePrivate($this->auth, 'checkToken');
159
+    }
160 160
 
161
-	public function testCheckTokenPasswordAuthenticatedWrongShare(): void {
162
-		$this->request->method('getPathInfo')
163
-			->willReturn('/dav/files/GX9HSGQrGE');
161
+    public function testCheckTokenPasswordAuthenticatedWrongShare(): void {
162
+        $this->request->method('getPathInfo')
163
+            ->willReturn('/dav/files/GX9HSGQrGE');
164 164
 
165
-		$share = $this->createMock(IShare::class);
166
-		$share->method('getPassword')->willReturn('password');
167
-		$share->method('getShareType')->willReturn(42);
165
+        $share = $this->createMock(IShare::class);
166
+        $share->method('getPassword')->willReturn('password');
167
+        $share->method('getShareType')->willReturn(42);
168 168
 
169
-		$this->shareManager->expects($this->once())
170
-			->method('getShareByToken')
171
-			->with('GX9HSGQrGE')
172
-			->willReturn($share);
169
+        $this->shareManager->expects($this->once())
170
+            ->method('getShareByToken')
171
+            ->with('GX9HSGQrGE')
172
+            ->willReturn($share);
173 173
 
174
-		$this->session->method('exists')->with('public_link_authenticated')->willReturn(false);
175
-		$this->session->method('get')->with('public_link_authenticated')->willReturn('43');
174
+        $this->session->method('exists')->with('public_link_authenticated')->willReturn(false);
175
+        $this->session->method('get')->with('public_link_authenticated')->willReturn('43');
176 176
 
177
-		$this->expectException(\Sabre\DAV\Exception\NotAuthenticated::class);
178
-		self::invokePrivate($this->auth, 'checkToken');
179
-	}
177
+        $this->expectException(\Sabre\DAV\Exception\NotAuthenticated::class);
178
+        self::invokePrivate($this->auth, 'checkToken');
179
+    }
180 180
 
181
-	public function testNoShare(): void {
182
-		$this->request->method('getPathInfo')
183
-			->willReturn('/dav/files/GX9HSGQrGE');
181
+    public function testNoShare(): void {
182
+        $this->request->method('getPathInfo')
183
+            ->willReturn('/dav/files/GX9HSGQrGE');
184 184
 
185
-		$this->shareManager->expects($this->once())
186
-			->method('getShareByToken')
187
-			->with('GX9HSGQrGE')
188
-			->willThrowException(new ShareNotFound());
185
+        $this->shareManager->expects($this->once())
186
+            ->method('getShareByToken')
187
+            ->with('GX9HSGQrGE')
188
+            ->willThrowException(new ShareNotFound());
189 189
 
190
-		$result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
190
+        $result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
191 191
 
192
-		$this->assertFalse($result);
193
-	}
192
+        $this->assertFalse($result);
193
+    }
194 194
 
195
-	public function testShareNoPassword(): void {
196
-		$this->request->method('getPathInfo')
197
-			->willReturn('/dav/files/GX9HSGQrGE');
195
+    public function testShareNoPassword(): void {
196
+        $this->request->method('getPathInfo')
197
+            ->willReturn('/dav/files/GX9HSGQrGE');
198 198
 
199
-		$share = $this->createMock(IShare::class);
200
-		$share->method('getPassword')->willReturn(null);
199
+        $share = $this->createMock(IShare::class);
200
+        $share->method('getPassword')->willReturn(null);
201 201
 
202
-		$this->shareManager->expects($this->once())
203
-			->method('getShareByToken')
204
-			->with('GX9HSGQrGE')
205
-			->willReturn($share);
202
+        $this->shareManager->expects($this->once())
203
+            ->method('getShareByToken')
204
+            ->with('GX9HSGQrGE')
205
+            ->willReturn($share);
206 206
 
207
-		$result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
207
+        $result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
208 208
 
209
-		$this->assertTrue($result);
210
-	}
209
+        $this->assertTrue($result);
210
+    }
211 211
 
212
-	public function testSharePasswordFancyShareType(): void {
213
-		$this->request->method('getPathInfo')
214
-			->willReturn('/dav/files/GX9HSGQrGE');
212
+    public function testSharePasswordFancyShareType(): void {
213
+        $this->request->method('getPathInfo')
214
+            ->willReturn('/dav/files/GX9HSGQrGE');
215 215
 
216
-		$share = $this->createMock(IShare::class);
217
-		$share->method('getPassword')->willReturn('password');
218
-		$share->method('getShareType')->willReturn(42);
216
+        $share = $this->createMock(IShare::class);
217
+        $share->method('getPassword')->willReturn('password');
218
+        $share->method('getShareType')->willReturn(42);
219 219
 
220
-		$this->shareManager->expects($this->once())
221
-			->method('getShareByToken')
222
-			->with('GX9HSGQrGE')
223
-			->willReturn($share);
220
+        $this->shareManager->expects($this->once())
221
+            ->method('getShareByToken')
222
+            ->with('GX9HSGQrGE')
223
+            ->willReturn($share);
224 224
 
225
-		$result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
225
+        $result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
226 226
 
227
-		$this->assertFalse($result);
228
-	}
227
+        $this->assertFalse($result);
228
+    }
229 229
 
230 230
 
231
-	public function testSharePasswordRemote(): void {
232
-		$this->request->method('getPathInfo')
233
-			->willReturn('/dav/files/GX9HSGQrGE');
231
+    public function testSharePasswordRemote(): void {
232
+        $this->request->method('getPathInfo')
233
+            ->willReturn('/dav/files/GX9HSGQrGE');
234 234
 
235
-		$share = $this->createMock(IShare::class);
236
-		$share->method('getPassword')->willReturn('password');
237
-		$share->method('getShareType')->willReturn(IShare::TYPE_REMOTE);
235
+        $share = $this->createMock(IShare::class);
236
+        $share->method('getPassword')->willReturn('password');
237
+        $share->method('getShareType')->willReturn(IShare::TYPE_REMOTE);
238 238
 
239
-		$this->shareManager->expects($this->once())
240
-			->method('getShareByToken')
241
-			->with('GX9HSGQrGE')
242
-			->willReturn($share);
239
+        $this->shareManager->expects($this->once())
240
+            ->method('getShareByToken')
241
+            ->with('GX9HSGQrGE')
242
+            ->willReturn($share);
243 243
 
244
-		$result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
244
+        $result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
245 245
 
246
-		$this->assertTrue($result);
247
-	}
246
+        $this->assertTrue($result);
247
+    }
248 248
 
249
-	public function testSharePasswordLinkValidPassword(): void {
250
-		$this->request->method('getPathInfo')
251
-			->willReturn('/dav/files/GX9HSGQrGE');
249
+    public function testSharePasswordLinkValidPassword(): void {
250
+        $this->request->method('getPathInfo')
251
+            ->willReturn('/dav/files/GX9HSGQrGE');
252 252
 
253
-		$share = $this->createMock(IShare::class);
254
-		$share->method('getPassword')->willReturn('password');
255
-		$share->method('getShareType')->willReturn(IShare::TYPE_LINK);
253
+        $share = $this->createMock(IShare::class);
254
+        $share->method('getPassword')->willReturn('password');
255
+        $share->method('getShareType')->willReturn(IShare::TYPE_LINK);
256 256
 
257
-		$this->shareManager->expects($this->once())
258
-			->method('getShareByToken')
259
-			->with('GX9HSGQrGE')
260
-			->willReturn($share);
257
+        $this->shareManager->expects($this->once())
258
+            ->method('getShareByToken')
259
+            ->with('GX9HSGQrGE')
260
+            ->willReturn($share);
261 261
 
262
-		$this->shareManager->expects($this->once())
263
-			->method('checkPassword')->with(
264
-				$this->equalTo($share),
265
-				$this->equalTo('password')
266
-			)->willReturn(true);
262
+        $this->shareManager->expects($this->once())
263
+            ->method('checkPassword')->with(
264
+                $this->equalTo($share),
265
+                $this->equalTo('password')
266
+            )->willReturn(true);
267 267
 
268
-		$result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
268
+        $result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
269 269
 
270
-		$this->assertTrue($result);
271
-	}
270
+        $this->assertTrue($result);
271
+    }
272 272
 
273
-	public function testSharePasswordMailValidPassword(): void {
274
-		$this->request->method('getPathInfo')
275
-			->willReturn('/dav/files/GX9HSGQrGE');
273
+    public function testSharePasswordMailValidPassword(): void {
274
+        $this->request->method('getPathInfo')
275
+            ->willReturn('/dav/files/GX9HSGQrGE');
276 276
 
277
-		$share = $this->createMock(IShare::class);
278
-		$share->method('getPassword')->willReturn('password');
279
-		$share->method('getShareType')->willReturn(IShare::TYPE_EMAIL);
277
+        $share = $this->createMock(IShare::class);
278
+        $share->method('getPassword')->willReturn('password');
279
+        $share->method('getShareType')->willReturn(IShare::TYPE_EMAIL);
280 280
 
281
-		$this->shareManager->expects($this->once())
282
-			->method('getShareByToken')
283
-			->with('GX9HSGQrGE')
284
-			->willReturn($share);
281
+        $this->shareManager->expects($this->once())
282
+            ->method('getShareByToken')
283
+            ->with('GX9HSGQrGE')
284
+            ->willReturn($share);
285 285
 
286
-		$this->shareManager->expects($this->once())
287
-			->method('checkPassword')->with(
288
-				$this->equalTo($share),
289
-				$this->equalTo('password')
290
-			)->willReturn(true);
286
+        $this->shareManager->expects($this->once())
287
+            ->method('checkPassword')->with(
288
+                $this->equalTo($share),
289
+                $this->equalTo('password')
290
+            )->willReturn(true);
291 291
 
292
-		$result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
292
+        $result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
293 293
 
294
-		$this->assertTrue($result);
295
-	}
294
+        $this->assertTrue($result);
295
+    }
296 296
 
297
-	public function testInvalidSharePasswordLinkValidSession(): void {
298
-		$this->request->method('getPathInfo')
299
-			->willReturn('/dav/files/GX9HSGQrGE');
297
+    public function testInvalidSharePasswordLinkValidSession(): void {
298
+        $this->request->method('getPathInfo')
299
+            ->willReturn('/dav/files/GX9HSGQrGE');
300 300
 
301
-		$share = $this->createMock(IShare::class);
302
-		$share->method('getPassword')->willReturn('password');
303
-		$share->method('getShareType')->willReturn(IShare::TYPE_LINK);
304
-		$share->method('getId')->willReturn('42');
301
+        $share = $this->createMock(IShare::class);
302
+        $share->method('getPassword')->willReturn('password');
303
+        $share->method('getShareType')->willReturn(IShare::TYPE_LINK);
304
+        $share->method('getId')->willReturn('42');
305 305
 
306
-		$this->shareManager->expects($this->once())
307
-			->method('getShareByToken')
308
-			->with('GX9HSGQrGE')
309
-			->willReturn($share);
306
+        $this->shareManager->expects($this->once())
307
+            ->method('getShareByToken')
308
+            ->with('GX9HSGQrGE')
309
+            ->willReturn($share);
310 310
 
311
-		$this->shareManager->expects($this->once())
312
-			->method('checkPassword')
313
-			->with(
314
-				$this->equalTo($share),
315
-				$this->equalTo('password')
316
-			)->willReturn(false);
311
+        $this->shareManager->expects($this->once())
312
+            ->method('checkPassword')
313
+            ->with(
314
+                $this->equalTo($share),
315
+                $this->equalTo('password')
316
+            )->willReturn(false);
317 317
 
318
-		$this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
319
-		$this->session->method('get')->with('public_link_authenticated')->willReturn('42');
318
+        $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
319
+        $this->session->method('get')->with('public_link_authenticated')->willReturn('42');
320 320
 
321
-		$result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
321
+        $result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
322 322
 
323
-		$this->assertTrue($result);
324
-	}
323
+        $this->assertTrue($result);
324
+    }
325 325
 
326
-	public function testSharePasswordLinkInvalidSession(): void {
327
-		$this->request->method('getPathInfo')
328
-			->willReturn('/dav/files/GX9HSGQrGE');
326
+    public function testSharePasswordLinkInvalidSession(): void {
327
+        $this->request->method('getPathInfo')
328
+            ->willReturn('/dav/files/GX9HSGQrGE');
329 329
 
330
-		$share = $this->createMock(IShare::class);
331
-		$share->method('getPassword')->willReturn('password');
332
-		$share->method('getShareType')->willReturn(IShare::TYPE_LINK);
333
-		$share->method('getId')->willReturn('42');
330
+        $share = $this->createMock(IShare::class);
331
+        $share->method('getPassword')->willReturn('password');
332
+        $share->method('getShareType')->willReturn(IShare::TYPE_LINK);
333
+        $share->method('getId')->willReturn('42');
334 334
 
335
-		$this->shareManager->expects($this->once())
336
-			->method('getShareByToken')
337
-			->with('GX9HSGQrGE')
338
-			->willReturn($share);
335
+        $this->shareManager->expects($this->once())
336
+            ->method('getShareByToken')
337
+            ->with('GX9HSGQrGE')
338
+            ->willReturn($share);
339 339
 
340
-		$this->shareManager->expects($this->once())
341
-			->method('checkPassword')
342
-			->with(
343
-				$this->equalTo($share),
344
-				$this->equalTo('password')
345
-			)->willReturn(false);
340
+        $this->shareManager->expects($this->once())
341
+            ->method('checkPassword')
342
+            ->with(
343
+                $this->equalTo($share),
344
+                $this->equalTo('password')
345
+            )->willReturn(false);
346 346
 
347
-		$this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
348
-		$this->session->method('get')->with('public_link_authenticated')->willReturn('43');
347
+        $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
348
+        $this->session->method('get')->with('public_link_authenticated')->willReturn('43');
349 349
 
350
-		$result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
350
+        $result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
351 351
 
352
-		$this->assertFalse($result);
353
-	}
352
+        $this->assertFalse($result);
353
+    }
354 354
 
355 355
 
356
-	public function testSharePasswordMailInvalidSession(): void {
357
-		$this->request->method('getPathInfo')
358
-			->willReturn('/dav/files/GX9HSGQrGE');
356
+    public function testSharePasswordMailInvalidSession(): void {
357
+        $this->request->method('getPathInfo')
358
+            ->willReturn('/dav/files/GX9HSGQrGE');
359 359
 
360
-		$share = $this->createMock(IShare::class);
361
-		$share->method('getPassword')->willReturn('password');
362
-		$share->method('getShareType')->willReturn(IShare::TYPE_EMAIL);
363
-		$share->method('getId')->willReturn('42');
360
+        $share = $this->createMock(IShare::class);
361
+        $share->method('getPassword')->willReturn('password');
362
+        $share->method('getShareType')->willReturn(IShare::TYPE_EMAIL);
363
+        $share->method('getId')->willReturn('42');
364 364
 
365
-		$this->shareManager->expects($this->once())
366
-			->method('getShareByToken')
367
-			->with('GX9HSGQrGE')
368
-			->willReturn($share);
365
+        $this->shareManager->expects($this->once())
366
+            ->method('getShareByToken')
367
+            ->with('GX9HSGQrGE')
368
+            ->willReturn($share);
369 369
 
370
-		$this->shareManager->expects($this->once())
371
-			->method('checkPassword')
372
-			->with(
373
-				$this->equalTo($share),
374
-				$this->equalTo('password')
375
-			)->willReturn(false);
370
+        $this->shareManager->expects($this->once())
371
+            ->method('checkPassword')
372
+            ->with(
373
+                $this->equalTo($share),
374
+                $this->equalTo('password')
375
+            )->willReturn(false);
376 376
 
377
-		$this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
378
-		$this->session->method('get')->with('public_link_authenticated')->willReturn('43');
377
+        $this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
378
+        $this->session->method('get')->with('public_link_authenticated')->willReturn('43');
379 379
 
380
-		$result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
380
+        $result = self::invokePrivate($this->auth, 'validateUserPass', ['username', 'password']);
381 381
 
382
-		$this->assertFalse($result);
383
-	}
382
+        $this->assertFalse($result);
383
+    }
384 384
 }
Please login to merge, or discard this patch.