Completed
Push — master ( d03f6d...56f3d1 )
by Joas
20:52 queued 17s
created
apps/dav/tests/unit/DAV/AnonymousOptionsTest.php 2 patches
Indentation   +52 added lines, -52 removed lines patch added patch discarded remove patch
@@ -16,77 +16,77 @@
 block discarded – undo
16 16
 use Test\TestCase;
17 17
 
18 18
 class AnonymousOptionsTest extends TestCase {
19
-	private function sendRequest(string $method, string $path, string $userAgent = '') {
20
-		$server = new Server();
21
-		$server->addPlugin(new AnonymousOptionsPlugin());
22
-		$server->addPlugin(new Plugin(new BasicCallBack(function () {
23
-			return false;
24
-		})));
19
+    private function sendRequest(string $method, string $path, string $userAgent = '') {
20
+        $server = new Server();
21
+        $server->addPlugin(new AnonymousOptionsPlugin());
22
+        $server->addPlugin(new Plugin(new BasicCallBack(function () {
23
+            return false;
24
+        })));
25 25
 
26
-		$server->httpRequest->setMethod($method);
27
-		$server->httpRequest->setUrl($path);
28
-		$server->httpRequest->setHeader('User-Agent', $userAgent);
26
+        $server->httpRequest->setMethod($method);
27
+        $server->httpRequest->setUrl($path);
28
+        $server->httpRequest->setHeader('User-Agent', $userAgent);
29 29
 
30
-		$server->sapi = new SapiMock();
31
-		$server->exec();
32
-		return $server->httpResponse;
33
-	}
30
+        $server->sapi = new SapiMock();
31
+        $server->exec();
32
+        return $server->httpResponse;
33
+    }
34 34
 
35
-	public function testAnonymousOptionsRoot(): void {
36
-		$response = $this->sendRequest('OPTIONS', '');
35
+    public function testAnonymousOptionsRoot(): void {
36
+        $response = $this->sendRequest('OPTIONS', '');
37 37
 
38
-		$this->assertEquals(401, $response->getStatus());
39
-	}
38
+        $this->assertEquals(401, $response->getStatus());
39
+    }
40 40
 
41
-	public function testAnonymousOptionsNonRoot(): void {
42
-		$response = $this->sendRequest('OPTIONS', 'foo');
41
+    public function testAnonymousOptionsNonRoot(): void {
42
+        $response = $this->sendRequest('OPTIONS', 'foo');
43 43
 
44
-		$this->assertEquals(401, $response->getStatus());
45
-	}
44
+        $this->assertEquals(401, $response->getStatus());
45
+    }
46 46
 
47
-	public function testAnonymousOptionsNonRootSubDir(): void {
48
-		$response = $this->sendRequest('OPTIONS', 'foo/bar');
47
+    public function testAnonymousOptionsNonRootSubDir(): void {
48
+        $response = $this->sendRequest('OPTIONS', 'foo/bar');
49 49
 
50
-		$this->assertEquals(401, $response->getStatus());
51
-	}
50
+        $this->assertEquals(401, $response->getStatus());
51
+    }
52 52
 
53
-	public function testAnonymousOptionsRootOffice(): void {
54
-		$response = $this->sendRequest('OPTIONS', '', 'Microsoft Office does strange things');
53
+    public function testAnonymousOptionsRootOffice(): void {
54
+        $response = $this->sendRequest('OPTIONS', '', 'Microsoft Office does strange things');
55 55
 
56
-		$this->assertEquals(200, $response->getStatus());
57
-	}
56
+        $this->assertEquals(200, $response->getStatus());
57
+    }
58 58
 
59
-	public function testAnonymousOptionsNonRootOffice(): void {
60
-		$response = $this->sendRequest('OPTIONS', 'foo', 'Microsoft Office does strange things');
59
+    public function testAnonymousOptionsNonRootOffice(): void {
60
+        $response = $this->sendRequest('OPTIONS', 'foo', 'Microsoft Office does strange things');
61 61
 
62
-		$this->assertEquals(200, $response->getStatus());
63
-	}
62
+        $this->assertEquals(200, $response->getStatus());
63
+    }
64 64
 
65
-	public function testAnonymousOptionsNonRootSubDirOffice(): void {
66
-		$response = $this->sendRequest('OPTIONS', 'foo/bar', 'Microsoft Office does strange things');
65
+    public function testAnonymousOptionsNonRootSubDirOffice(): void {
66
+        $response = $this->sendRequest('OPTIONS', 'foo/bar', 'Microsoft Office does strange things');
67 67
 
68
-		$this->assertEquals(200, $response->getStatus());
69
-	}
68
+        $this->assertEquals(200, $response->getStatus());
69
+    }
70 70
 
71
-	public function testAnonymousHead(): void {
72
-		$response = $this->sendRequest('HEAD', '', 'Microsoft Office does strange things');
71
+    public function testAnonymousHead(): void {
72
+        $response = $this->sendRequest('HEAD', '', 'Microsoft Office does strange things');
73 73
 
74
-		$this->assertEquals(200, $response->getStatus());
75
-	}
74
+        $this->assertEquals(200, $response->getStatus());
75
+    }
76 76
 
77
-	public function testAnonymousHeadNoOffice(): void {
78
-		$response = $this->sendRequest('HEAD', '');
77
+    public function testAnonymousHeadNoOffice(): void {
78
+        $response = $this->sendRequest('HEAD', '');
79 79
 
80
-		$this->assertEquals(401, $response->getStatus(), 'curl');
81
-	}
80
+        $this->assertEquals(401, $response->getStatus(), 'curl');
81
+    }
82 82
 }
83 83
 
84 84
 class SapiMock extends Sapi {
85
-	/**
86
-	 * Overriding this so nothing is ever echo'd.
87
-	 *
88
-	 * @return void
89
-	 */
90
-	public static function sendResponse(ResponseInterface $response): void {
91
-	}
85
+    /**
86
+     * Overriding this so nothing is ever echo'd.
87
+     *
88
+     * @return void
89
+     */
90
+    public static function sendResponse(ResponseInterface $response): void {
91
+    }
92 92
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -19,7 +19,7 @@
 block discarded – undo
19 19
 	private function sendRequest(string $method, string $path, string $userAgent = '') {
20 20
 		$server = new Server();
21 21
 		$server->addPlugin(new AnonymousOptionsPlugin());
22
-		$server->addPlugin(new Plugin(new BasicCallBack(function () {
22
+		$server->addPlugin(new Plugin(new BasicCallBack(function() {
23 23
 			return false;
24 24
 		})));
25 25
 
Please login to merge, or discard this patch.
apps/dav/tests/unit/DAV/GroupPrincipalTest.php 1 patch
Indentation   +312 added lines, -312 removed lines patch added patch discarded remove patch
@@ -20,316 +20,316 @@
 block discarded – undo
20 20
 use Sabre\DAV\PropPatch;
21 21
 
22 22
 class GroupPrincipalTest extends \Test\TestCase {
23
-	private IConfig&MockObject $config;
24
-	private IGroupManager&MockObject $groupManager;
25
-	private IUserSession&MockObject $userSession;
26
-	private IManager&MockObject $shareManager;
27
-	private GroupPrincipalBackend $connector;
28
-
29
-	protected function setUp(): void {
30
-		$this->groupManager = $this->createMock(IGroupManager::class);
31
-		$this->userSession = $this->createMock(IUserSession::class);
32
-		$this->shareManager = $this->createMock(IManager::class);
33
-		$this->config = $this->createMock(IConfig::class);
34
-
35
-		$this->connector = new GroupPrincipalBackend(
36
-			$this->groupManager,
37
-			$this->userSession,
38
-			$this->shareManager,
39
-			$this->config
40
-		);
41
-		parent::setUp();
42
-	}
43
-
44
-	public function testGetPrincipalsByPrefixWithoutPrefix(): void {
45
-		$response = $this->connector->getPrincipalsByPrefix('');
46
-		$this->assertSame([], $response);
47
-	}
48
-
49
-	public function testGetPrincipalsByPrefixWithUsers(): void {
50
-		$group1 = $this->mockGroup('foo');
51
-		$group2 = $this->mockGroup('bar');
52
-		$this->groupManager
53
-			->expects($this->once())
54
-			->method('search')
55
-			->with('')
56
-			->willReturn([$group1, $group2]);
57
-
58
-		$expectedResponse = [
59
-			0 => [
60
-				'uri' => 'principals/groups/foo',
61
-				'{DAV:}displayname' => 'Group foo',
62
-				'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'GROUP',
63
-			],
64
-			1 => [
65
-				'uri' => 'principals/groups/bar',
66
-				'{DAV:}displayname' => 'Group bar',
67
-				'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'GROUP',
68
-			]
69
-		];
70
-		$response = $this->connector->getPrincipalsByPrefix('principals/groups');
71
-		$this->assertSame($expectedResponse, $response);
72
-	}
73
-
74
-	public function testGetPrincipalsByPrefixEmpty(): void {
75
-		$this->groupManager
76
-			->expects($this->once())
77
-			->method('search')
78
-			->with('')
79
-			->willReturn([]);
80
-
81
-		$response = $this->connector->getPrincipalsByPrefix('principals/groups');
82
-		$this->assertSame([], $response);
83
-	}
84
-
85
-	public function testGetPrincipalsByPathWithoutMail(): void {
86
-		$group1 = $this->mockGroup('foo');
87
-		$this->groupManager
88
-			->expects($this->once())
89
-			->method('get')
90
-			->with('foo')
91
-			->willReturn($group1);
92
-
93
-		$expectedResponse = [
94
-			'uri' => 'principals/groups/foo',
95
-			'{DAV:}displayname' => 'Group foo',
96
-			'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'GROUP',
97
-		];
98
-		$response = $this->connector->getPrincipalByPath('principals/groups/foo');
99
-		$this->assertSame($expectedResponse, $response);
100
-	}
101
-
102
-	public function testGetPrincipalsByPathWithMail(): void {
103
-		$fooUser = $this->mockGroup('foo');
104
-		$this->groupManager
105
-			->expects($this->once())
106
-			->method('get')
107
-			->with('foo')
108
-			->willReturn($fooUser);
109
-
110
-		$expectedResponse = [
111
-			'uri' => 'principals/groups/foo',
112
-			'{DAV:}displayname' => 'Group foo',
113
-			'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'GROUP',
114
-		];
115
-		$response = $this->connector->getPrincipalByPath('principals/groups/foo');
116
-		$this->assertSame($expectedResponse, $response);
117
-	}
118
-
119
-	public function testGetPrincipalsByPathEmpty(): void {
120
-		$this->groupManager
121
-			->expects($this->once())
122
-			->method('get')
123
-			->with('foo')
124
-			->willReturn(null);
125
-
126
-		$response = $this->connector->getPrincipalByPath('principals/groups/foo');
127
-		$this->assertSame(null, $response);
128
-	}
129
-
130
-	public function testGetPrincipalsByPathGroupWithSlash(): void {
131
-		$group1 = $this->mockGroup('foo/bar');
132
-		$this->groupManager
133
-			->expects($this->once())
134
-			->method('get')
135
-			->with('foo/bar')
136
-			->willReturn($group1);
137
-
138
-		$expectedResponse = [
139
-			'uri' => 'principals/groups/foo%2Fbar',
140
-			'{DAV:}displayname' => 'Group foo/bar',
141
-			'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'GROUP',
142
-		];
143
-		$response = $this->connector->getPrincipalByPath('principals/groups/foo/bar');
144
-		$this->assertSame($expectedResponse, $response);
145
-	}
146
-
147
-	public function testGetPrincipalsByPathGroupWithHash(): void {
148
-		$group1 = $this->mockGroup('foo#bar');
149
-		$this->groupManager
150
-			->expects($this->once())
151
-			->method('get')
152
-			->with('foo#bar')
153
-			->willReturn($group1);
154
-
155
-		$expectedResponse = [
156
-			'uri' => 'principals/groups/foo%23bar',
157
-			'{DAV:}displayname' => 'Group foo#bar',
158
-			'{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'GROUP',
159
-		];
160
-		$response = $this->connector->getPrincipalByPath('principals/groups/foo#bar');
161
-		$this->assertSame($expectedResponse, $response);
162
-	}
163
-
164
-	public function testGetGroupMemberSet(): void {
165
-		$response = $this->connector->getGroupMemberSet('principals/groups/foo');
166
-		$this->assertSame([], $response);
167
-	}
168
-
169
-	public function testGetGroupMembership(): void {
170
-		$response = $this->connector->getGroupMembership('principals/groups/foo');
171
-		$this->assertSame([], $response);
172
-	}
173
-
174
-
175
-	public function testSetGroupMembership(): void {
176
-		$this->expectException(\Sabre\DAV\Exception::class);
177
-		$this->expectExceptionMessage('Setting members of the group is not supported yet');
178
-
179
-		$this->connector->setGroupMemberSet('principals/groups/foo', ['foo']);
180
-	}
181
-
182
-	public function testUpdatePrincipal(): void {
183
-		$this->assertSame(0, $this->connector->updatePrincipal('foo', new PropPatch([])));
184
-	}
185
-
186
-	public function testSearchPrincipalsWithEmptySearchProperties(): void {
187
-		$this->assertSame([], $this->connector->searchPrincipals('principals/groups', []));
188
-	}
189
-
190
-	public function testSearchPrincipalsWithWrongPrefixPath(): void {
191
-		$this->assertSame([], $this->connector->searchPrincipals('principals/users',
192
-			['{DAV:}displayname' => 'Foo']));
193
-	}
194
-
195
-	/**
196
-	 * @dataProvider searchPrincipalsDataProvider
197
-	 */
198
-	public function testSearchPrincipals(bool $sharingEnabled, bool $groupSharingEnabled, bool $groupsOnly, string $test, array $result): void {
199
-		$this->shareManager->expects($this->once())
200
-			->method('shareAPIEnabled')
201
-			->willReturn($sharingEnabled);
202
-
203
-		$this->shareManager->expects($sharingEnabled ? $this->once() : $this->never())
204
-			->method('allowGroupSharing')
205
-			->willReturn($groupSharingEnabled);
206
-
207
-		if ($sharingEnabled && $groupSharingEnabled) {
208
-			$this->shareManager->expects($this->once())
209
-				->method('shareWithGroupMembersOnly')
210
-				->willReturn($groupsOnly);
211
-
212
-			if ($groupsOnly) {
213
-				$user = $this->createMock(IUser::class);
214
-				$this->userSession->expects($this->once())
215
-					->method('getUser')
216
-					->willReturn($user);
217
-
218
-				$this->groupManager->expects($this->once())
219
-					->method('getUserGroupIds')
220
-					->with($user)
221
-					->willReturn(['group1', 'group2', 'group5']);
222
-			}
223
-		} else {
224
-			$this->shareManager->expects($this->never())
225
-				->method('shareWithGroupMembersOnly');
226
-			$this->groupManager->expects($this->never())
227
-				->method($this->anything());
228
-		}
229
-
230
-		$group1 = $this->createMock(IGroup::class);
231
-		$group1->method('getGID')->willReturn('group1');
232
-		$group2 = $this->createMock(IGroup::class);
233
-		$group2->method('getGID')->willReturn('group2');
234
-		$group3 = $this->createMock(IGroup::class);
235
-		$group3->method('getGID')->willReturn('group3');
236
-		$group4 = $this->createMock(IGroup::class);
237
-		$group4->method('getGID')->willReturn('group4');
238
-		$group5 = $this->createMock(IGroup::class);
239
-		$group5->method('getGID')->willReturn('group5');
240
-
241
-		if ($sharingEnabled && $groupSharingEnabled) {
242
-			$this->groupManager->expects($this->once())
243
-				->method('search')
244
-				->with('Foo')
245
-				->willReturn([$group1, $group2, $group3, $group4, $group5]);
246
-		} else {
247
-			$this->groupManager->expects($this->never())
248
-				->method('search');
249
-		}
250
-
251
-		$this->assertSame($result, $this->connector->searchPrincipals('principals/groups',
252
-			['{DAV:}displayname' => 'Foo'], $test));
253
-	}
254
-
255
-	public static function searchPrincipalsDataProvider(): array {
256
-		return [
257
-			[true, true, false, 'allof', ['principals/groups/group1', 'principals/groups/group2', 'principals/groups/group3', 'principals/groups/group4', 'principals/groups/group5']],
258
-			[true, true, false, 'anyof', ['principals/groups/group1', 'principals/groups/group2', 'principals/groups/group3', 'principals/groups/group4', 'principals/groups/group5']],
259
-			[true, true, true, 'allof', ['principals/groups/group1', 'principals/groups/group2', 'principals/groups/group5']],
260
-			[true, true, true, 'anyof', ['principals/groups/group1', 'principals/groups/group2', 'principals/groups/group5']],
261
-			[true, false, false, 'allof', []],
262
-			[false, true, false, 'anyof', []],
263
-			[false, false, false, 'allof', []],
264
-			[false, false, false, 'anyof', []],
265
-		];
266
-	}
267
-
268
-	/**
269
-	 * @dataProvider findByUriDataProvider
270
-	 */
271
-	public function testFindByUri(bool $sharingEnabled, bool $groupSharingEnabled, bool $groupsOnly, string $findUri, ?string $result): void {
272
-		$this->shareManager->expects($this->once())
273
-			->method('shareAPIEnabled')
274
-			->willReturn($sharingEnabled);
275
-
276
-		$this->shareManager->expects($sharingEnabled ? $this->once() : $this->never())
277
-			->method('allowGroupSharing')
278
-			->willReturn($groupSharingEnabled);
279
-
280
-		if ($sharingEnabled && $groupSharingEnabled) {
281
-			$this->shareManager->expects($this->once())
282
-				->method('shareWithGroupMembersOnly')
283
-				->willReturn($groupsOnly);
284
-
285
-			if ($groupsOnly) {
286
-				$user = $this->createMock(IUser::class);
287
-				$this->userSession->expects($this->once())
288
-					->method('getUser')
289
-					->willReturn($user);
290
-
291
-				$this->groupManager->expects($this->once())
292
-					->method('getUserGroupIds')
293
-					->with($user)
294
-					->willReturn(['group1', 'group2', 'group5']);
295
-			}
296
-		} else {
297
-			$this->shareManager->expects($this->never())
298
-				->method('shareWithGroupMembersOnly');
299
-			$this->groupManager->expects($this->never())
300
-				->method($this->anything());
301
-		}
302
-
303
-		$this->assertEquals($result, $this->connector->findByUri($findUri, 'principals/groups'));
304
-	}
305
-
306
-	public static function findByUriDataProvider(): array {
307
-		return [
308
-			[false, false, false, 'principal:principals/groups/group1', null],
309
-			[false, false, false, 'principal:principals/groups/group3', null],
310
-			[false, true, false, 'principal:principals/groups/group1', null],
311
-			[false, true, false, 'principal:principals/groups/group3', null],
312
-			[false, false, true, 'principal:principals/groups/group1', null],
313
-			[false, false, true, 'principal:principals/groups/group3', null],
314
-			[true, false, true, 'principal:principals/groups/group1', null],
315
-			[true, false, true, 'principal:principals/groups/group3', null],
316
-			[true, true, true, 'principal:principals/groups/group1', 'principals/groups/group1'],
317
-			[true, true, true, 'principal:principals/groups/group3', null],
318
-			[true, true, false, 'principal:principals/groups/group1', 'principals/groups/group1'],
319
-			[true, true, false, 'principal:principals/groups/group3', 'principals/groups/group3'],
320
-		];
321
-	}
322
-
323
-	private function mockGroup(string $gid): Group&MockObject {
324
-		$fooGroup = $this->createMock(Group::class);
325
-		$fooGroup
326
-			->expects($this->exactly(1))
327
-			->method('getGID')
328
-			->willReturn($gid);
329
-		$fooGroup
330
-			->expects($this->exactly(1))
331
-			->method('getDisplayName')
332
-			->willReturn('Group ' . $gid);
333
-		return $fooGroup;
334
-	}
23
+    private IConfig&MockObject $config;
24
+    private IGroupManager&MockObject $groupManager;
25
+    private IUserSession&MockObject $userSession;
26
+    private IManager&MockObject $shareManager;
27
+    private GroupPrincipalBackend $connector;
28
+
29
+    protected function setUp(): void {
30
+        $this->groupManager = $this->createMock(IGroupManager::class);
31
+        $this->userSession = $this->createMock(IUserSession::class);
32
+        $this->shareManager = $this->createMock(IManager::class);
33
+        $this->config = $this->createMock(IConfig::class);
34
+
35
+        $this->connector = new GroupPrincipalBackend(
36
+            $this->groupManager,
37
+            $this->userSession,
38
+            $this->shareManager,
39
+            $this->config
40
+        );
41
+        parent::setUp();
42
+    }
43
+
44
+    public function testGetPrincipalsByPrefixWithoutPrefix(): void {
45
+        $response = $this->connector->getPrincipalsByPrefix('');
46
+        $this->assertSame([], $response);
47
+    }
48
+
49
+    public function testGetPrincipalsByPrefixWithUsers(): void {
50
+        $group1 = $this->mockGroup('foo');
51
+        $group2 = $this->mockGroup('bar');
52
+        $this->groupManager
53
+            ->expects($this->once())
54
+            ->method('search')
55
+            ->with('')
56
+            ->willReturn([$group1, $group2]);
57
+
58
+        $expectedResponse = [
59
+            0 => [
60
+                'uri' => 'principals/groups/foo',
61
+                '{DAV:}displayname' => 'Group foo',
62
+                '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'GROUP',
63
+            ],
64
+            1 => [
65
+                'uri' => 'principals/groups/bar',
66
+                '{DAV:}displayname' => 'Group bar',
67
+                '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'GROUP',
68
+            ]
69
+        ];
70
+        $response = $this->connector->getPrincipalsByPrefix('principals/groups');
71
+        $this->assertSame($expectedResponse, $response);
72
+    }
73
+
74
+    public function testGetPrincipalsByPrefixEmpty(): void {
75
+        $this->groupManager
76
+            ->expects($this->once())
77
+            ->method('search')
78
+            ->with('')
79
+            ->willReturn([]);
80
+
81
+        $response = $this->connector->getPrincipalsByPrefix('principals/groups');
82
+        $this->assertSame([], $response);
83
+    }
84
+
85
+    public function testGetPrincipalsByPathWithoutMail(): void {
86
+        $group1 = $this->mockGroup('foo');
87
+        $this->groupManager
88
+            ->expects($this->once())
89
+            ->method('get')
90
+            ->with('foo')
91
+            ->willReturn($group1);
92
+
93
+        $expectedResponse = [
94
+            'uri' => 'principals/groups/foo',
95
+            '{DAV:}displayname' => 'Group foo',
96
+            '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'GROUP',
97
+        ];
98
+        $response = $this->connector->getPrincipalByPath('principals/groups/foo');
99
+        $this->assertSame($expectedResponse, $response);
100
+    }
101
+
102
+    public function testGetPrincipalsByPathWithMail(): void {
103
+        $fooUser = $this->mockGroup('foo');
104
+        $this->groupManager
105
+            ->expects($this->once())
106
+            ->method('get')
107
+            ->with('foo')
108
+            ->willReturn($fooUser);
109
+
110
+        $expectedResponse = [
111
+            'uri' => 'principals/groups/foo',
112
+            '{DAV:}displayname' => 'Group foo',
113
+            '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'GROUP',
114
+        ];
115
+        $response = $this->connector->getPrincipalByPath('principals/groups/foo');
116
+        $this->assertSame($expectedResponse, $response);
117
+    }
118
+
119
+    public function testGetPrincipalsByPathEmpty(): void {
120
+        $this->groupManager
121
+            ->expects($this->once())
122
+            ->method('get')
123
+            ->with('foo')
124
+            ->willReturn(null);
125
+
126
+        $response = $this->connector->getPrincipalByPath('principals/groups/foo');
127
+        $this->assertSame(null, $response);
128
+    }
129
+
130
+    public function testGetPrincipalsByPathGroupWithSlash(): void {
131
+        $group1 = $this->mockGroup('foo/bar');
132
+        $this->groupManager
133
+            ->expects($this->once())
134
+            ->method('get')
135
+            ->with('foo/bar')
136
+            ->willReturn($group1);
137
+
138
+        $expectedResponse = [
139
+            'uri' => 'principals/groups/foo%2Fbar',
140
+            '{DAV:}displayname' => 'Group foo/bar',
141
+            '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'GROUP',
142
+        ];
143
+        $response = $this->connector->getPrincipalByPath('principals/groups/foo/bar');
144
+        $this->assertSame($expectedResponse, $response);
145
+    }
146
+
147
+    public function testGetPrincipalsByPathGroupWithHash(): void {
148
+        $group1 = $this->mockGroup('foo#bar');
149
+        $this->groupManager
150
+            ->expects($this->once())
151
+            ->method('get')
152
+            ->with('foo#bar')
153
+            ->willReturn($group1);
154
+
155
+        $expectedResponse = [
156
+            'uri' => 'principals/groups/foo%23bar',
157
+            '{DAV:}displayname' => 'Group foo#bar',
158
+            '{urn:ietf:params:xml:ns:caldav}calendar-user-type' => 'GROUP',
159
+        ];
160
+        $response = $this->connector->getPrincipalByPath('principals/groups/foo#bar');
161
+        $this->assertSame($expectedResponse, $response);
162
+    }
163
+
164
+    public function testGetGroupMemberSet(): void {
165
+        $response = $this->connector->getGroupMemberSet('principals/groups/foo');
166
+        $this->assertSame([], $response);
167
+    }
168
+
169
+    public function testGetGroupMembership(): void {
170
+        $response = $this->connector->getGroupMembership('principals/groups/foo');
171
+        $this->assertSame([], $response);
172
+    }
173
+
174
+
175
+    public function testSetGroupMembership(): void {
176
+        $this->expectException(\Sabre\DAV\Exception::class);
177
+        $this->expectExceptionMessage('Setting members of the group is not supported yet');
178
+
179
+        $this->connector->setGroupMemberSet('principals/groups/foo', ['foo']);
180
+    }
181
+
182
+    public function testUpdatePrincipal(): void {
183
+        $this->assertSame(0, $this->connector->updatePrincipal('foo', new PropPatch([])));
184
+    }
185
+
186
+    public function testSearchPrincipalsWithEmptySearchProperties(): void {
187
+        $this->assertSame([], $this->connector->searchPrincipals('principals/groups', []));
188
+    }
189
+
190
+    public function testSearchPrincipalsWithWrongPrefixPath(): void {
191
+        $this->assertSame([], $this->connector->searchPrincipals('principals/users',
192
+            ['{DAV:}displayname' => 'Foo']));
193
+    }
194
+
195
+    /**
196
+     * @dataProvider searchPrincipalsDataProvider
197
+     */
198
+    public function testSearchPrincipals(bool $sharingEnabled, bool $groupSharingEnabled, bool $groupsOnly, string $test, array $result): void {
199
+        $this->shareManager->expects($this->once())
200
+            ->method('shareAPIEnabled')
201
+            ->willReturn($sharingEnabled);
202
+
203
+        $this->shareManager->expects($sharingEnabled ? $this->once() : $this->never())
204
+            ->method('allowGroupSharing')
205
+            ->willReturn($groupSharingEnabled);
206
+
207
+        if ($sharingEnabled && $groupSharingEnabled) {
208
+            $this->shareManager->expects($this->once())
209
+                ->method('shareWithGroupMembersOnly')
210
+                ->willReturn($groupsOnly);
211
+
212
+            if ($groupsOnly) {
213
+                $user = $this->createMock(IUser::class);
214
+                $this->userSession->expects($this->once())
215
+                    ->method('getUser')
216
+                    ->willReturn($user);
217
+
218
+                $this->groupManager->expects($this->once())
219
+                    ->method('getUserGroupIds')
220
+                    ->with($user)
221
+                    ->willReturn(['group1', 'group2', 'group5']);
222
+            }
223
+        } else {
224
+            $this->shareManager->expects($this->never())
225
+                ->method('shareWithGroupMembersOnly');
226
+            $this->groupManager->expects($this->never())
227
+                ->method($this->anything());
228
+        }
229
+
230
+        $group1 = $this->createMock(IGroup::class);
231
+        $group1->method('getGID')->willReturn('group1');
232
+        $group2 = $this->createMock(IGroup::class);
233
+        $group2->method('getGID')->willReturn('group2');
234
+        $group3 = $this->createMock(IGroup::class);
235
+        $group3->method('getGID')->willReturn('group3');
236
+        $group4 = $this->createMock(IGroup::class);
237
+        $group4->method('getGID')->willReturn('group4');
238
+        $group5 = $this->createMock(IGroup::class);
239
+        $group5->method('getGID')->willReturn('group5');
240
+
241
+        if ($sharingEnabled && $groupSharingEnabled) {
242
+            $this->groupManager->expects($this->once())
243
+                ->method('search')
244
+                ->with('Foo')
245
+                ->willReturn([$group1, $group2, $group3, $group4, $group5]);
246
+        } else {
247
+            $this->groupManager->expects($this->never())
248
+                ->method('search');
249
+        }
250
+
251
+        $this->assertSame($result, $this->connector->searchPrincipals('principals/groups',
252
+            ['{DAV:}displayname' => 'Foo'], $test));
253
+    }
254
+
255
+    public static function searchPrincipalsDataProvider(): array {
256
+        return [
257
+            [true, true, false, 'allof', ['principals/groups/group1', 'principals/groups/group2', 'principals/groups/group3', 'principals/groups/group4', 'principals/groups/group5']],
258
+            [true, true, false, 'anyof', ['principals/groups/group1', 'principals/groups/group2', 'principals/groups/group3', 'principals/groups/group4', 'principals/groups/group5']],
259
+            [true, true, true, 'allof', ['principals/groups/group1', 'principals/groups/group2', 'principals/groups/group5']],
260
+            [true, true, true, 'anyof', ['principals/groups/group1', 'principals/groups/group2', 'principals/groups/group5']],
261
+            [true, false, false, 'allof', []],
262
+            [false, true, false, 'anyof', []],
263
+            [false, false, false, 'allof', []],
264
+            [false, false, false, 'anyof', []],
265
+        ];
266
+    }
267
+
268
+    /**
269
+     * @dataProvider findByUriDataProvider
270
+     */
271
+    public function testFindByUri(bool $sharingEnabled, bool $groupSharingEnabled, bool $groupsOnly, string $findUri, ?string $result): void {
272
+        $this->shareManager->expects($this->once())
273
+            ->method('shareAPIEnabled')
274
+            ->willReturn($sharingEnabled);
275
+
276
+        $this->shareManager->expects($sharingEnabled ? $this->once() : $this->never())
277
+            ->method('allowGroupSharing')
278
+            ->willReturn($groupSharingEnabled);
279
+
280
+        if ($sharingEnabled && $groupSharingEnabled) {
281
+            $this->shareManager->expects($this->once())
282
+                ->method('shareWithGroupMembersOnly')
283
+                ->willReturn($groupsOnly);
284
+
285
+            if ($groupsOnly) {
286
+                $user = $this->createMock(IUser::class);
287
+                $this->userSession->expects($this->once())
288
+                    ->method('getUser')
289
+                    ->willReturn($user);
290
+
291
+                $this->groupManager->expects($this->once())
292
+                    ->method('getUserGroupIds')
293
+                    ->with($user)
294
+                    ->willReturn(['group1', 'group2', 'group5']);
295
+            }
296
+        } else {
297
+            $this->shareManager->expects($this->never())
298
+                ->method('shareWithGroupMembersOnly');
299
+            $this->groupManager->expects($this->never())
300
+                ->method($this->anything());
301
+        }
302
+
303
+        $this->assertEquals($result, $this->connector->findByUri($findUri, 'principals/groups'));
304
+    }
305
+
306
+    public static function findByUriDataProvider(): array {
307
+        return [
308
+            [false, false, false, 'principal:principals/groups/group1', null],
309
+            [false, false, false, 'principal:principals/groups/group3', null],
310
+            [false, true, false, 'principal:principals/groups/group1', null],
311
+            [false, true, false, 'principal:principals/groups/group3', null],
312
+            [false, false, true, 'principal:principals/groups/group1', null],
313
+            [false, false, true, 'principal:principals/groups/group3', null],
314
+            [true, false, true, 'principal:principals/groups/group1', null],
315
+            [true, false, true, 'principal:principals/groups/group3', null],
316
+            [true, true, true, 'principal:principals/groups/group1', 'principals/groups/group1'],
317
+            [true, true, true, 'principal:principals/groups/group3', null],
318
+            [true, true, false, 'principal:principals/groups/group1', 'principals/groups/group1'],
319
+            [true, true, false, 'principal:principals/groups/group3', 'principals/groups/group3'],
320
+        ];
321
+    }
322
+
323
+    private function mockGroup(string $gid): Group&MockObject {
324
+        $fooGroup = $this->createMock(Group::class);
325
+        $fooGroup
326
+            ->expects($this->exactly(1))
327
+            ->method('getGID')
328
+            ->willReturn($gid);
329
+        $fooGroup
330
+            ->expects($this->exactly(1))
331
+            ->method('getDisplayName')
332
+            ->willReturn('Group ' . $gid);
333
+        return $fooGroup;
334
+    }
335 335
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/DAV/Listener/UserEventsListenerTest.php 1 patch
Indentation   +112 added lines, -112 removed lines patch added patch discarded remove patch
@@ -22,116 +22,116 @@
 block discarded – undo
22 22
 use Test\TestCase;
23 23
 
24 24
 class UserEventsListenerTest extends TestCase {
25
-	private IUserManager&MockObject $userManager;
26
-	private SyncService&MockObject $syncService;
27
-	private CalDavBackend&MockObject $calDavBackend;
28
-	private CardDavBackend&MockObject $cardDavBackend;
29
-	private Defaults&MockObject $defaults;
30
-
31
-	private DefaultContactService&MockObject $defaultContactService;
32
-
33
-	private UserEventsListener $userEventsListener;
34
-
35
-	protected function setUp(): void {
36
-		parent::setUp();
37
-		$this->userManager = $this->createMock(IUserManager::class);
38
-		$this->syncService = $this->createMock(SyncService::class);
39
-		$this->calDavBackend = $this->createMock(CalDavBackend::class);
40
-		$this->cardDavBackend = $this->createMock(CardDavBackend::class);
41
-		$this->defaults = $this->createMock(Defaults::class);
42
-		$this->defaultContactService = $this->createMock(DefaultContactService::class);
43
-		$this->userEventsListener = new UserEventsListener(
44
-			$this->userManager,
45
-			$this->syncService,
46
-			$this->calDavBackend,
47
-			$this->cardDavBackend,
48
-			$this->defaults,
49
-			$this->defaultContactService,
50
-		);
51
-	}
52
-
53
-	public function test(): void {
54
-		$user = $this->createMock(IUser::class);
55
-		$user->expects($this->once())->method('getUID')->willReturn('newUser');
56
-
57
-		$this->defaults->expects($this->once())->method('getColorPrimary')->willReturn('#745bca');
58
-
59
-		$this->calDavBackend->expects($this->once())->method('getCalendarsForUserCount')->willReturn(0);
60
-		$this->calDavBackend->expects($this->once())->method('createCalendar')->with(
61
-			'principals/users/newUser',
62
-			'personal', [
63
-				'{DAV:}displayname' => 'Personal',
64
-				'{http://apple.com/ns/ical/}calendar-color' => '#745bca',
65
-				'components' => 'VEVENT'
66
-			]);
67
-
68
-		$this->cardDavBackend->expects($this->once())->method('getAddressBooksForUserCount')->willReturn(0);
69
-		$this->cardDavBackend->expects($this->once())->method('createAddressBook')->with(
70
-			'principals/users/newUser',
71
-			'contacts', ['{DAV:}displayname' => 'Contacts']);
72
-
73
-		$this->userEventsListener->firstLogin($user);
74
-	}
75
-
76
-	public function testWithExisting(): void {
77
-		$user = $this->createMock(IUser::class);
78
-		$user->expects($this->once())->method('getUID')->willReturn('newUser');
79
-
80
-		$this->calDavBackend->expects($this->once())->method('getCalendarsForUserCount')->willReturn(1);
81
-		$this->calDavBackend->expects($this->never())->method('createCalendar');
82
-
83
-		$this->cardDavBackend->expects($this->once())->method('getAddressBooksForUserCount')->willReturn(1);
84
-		$this->cardDavBackend->expects($this->never())->method('createAddressBook');
85
-
86
-		$this->userEventsListener->firstLogin($user);
87
-	}
88
-
89
-	public function testWithBirthdayCalendar(): void {
90
-		$user = $this->createMock(IUser::class);
91
-		$user->expects($this->once())->method('getUID')->willReturn('newUser');
92
-
93
-		$this->defaults->expects($this->once())->method('getColorPrimary')->willReturn('#745bca');
94
-
95
-		$this->calDavBackend->expects($this->once())->method('getCalendarsForUserCount')->willReturn(0);
96
-		$this->calDavBackend->expects($this->once())->method('createCalendar')->with(
97
-			'principals/users/newUser',
98
-			'personal', [
99
-				'{DAV:}displayname' => 'Personal',
100
-				'{http://apple.com/ns/ical/}calendar-color' => '#745bca',
101
-				'components' => 'VEVENT'
102
-			]);
103
-
104
-		$this->cardDavBackend->expects($this->once())->method('getAddressBooksForUserCount')->willReturn(0);
105
-		$this->cardDavBackend->expects($this->once())->method('createAddressBook')->with(
106
-			'principals/users/newUser',
107
-			'contacts', ['{DAV:}displayname' => 'Contacts']);
108
-
109
-		$this->userEventsListener->firstLogin($user);
110
-	}
111
-
112
-	public function testDeleteCalendar(): void {
113
-		$user = $this->createMock(IUser::class);
114
-		$user->expects($this->once())->method('getUID')->willReturn('newUser');
115
-
116
-		$this->syncService->expects($this->once())
117
-			->method('deleteUser');
118
-
119
-		$this->calDavBackend->expects($this->once())->method('getUsersOwnCalendars')->willReturn([
120
-			['id' => 'personal']
121
-		]);
122
-		$this->calDavBackend->expects($this->once())->method('getSubscriptionsForUser')->willReturn([
123
-			['id' => 'some-subscription']
124
-		]);
125
-		$this->calDavBackend->expects($this->once())->method('deleteCalendar')->with('personal');
126
-		$this->calDavBackend->expects($this->once())->method('deleteSubscription')->with('some-subscription');
127
-		$this->calDavBackend->expects($this->once())->method('deleteAllSharesByUser');
128
-
129
-		$this->cardDavBackend->expects($this->once())->method('getUsersOwnAddressBooks')->willReturn([
130
-			['id' => 'personal']
131
-		]);
132
-		$this->cardDavBackend->expects($this->once())->method('deleteAddressBook');
133
-
134
-		$this->userEventsListener->preDeleteUser($user);
135
-		$this->userEventsListener->postDeleteUser('newUser');
136
-	}
25
+    private IUserManager&MockObject $userManager;
26
+    private SyncService&MockObject $syncService;
27
+    private CalDavBackend&MockObject $calDavBackend;
28
+    private CardDavBackend&MockObject $cardDavBackend;
29
+    private Defaults&MockObject $defaults;
30
+
31
+    private DefaultContactService&MockObject $defaultContactService;
32
+
33
+    private UserEventsListener $userEventsListener;
34
+
35
+    protected function setUp(): void {
36
+        parent::setUp();
37
+        $this->userManager = $this->createMock(IUserManager::class);
38
+        $this->syncService = $this->createMock(SyncService::class);
39
+        $this->calDavBackend = $this->createMock(CalDavBackend::class);
40
+        $this->cardDavBackend = $this->createMock(CardDavBackend::class);
41
+        $this->defaults = $this->createMock(Defaults::class);
42
+        $this->defaultContactService = $this->createMock(DefaultContactService::class);
43
+        $this->userEventsListener = new UserEventsListener(
44
+            $this->userManager,
45
+            $this->syncService,
46
+            $this->calDavBackend,
47
+            $this->cardDavBackend,
48
+            $this->defaults,
49
+            $this->defaultContactService,
50
+        );
51
+    }
52
+
53
+    public function test(): void {
54
+        $user = $this->createMock(IUser::class);
55
+        $user->expects($this->once())->method('getUID')->willReturn('newUser');
56
+
57
+        $this->defaults->expects($this->once())->method('getColorPrimary')->willReturn('#745bca');
58
+
59
+        $this->calDavBackend->expects($this->once())->method('getCalendarsForUserCount')->willReturn(0);
60
+        $this->calDavBackend->expects($this->once())->method('createCalendar')->with(
61
+            'principals/users/newUser',
62
+            'personal', [
63
+                '{DAV:}displayname' => 'Personal',
64
+                '{http://apple.com/ns/ical/}calendar-color' => '#745bca',
65
+                'components' => 'VEVENT'
66
+            ]);
67
+
68
+        $this->cardDavBackend->expects($this->once())->method('getAddressBooksForUserCount')->willReturn(0);
69
+        $this->cardDavBackend->expects($this->once())->method('createAddressBook')->with(
70
+            'principals/users/newUser',
71
+            'contacts', ['{DAV:}displayname' => 'Contacts']);
72
+
73
+        $this->userEventsListener->firstLogin($user);
74
+    }
75
+
76
+    public function testWithExisting(): void {
77
+        $user = $this->createMock(IUser::class);
78
+        $user->expects($this->once())->method('getUID')->willReturn('newUser');
79
+
80
+        $this->calDavBackend->expects($this->once())->method('getCalendarsForUserCount')->willReturn(1);
81
+        $this->calDavBackend->expects($this->never())->method('createCalendar');
82
+
83
+        $this->cardDavBackend->expects($this->once())->method('getAddressBooksForUserCount')->willReturn(1);
84
+        $this->cardDavBackend->expects($this->never())->method('createAddressBook');
85
+
86
+        $this->userEventsListener->firstLogin($user);
87
+    }
88
+
89
+    public function testWithBirthdayCalendar(): void {
90
+        $user = $this->createMock(IUser::class);
91
+        $user->expects($this->once())->method('getUID')->willReturn('newUser');
92
+
93
+        $this->defaults->expects($this->once())->method('getColorPrimary')->willReturn('#745bca');
94
+
95
+        $this->calDavBackend->expects($this->once())->method('getCalendarsForUserCount')->willReturn(0);
96
+        $this->calDavBackend->expects($this->once())->method('createCalendar')->with(
97
+            'principals/users/newUser',
98
+            'personal', [
99
+                '{DAV:}displayname' => 'Personal',
100
+                '{http://apple.com/ns/ical/}calendar-color' => '#745bca',
101
+                'components' => 'VEVENT'
102
+            ]);
103
+
104
+        $this->cardDavBackend->expects($this->once())->method('getAddressBooksForUserCount')->willReturn(0);
105
+        $this->cardDavBackend->expects($this->once())->method('createAddressBook')->with(
106
+            'principals/users/newUser',
107
+            'contacts', ['{DAV:}displayname' => 'Contacts']);
108
+
109
+        $this->userEventsListener->firstLogin($user);
110
+    }
111
+
112
+    public function testDeleteCalendar(): void {
113
+        $user = $this->createMock(IUser::class);
114
+        $user->expects($this->once())->method('getUID')->willReturn('newUser');
115
+
116
+        $this->syncService->expects($this->once())
117
+            ->method('deleteUser');
118
+
119
+        $this->calDavBackend->expects($this->once())->method('getUsersOwnCalendars')->willReturn([
120
+            ['id' => 'personal']
121
+        ]);
122
+        $this->calDavBackend->expects($this->once())->method('getSubscriptionsForUser')->willReturn([
123
+            ['id' => 'some-subscription']
124
+        ]);
125
+        $this->calDavBackend->expects($this->once())->method('deleteCalendar')->with('personal');
126
+        $this->calDavBackend->expects($this->once())->method('deleteSubscription')->with('some-subscription');
127
+        $this->calDavBackend->expects($this->once())->method('deleteAllSharesByUser');
128
+
129
+        $this->cardDavBackend->expects($this->once())->method('getUsersOwnAddressBooks')->willReturn([
130
+            ['id' => 'personal']
131
+        ]);
132
+        $this->cardDavBackend->expects($this->once())->method('deleteAddressBook');
133
+
134
+        $this->userEventsListener->preDeleteUser($user);
135
+        $this->userEventsListener->postDeleteUser('newUser');
136
+    }
137 137
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/DAV/CustomPropertiesBackendTest.php 2 patches
Indentation   +438 added lines, -438 removed lines patch added patch discarded remove patch
@@ -28,442 +28,442 @@
 block discarded – undo
28 28
  * @group DB
29 29
  */
30 30
 class CustomPropertiesBackendTest extends TestCase {
31
-	private const BASE_URI = '/remote.php/dav/';
32
-
33
-	private Server&MockObject $server;
34
-	private Tree&MockObject $tree;
35
-	private IDBConnection $dbConnection;
36
-	private IUser&MockObject $user;
37
-	private DefaultCalendarValidator&MockObject $defaultCalendarValidator;
38
-	private CustomPropertiesBackend $backend;
39
-
40
-	protected function setUp(): void {
41
-		parent::setUp();
42
-
43
-		$this->server = $this->createMock(Server::class);
44
-		$this->server->method('getBaseUri')
45
-			->willReturn(self::BASE_URI);
46
-		$this->tree = $this->createMock(Tree::class);
47
-		$this->user = $this->createMock(IUser::class);
48
-		$this->user->method('getUID')
49
-			->with()
50
-			->willReturn('dummy_user_42');
51
-		$this->dbConnection = \OCP\Server::get(IDBConnection::class);
52
-		$this->defaultCalendarValidator = $this->createMock(DefaultCalendarValidator::class);
53
-
54
-		$this->backend = new CustomPropertiesBackend(
55
-			$this->server,
56
-			$this->tree,
57
-			$this->dbConnection,
58
-			$this->user,
59
-			$this->defaultCalendarValidator,
60
-		);
61
-	}
62
-
63
-	protected function tearDown(): void {
64
-		$query = $this->dbConnection->getQueryBuilder();
65
-		$query->delete('properties');
66
-		$query->execute();
67
-
68
-		parent::tearDown();
69
-	}
70
-
71
-	private function formatPath(string $path): string {
72
-		if (strlen($path) > 250) {
73
-			return sha1($path);
74
-		} else {
75
-			return $path;
76
-		}
77
-	}
78
-
79
-	protected function insertProps(string $user, string $path, array $props): void {
80
-		foreach ($props as $name => $value) {
81
-			$this->insertProp($user, $path, $name, $value);
82
-		}
83
-	}
84
-
85
-	protected function insertProp(string $user, string $path, string $name, mixed $value): void {
86
-		$type = CustomPropertiesBackend::PROPERTY_TYPE_STRING;
87
-		if ($value instanceof Href) {
88
-			$value = $value->getHref();
89
-			$type = CustomPropertiesBackend::PROPERTY_TYPE_HREF;
90
-		}
91
-
92
-		$query = $this->dbConnection->getQueryBuilder();
93
-		$query->insert('properties')
94
-			->values([
95
-				'userid' => $query->createNamedParameter($user),
96
-				'propertypath' => $query->createNamedParameter($this->formatPath($path)),
97
-				'propertyname' => $query->createNamedParameter($name),
98
-				'propertyvalue' => $query->createNamedParameter($value),
99
-				'valuetype' => $query->createNamedParameter($type, IQueryBuilder::PARAM_INT)
100
-			]);
101
-		$query->execute();
102
-	}
103
-
104
-	protected function getProps(string $user, string $path): array {
105
-		$query = $this->dbConnection->getQueryBuilder();
106
-		$query->select('propertyname', 'propertyvalue', 'valuetype')
107
-			->from('properties')
108
-			->where($query->expr()->eq('userid', $query->createNamedParameter($user)))
109
-			->andWhere($query->expr()->eq('propertypath', $query->createNamedParameter($this->formatPath($path))));
110
-
111
-		$result = $query->execute();
112
-		$data = [];
113
-		while ($row = $result->fetch()) {
114
-			$value = $row['propertyvalue'];
115
-			if ((int)$row['valuetype'] === CustomPropertiesBackend::PROPERTY_TYPE_HREF) {
116
-				$value = new Href($value);
117
-			}
118
-			$data[$row['propertyname']] = $value;
119
-		}
120
-		$result->closeCursor();
121
-
122
-		return $data;
123
-	}
124
-
125
-	public function testPropFindNoDbCalls(): void {
126
-		$db = $this->createMock(IDBConnection::class);
127
-		$backend = new CustomPropertiesBackend(
128
-			$this->server,
129
-			$this->tree,
130
-			$db,
131
-			$this->user,
132
-			$this->defaultCalendarValidator,
133
-		);
134
-
135
-		$propFind = $this->createMock(PropFind::class);
136
-		$propFind->expects($this->once())
137
-			->method('get404Properties')
138
-			->with()
139
-			->willReturn([
140
-				'{http://owncloud.org/ns}permissions',
141
-				'{http://owncloud.org/ns}downloadURL',
142
-				'{http://owncloud.org/ns}dDC',
143
-				'{http://owncloud.org/ns}size',
144
-			]);
145
-
146
-		$db->expects($this->never())
147
-			->method($this->anything());
148
-
149
-		$backend->propFind('foo_bar_path_1337_0', $propFind);
150
-	}
151
-
152
-	public function testPropFindCalendarCall(): void {
153
-		$propFind = $this->createMock(PropFind::class);
154
-		$propFind->method('get404Properties')
155
-			->with()
156
-			->willReturn([
157
-				'{DAV:}getcontentlength',
158
-				'{DAV:}getcontenttype',
159
-				'{DAV:}getetag',
160
-				'{abc}def',
161
-			]);
162
-
163
-		$propFind->method('getRequestedProperties')
164
-			->with()
165
-			->willReturn([
166
-				'{DAV:}getcontentlength',
167
-				'{DAV:}getcontenttype',
168
-				'{DAV:}getetag',
169
-				'{DAV:}displayname',
170
-				'{urn:ietf:params:xml:ns:caldav}calendar-description',
171
-				'{urn:ietf:params:xml:ns:caldav}calendar-timezone',
172
-				'{abc}def',
173
-			]);
174
-
175
-		$props = [
176
-			'{abc}def' => 'a',
177
-			'{DAV:}displayname' => 'b',
178
-			'{urn:ietf:params:xml:ns:caldav}calendar-description' => 'c',
179
-			'{urn:ietf:params:xml:ns:caldav}calendar-timezone' => 'd',
180
-		];
181
-
182
-		$this->insertProps('dummy_user_42', 'calendars/foo/bar_path_1337_0', $props);
183
-
184
-		$setProps = [];
185
-		$propFind->method('set')
186
-			->willReturnCallback(function ($name, $value, $status) use (&$setProps): void {
187
-				$setProps[$name] = $value;
188
-			});
189
-
190
-		$this->backend->propFind('calendars/foo/bar_path_1337_0', $propFind);
191
-		$this->assertEquals($props, $setProps);
192
-	}
193
-
194
-	public function testPropFindPrincipalCall(): void {
195
-		$this->tree->method('getNodeForPath')
196
-			->willReturnCallback(function ($uri) {
197
-				$node = $this->createMock(Calendar::class);
198
-				$node->method('getOwner')
199
-					->willReturn('principals/users/dummy_user_42');
200
-				return $node;
201
-			});
202
-
203
-		$propFind = $this->createMock(PropFind::class);
204
-		$propFind->method('get404Properties')
205
-			->with()
206
-			->willReturn([
207
-				'{DAV:}getcontentlength',
208
-				'{DAV:}getcontenttype',
209
-				'{DAV:}getetag',
210
-				'{abc}def',
211
-			]);
212
-
213
-		$propFind->method('getRequestedProperties')
214
-			->with()
215
-			->willReturn([
216
-				'{DAV:}getcontentlength',
217
-				'{DAV:}getcontenttype',
218
-				'{DAV:}getetag',
219
-				'{abc}def',
220
-				'{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL',
221
-			]);
222
-
223
-		$props = [
224
-			'{abc}def' => 'a',
225
-			'{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('calendars/admin/personal'),
226
-		];
227
-		$this->insertProps('dummy_user_42', 'principals/users/dummy_user_42', $props);
228
-
229
-		$setProps = [];
230
-		$propFind->method('set')
231
-			->willReturnCallback(function ($name, $value, $status) use (&$setProps): void {
232
-				$setProps[$name] = $value;
233
-			});
234
-
235
-		$this->backend->propFind('principals/users/dummy_user_42', $propFind);
236
-		$this->assertEquals($props, $setProps);
237
-	}
238
-
239
-	public static function propFindPrincipalScheduleDefaultCalendarProviderUrlProvider(): array {
240
-		// [ user, nodes, existingProps, requestedProps, returnedProps ]
241
-		return [
242
-			[ // Exists
243
-				'dummy_user_42',
244
-				['calendars/dummy_user_42/foo/' => Calendar::class],
245
-				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('calendars/dummy_user_42/foo/')],
246
-				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL'],
247
-				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('calendars/dummy_user_42/foo/')],
248
-			],
249
-			[ // Doesn't exist
250
-				'dummy_user_42',
251
-				['calendars/dummy_user_42/foo/' => Calendar::class],
252
-				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('calendars/dummy_user_42/bar/')],
253
-				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL'],
254
-				[],
255
-			],
256
-			[ // No privilege
257
-				'dummy_user_42',
258
-				['calendars/user2/baz/' => Calendar::class],
259
-				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('calendars/user2/baz/')],
260
-				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL'],
261
-				[],
262
-			],
263
-			[ // Not a calendar
264
-				'dummy_user_42',
265
-				['foo/dummy_user_42/bar/' => IACL::class],
266
-				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/dummy_user_42/bar/')],
267
-				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL'],
268
-				[],
269
-			],
270
-		];
271
-
272
-	}
273
-
274
-	/**
275
-	 * @dataProvider propFindPrincipalScheduleDefaultCalendarProviderUrlProvider
276
-	 */
277
-	public function testPropFindPrincipalScheduleDefaultCalendarUrl(
278
-		string $user,
279
-		array $nodes,
280
-		array $existingProps,
281
-		array $requestedProps,
282
-		array $returnedProps,
283
-	): void {
284
-		$propFind = $this->createMock(PropFind::class);
285
-		$propFind->method('get404Properties')
286
-			->with()
287
-			->willReturn([
288
-				'{DAV:}getcontentlength',
289
-				'{DAV:}getcontenttype',
290
-				'{DAV:}getetag',
291
-			]);
292
-
293
-		$propFind->method('getRequestedProperties')
294
-			->with()
295
-			->willReturn(array_merge([
296
-				'{DAV:}getcontentlength',
297
-				'{DAV:}getcontenttype',
298
-				'{DAV:}getetag',
299
-				'{abc}def',
300
-			],
301
-				$requestedProps,
302
-			));
303
-
304
-		$this->server->method('calculateUri')
305
-			->willReturnCallback(function ($uri) {
306
-				if (!str_starts_with($uri, self::BASE_URI)) {
307
-					return trim(substr($uri, strlen(self::BASE_URI)), '/');
308
-				}
309
-				return null;
310
-			});
311
-		$this->tree->method('getNodeForPath')
312
-			->willReturnCallback(function ($uri) use ($nodes) {
313
-				if (str_starts_with($uri, 'principals/')) {
314
-					return $this->createMock(IPrincipal::class);
315
-				}
316
-				if (array_key_exists($uri, $nodes)) {
317
-					$owner = explode('/', $uri)[1];
318
-					$node = $this->createMock($nodes[$uri]);
319
-					$node->method('getOwner')
320
-						->willReturn("principals/users/$owner");
321
-					return $node;
322
-				}
323
-				throw new NotFound('Node not found');
324
-			});
325
-
326
-		$this->insertProps($user, "principals/users/$user", $existingProps);
327
-
328
-		$setProps = [];
329
-		$propFind->method('set')
330
-			->willReturnCallback(function ($name, $value, $status) use (&$setProps): void {
331
-				$setProps[$name] = $value;
332
-			});
333
-
334
-		$this->backend->propFind("principals/users/$user", $propFind);
335
-		$this->assertEquals($returnedProps, $setProps);
336
-	}
337
-
338
-	/**
339
-	 * @dataProvider propPatchProvider
340
-	 */
341
-	public function testPropPatch(string $path, array $existing, array $props, array $result): void {
342
-		$this->server->method('calculateUri')
343
-			->willReturnCallback(function ($uri) {
344
-				if (str_starts_with($uri, self::BASE_URI)) {
345
-					return trim(substr($uri, strlen(self::BASE_URI)), '/');
346
-				}
347
-				return null;
348
-			});
349
-		$this->tree->method('getNodeForPath')
350
-			->willReturnCallback(function ($uri) {
351
-				$node = $this->createMock(Calendar::class);
352
-				$node->method('getOwner')
353
-					->willReturn('principals/users/' . $this->user->getUID());
354
-				return $node;
355
-			});
356
-
357
-		$this->insertProps($this->user->getUID(), $path, $existing);
358
-		$propPatch = new PropPatch($props);
359
-
360
-		$this->backend->propPatch($path, $propPatch);
361
-		$propPatch->commit();
362
-
363
-		$storedProps = $this->getProps($this->user->getUID(), $path);
364
-		$this->assertEquals($result, $storedProps);
365
-	}
366
-
367
-	public static function propPatchProvider(): array {
368
-		$longPath = str_repeat('long_path', 100);
369
-		return [
370
-			['foo_bar_path_1337', [], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
371
-			['foo_bar_path_1337', ['{DAV:}displayname' => 'foo'], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
372
-			['foo_bar_path_1337', ['{DAV:}displayname' => 'foo'], ['{DAV:}displayname' => null], []],
373
-			[$longPath, [], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
374
-			['principals/users/dummy_user_42', [], ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/bar/')], ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/bar/')]],
375
-			['principals/users/dummy_user_42', [], ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href(self::BASE_URI . 'foo/bar/')], ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/bar/')]],
376
-		];
377
-	}
378
-
379
-	public function testPropPatchWithUnsuitableCalendar(): void {
380
-		$path = 'principals/users/' . $this->user->getUID();
381
-
382
-		$node = $this->createMock(Calendar::class);
383
-		$node->expects(self::once())
384
-			->method('getOwner')
385
-			->willReturn($path);
386
-
387
-		$this->defaultCalendarValidator->expects(self::once())
388
-			->method('validateScheduleDefaultCalendar')
389
-			->with($node)
390
-			->willThrowException(new \Sabre\DAV\Exception('Invalid calendar'));
391
-
392
-		$this->server->method('calculateUri')
393
-			->willReturnCallback(function ($uri) {
394
-				if (str_starts_with($uri, self::BASE_URI)) {
395
-					return trim(substr($uri, strlen(self::BASE_URI)), '/');
396
-				}
397
-				return null;
398
-			});
399
-		$this->tree->expects(self::once())
400
-			->method('getNodeForPath')
401
-			->with('foo/bar/')
402
-			->willReturn($node);
403
-
404
-		$storedProps = $this->getProps($this->user->getUID(), $path);
405
-		$this->assertEquals([], $storedProps);
406
-
407
-		$propPatch = new PropPatch([
408
-			'{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/bar/'),
409
-		]);
410
-		$this->backend->propPatch($path, $propPatch);
411
-		try {
412
-			$propPatch->commit();
413
-		} catch (\Throwable $e) {
414
-			$this->assertInstanceOf(\Sabre\DAV\Exception::class, $e);
415
-		}
416
-
417
-		$storedProps = $this->getProps($this->user->getUID(), $path);
418
-		$this->assertEquals([], $storedProps);
419
-	}
420
-
421
-	/**
422
-	 * @dataProvider deleteProvider
423
-	 */
424
-	public function testDelete(string $path): void {
425
-		$this->insertProps('dummy_user_42', $path, ['foo' => 'bar']);
426
-		$this->backend->delete($path);
427
-		$this->assertEquals([], $this->getProps('dummy_user_42', $path));
428
-	}
429
-
430
-	public static function deleteProvider(): array {
431
-		return [
432
-			['foo_bar_path_1337'],
433
-			[str_repeat('long_path', 100)]
434
-		];
435
-	}
436
-
437
-	/**
438
-	 * @dataProvider moveProvider
439
-	 */
440
-	public function testMove(string $source, string $target): void {
441
-		$this->insertProps('dummy_user_42', $source, ['foo' => 'bar']);
442
-		$this->backend->move($source, $target);
443
-		$this->assertEquals([], $this->getProps('dummy_user_42', $source));
444
-		$this->assertEquals(['foo' => 'bar'], $this->getProps('dummy_user_42', $target));
445
-	}
446
-
447
-	public static function moveProvider(): array {
448
-		return [
449
-			['foo_bar_path_1337', 'foo_bar_path_7333'],
450
-			[str_repeat('long_path1', 100), str_repeat('long_path2', 100)]
451
-		];
452
-	}
453
-
454
-	public function testDecodeValueFromDatabaseObjectCurrent(): void {
455
-		$propertyValue = 'O:48:"Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp":1:{s:8:"\x00*\x00value";s:6:"opaque";}';
456
-		$propertyType = 3;
457
-		$decodeValue = $this->invokePrivate($this->backend, 'decodeValueFromDatabase', [$propertyValue, $propertyType]);
458
-		$this->assertInstanceOf(\Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp::class, $decodeValue);
459
-		$this->assertEquals('opaque', $decodeValue->getValue());
460
-	}
461
-
462
-	public function testDecodeValueFromDatabaseObjectLegacy(): void {
463
-		$propertyValue = 'O:48:"Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp":1:{s:8:"' . chr(0) . '*' . chr(0) . 'value";s:6:"opaque";}';
464
-		$propertyType = 3;
465
-		$decodeValue = $this->invokePrivate($this->backend, 'decodeValueFromDatabase', [$propertyValue, $propertyType]);
466
-		$this->assertInstanceOf(\Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp::class, $decodeValue);
467
-		$this->assertEquals('opaque', $decodeValue->getValue());
468
-	}
31
+    private const BASE_URI = '/remote.php/dav/';
32
+
33
+    private Server&MockObject $server;
34
+    private Tree&MockObject $tree;
35
+    private IDBConnection $dbConnection;
36
+    private IUser&MockObject $user;
37
+    private DefaultCalendarValidator&MockObject $defaultCalendarValidator;
38
+    private CustomPropertiesBackend $backend;
39
+
40
+    protected function setUp(): void {
41
+        parent::setUp();
42
+
43
+        $this->server = $this->createMock(Server::class);
44
+        $this->server->method('getBaseUri')
45
+            ->willReturn(self::BASE_URI);
46
+        $this->tree = $this->createMock(Tree::class);
47
+        $this->user = $this->createMock(IUser::class);
48
+        $this->user->method('getUID')
49
+            ->with()
50
+            ->willReturn('dummy_user_42');
51
+        $this->dbConnection = \OCP\Server::get(IDBConnection::class);
52
+        $this->defaultCalendarValidator = $this->createMock(DefaultCalendarValidator::class);
53
+
54
+        $this->backend = new CustomPropertiesBackend(
55
+            $this->server,
56
+            $this->tree,
57
+            $this->dbConnection,
58
+            $this->user,
59
+            $this->defaultCalendarValidator,
60
+        );
61
+    }
62
+
63
+    protected function tearDown(): void {
64
+        $query = $this->dbConnection->getQueryBuilder();
65
+        $query->delete('properties');
66
+        $query->execute();
67
+
68
+        parent::tearDown();
69
+    }
70
+
71
+    private function formatPath(string $path): string {
72
+        if (strlen($path) > 250) {
73
+            return sha1($path);
74
+        } else {
75
+            return $path;
76
+        }
77
+    }
78
+
79
+    protected function insertProps(string $user, string $path, array $props): void {
80
+        foreach ($props as $name => $value) {
81
+            $this->insertProp($user, $path, $name, $value);
82
+        }
83
+    }
84
+
85
+    protected function insertProp(string $user, string $path, string $name, mixed $value): void {
86
+        $type = CustomPropertiesBackend::PROPERTY_TYPE_STRING;
87
+        if ($value instanceof Href) {
88
+            $value = $value->getHref();
89
+            $type = CustomPropertiesBackend::PROPERTY_TYPE_HREF;
90
+        }
91
+
92
+        $query = $this->dbConnection->getQueryBuilder();
93
+        $query->insert('properties')
94
+            ->values([
95
+                'userid' => $query->createNamedParameter($user),
96
+                'propertypath' => $query->createNamedParameter($this->formatPath($path)),
97
+                'propertyname' => $query->createNamedParameter($name),
98
+                'propertyvalue' => $query->createNamedParameter($value),
99
+                'valuetype' => $query->createNamedParameter($type, IQueryBuilder::PARAM_INT)
100
+            ]);
101
+        $query->execute();
102
+    }
103
+
104
+    protected function getProps(string $user, string $path): array {
105
+        $query = $this->dbConnection->getQueryBuilder();
106
+        $query->select('propertyname', 'propertyvalue', 'valuetype')
107
+            ->from('properties')
108
+            ->where($query->expr()->eq('userid', $query->createNamedParameter($user)))
109
+            ->andWhere($query->expr()->eq('propertypath', $query->createNamedParameter($this->formatPath($path))));
110
+
111
+        $result = $query->execute();
112
+        $data = [];
113
+        while ($row = $result->fetch()) {
114
+            $value = $row['propertyvalue'];
115
+            if ((int)$row['valuetype'] === CustomPropertiesBackend::PROPERTY_TYPE_HREF) {
116
+                $value = new Href($value);
117
+            }
118
+            $data[$row['propertyname']] = $value;
119
+        }
120
+        $result->closeCursor();
121
+
122
+        return $data;
123
+    }
124
+
125
+    public function testPropFindNoDbCalls(): void {
126
+        $db = $this->createMock(IDBConnection::class);
127
+        $backend = new CustomPropertiesBackend(
128
+            $this->server,
129
+            $this->tree,
130
+            $db,
131
+            $this->user,
132
+            $this->defaultCalendarValidator,
133
+        );
134
+
135
+        $propFind = $this->createMock(PropFind::class);
136
+        $propFind->expects($this->once())
137
+            ->method('get404Properties')
138
+            ->with()
139
+            ->willReturn([
140
+                '{http://owncloud.org/ns}permissions',
141
+                '{http://owncloud.org/ns}downloadURL',
142
+                '{http://owncloud.org/ns}dDC',
143
+                '{http://owncloud.org/ns}size',
144
+            ]);
145
+
146
+        $db->expects($this->never())
147
+            ->method($this->anything());
148
+
149
+        $backend->propFind('foo_bar_path_1337_0', $propFind);
150
+    }
151
+
152
+    public function testPropFindCalendarCall(): void {
153
+        $propFind = $this->createMock(PropFind::class);
154
+        $propFind->method('get404Properties')
155
+            ->with()
156
+            ->willReturn([
157
+                '{DAV:}getcontentlength',
158
+                '{DAV:}getcontenttype',
159
+                '{DAV:}getetag',
160
+                '{abc}def',
161
+            ]);
162
+
163
+        $propFind->method('getRequestedProperties')
164
+            ->with()
165
+            ->willReturn([
166
+                '{DAV:}getcontentlength',
167
+                '{DAV:}getcontenttype',
168
+                '{DAV:}getetag',
169
+                '{DAV:}displayname',
170
+                '{urn:ietf:params:xml:ns:caldav}calendar-description',
171
+                '{urn:ietf:params:xml:ns:caldav}calendar-timezone',
172
+                '{abc}def',
173
+            ]);
174
+
175
+        $props = [
176
+            '{abc}def' => 'a',
177
+            '{DAV:}displayname' => 'b',
178
+            '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'c',
179
+            '{urn:ietf:params:xml:ns:caldav}calendar-timezone' => 'd',
180
+        ];
181
+
182
+        $this->insertProps('dummy_user_42', 'calendars/foo/bar_path_1337_0', $props);
183
+
184
+        $setProps = [];
185
+        $propFind->method('set')
186
+            ->willReturnCallback(function ($name, $value, $status) use (&$setProps): void {
187
+                $setProps[$name] = $value;
188
+            });
189
+
190
+        $this->backend->propFind('calendars/foo/bar_path_1337_0', $propFind);
191
+        $this->assertEquals($props, $setProps);
192
+    }
193
+
194
+    public function testPropFindPrincipalCall(): void {
195
+        $this->tree->method('getNodeForPath')
196
+            ->willReturnCallback(function ($uri) {
197
+                $node = $this->createMock(Calendar::class);
198
+                $node->method('getOwner')
199
+                    ->willReturn('principals/users/dummy_user_42');
200
+                return $node;
201
+            });
202
+
203
+        $propFind = $this->createMock(PropFind::class);
204
+        $propFind->method('get404Properties')
205
+            ->with()
206
+            ->willReturn([
207
+                '{DAV:}getcontentlength',
208
+                '{DAV:}getcontenttype',
209
+                '{DAV:}getetag',
210
+                '{abc}def',
211
+            ]);
212
+
213
+        $propFind->method('getRequestedProperties')
214
+            ->with()
215
+            ->willReturn([
216
+                '{DAV:}getcontentlength',
217
+                '{DAV:}getcontenttype',
218
+                '{DAV:}getetag',
219
+                '{abc}def',
220
+                '{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL',
221
+            ]);
222
+
223
+        $props = [
224
+            '{abc}def' => 'a',
225
+            '{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('calendars/admin/personal'),
226
+        ];
227
+        $this->insertProps('dummy_user_42', 'principals/users/dummy_user_42', $props);
228
+
229
+        $setProps = [];
230
+        $propFind->method('set')
231
+            ->willReturnCallback(function ($name, $value, $status) use (&$setProps): void {
232
+                $setProps[$name] = $value;
233
+            });
234
+
235
+        $this->backend->propFind('principals/users/dummy_user_42', $propFind);
236
+        $this->assertEquals($props, $setProps);
237
+    }
238
+
239
+    public static function propFindPrincipalScheduleDefaultCalendarProviderUrlProvider(): array {
240
+        // [ user, nodes, existingProps, requestedProps, returnedProps ]
241
+        return [
242
+            [ // Exists
243
+                'dummy_user_42',
244
+                ['calendars/dummy_user_42/foo/' => Calendar::class],
245
+                ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('calendars/dummy_user_42/foo/')],
246
+                ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL'],
247
+                ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('calendars/dummy_user_42/foo/')],
248
+            ],
249
+            [ // Doesn't exist
250
+                'dummy_user_42',
251
+                ['calendars/dummy_user_42/foo/' => Calendar::class],
252
+                ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('calendars/dummy_user_42/bar/')],
253
+                ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL'],
254
+                [],
255
+            ],
256
+            [ // No privilege
257
+                'dummy_user_42',
258
+                ['calendars/user2/baz/' => Calendar::class],
259
+                ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('calendars/user2/baz/')],
260
+                ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL'],
261
+                [],
262
+            ],
263
+            [ // Not a calendar
264
+                'dummy_user_42',
265
+                ['foo/dummy_user_42/bar/' => IACL::class],
266
+                ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/dummy_user_42/bar/')],
267
+                ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL'],
268
+                [],
269
+            ],
270
+        ];
271
+
272
+    }
273
+
274
+    /**
275
+     * @dataProvider propFindPrincipalScheduleDefaultCalendarProviderUrlProvider
276
+     */
277
+    public function testPropFindPrincipalScheduleDefaultCalendarUrl(
278
+        string $user,
279
+        array $nodes,
280
+        array $existingProps,
281
+        array $requestedProps,
282
+        array $returnedProps,
283
+    ): void {
284
+        $propFind = $this->createMock(PropFind::class);
285
+        $propFind->method('get404Properties')
286
+            ->with()
287
+            ->willReturn([
288
+                '{DAV:}getcontentlength',
289
+                '{DAV:}getcontenttype',
290
+                '{DAV:}getetag',
291
+            ]);
292
+
293
+        $propFind->method('getRequestedProperties')
294
+            ->with()
295
+            ->willReturn(array_merge([
296
+                '{DAV:}getcontentlength',
297
+                '{DAV:}getcontenttype',
298
+                '{DAV:}getetag',
299
+                '{abc}def',
300
+            ],
301
+                $requestedProps,
302
+            ));
303
+
304
+        $this->server->method('calculateUri')
305
+            ->willReturnCallback(function ($uri) {
306
+                if (!str_starts_with($uri, self::BASE_URI)) {
307
+                    return trim(substr($uri, strlen(self::BASE_URI)), '/');
308
+                }
309
+                return null;
310
+            });
311
+        $this->tree->method('getNodeForPath')
312
+            ->willReturnCallback(function ($uri) use ($nodes) {
313
+                if (str_starts_with($uri, 'principals/')) {
314
+                    return $this->createMock(IPrincipal::class);
315
+                }
316
+                if (array_key_exists($uri, $nodes)) {
317
+                    $owner = explode('/', $uri)[1];
318
+                    $node = $this->createMock($nodes[$uri]);
319
+                    $node->method('getOwner')
320
+                        ->willReturn("principals/users/$owner");
321
+                    return $node;
322
+                }
323
+                throw new NotFound('Node not found');
324
+            });
325
+
326
+        $this->insertProps($user, "principals/users/$user", $existingProps);
327
+
328
+        $setProps = [];
329
+        $propFind->method('set')
330
+            ->willReturnCallback(function ($name, $value, $status) use (&$setProps): void {
331
+                $setProps[$name] = $value;
332
+            });
333
+
334
+        $this->backend->propFind("principals/users/$user", $propFind);
335
+        $this->assertEquals($returnedProps, $setProps);
336
+    }
337
+
338
+    /**
339
+     * @dataProvider propPatchProvider
340
+     */
341
+    public function testPropPatch(string $path, array $existing, array $props, array $result): void {
342
+        $this->server->method('calculateUri')
343
+            ->willReturnCallback(function ($uri) {
344
+                if (str_starts_with($uri, self::BASE_URI)) {
345
+                    return trim(substr($uri, strlen(self::BASE_URI)), '/');
346
+                }
347
+                return null;
348
+            });
349
+        $this->tree->method('getNodeForPath')
350
+            ->willReturnCallback(function ($uri) {
351
+                $node = $this->createMock(Calendar::class);
352
+                $node->method('getOwner')
353
+                    ->willReturn('principals/users/' . $this->user->getUID());
354
+                return $node;
355
+            });
356
+
357
+        $this->insertProps($this->user->getUID(), $path, $existing);
358
+        $propPatch = new PropPatch($props);
359
+
360
+        $this->backend->propPatch($path, $propPatch);
361
+        $propPatch->commit();
362
+
363
+        $storedProps = $this->getProps($this->user->getUID(), $path);
364
+        $this->assertEquals($result, $storedProps);
365
+    }
366
+
367
+    public static function propPatchProvider(): array {
368
+        $longPath = str_repeat('long_path', 100);
369
+        return [
370
+            ['foo_bar_path_1337', [], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
371
+            ['foo_bar_path_1337', ['{DAV:}displayname' => 'foo'], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
372
+            ['foo_bar_path_1337', ['{DAV:}displayname' => 'foo'], ['{DAV:}displayname' => null], []],
373
+            [$longPath, [], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
374
+            ['principals/users/dummy_user_42', [], ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/bar/')], ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/bar/')]],
375
+            ['principals/users/dummy_user_42', [], ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href(self::BASE_URI . 'foo/bar/')], ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/bar/')]],
376
+        ];
377
+    }
378
+
379
+    public function testPropPatchWithUnsuitableCalendar(): void {
380
+        $path = 'principals/users/' . $this->user->getUID();
381
+
382
+        $node = $this->createMock(Calendar::class);
383
+        $node->expects(self::once())
384
+            ->method('getOwner')
385
+            ->willReturn($path);
386
+
387
+        $this->defaultCalendarValidator->expects(self::once())
388
+            ->method('validateScheduleDefaultCalendar')
389
+            ->with($node)
390
+            ->willThrowException(new \Sabre\DAV\Exception('Invalid calendar'));
391
+
392
+        $this->server->method('calculateUri')
393
+            ->willReturnCallback(function ($uri) {
394
+                if (str_starts_with($uri, self::BASE_URI)) {
395
+                    return trim(substr($uri, strlen(self::BASE_URI)), '/');
396
+                }
397
+                return null;
398
+            });
399
+        $this->tree->expects(self::once())
400
+            ->method('getNodeForPath')
401
+            ->with('foo/bar/')
402
+            ->willReturn($node);
403
+
404
+        $storedProps = $this->getProps($this->user->getUID(), $path);
405
+        $this->assertEquals([], $storedProps);
406
+
407
+        $propPatch = new PropPatch([
408
+            '{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/bar/'),
409
+        ]);
410
+        $this->backend->propPatch($path, $propPatch);
411
+        try {
412
+            $propPatch->commit();
413
+        } catch (\Throwable $e) {
414
+            $this->assertInstanceOf(\Sabre\DAV\Exception::class, $e);
415
+        }
416
+
417
+        $storedProps = $this->getProps($this->user->getUID(), $path);
418
+        $this->assertEquals([], $storedProps);
419
+    }
420
+
421
+    /**
422
+     * @dataProvider deleteProvider
423
+     */
424
+    public function testDelete(string $path): void {
425
+        $this->insertProps('dummy_user_42', $path, ['foo' => 'bar']);
426
+        $this->backend->delete($path);
427
+        $this->assertEquals([], $this->getProps('dummy_user_42', $path));
428
+    }
429
+
430
+    public static function deleteProvider(): array {
431
+        return [
432
+            ['foo_bar_path_1337'],
433
+            [str_repeat('long_path', 100)]
434
+        ];
435
+    }
436
+
437
+    /**
438
+     * @dataProvider moveProvider
439
+     */
440
+    public function testMove(string $source, string $target): void {
441
+        $this->insertProps('dummy_user_42', $source, ['foo' => 'bar']);
442
+        $this->backend->move($source, $target);
443
+        $this->assertEquals([], $this->getProps('dummy_user_42', $source));
444
+        $this->assertEquals(['foo' => 'bar'], $this->getProps('dummy_user_42', $target));
445
+    }
446
+
447
+    public static function moveProvider(): array {
448
+        return [
449
+            ['foo_bar_path_1337', 'foo_bar_path_7333'],
450
+            [str_repeat('long_path1', 100), str_repeat('long_path2', 100)]
451
+        ];
452
+    }
453
+
454
+    public function testDecodeValueFromDatabaseObjectCurrent(): void {
455
+        $propertyValue = 'O:48:"Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp":1:{s:8:"\x00*\x00value";s:6:"opaque";}';
456
+        $propertyType = 3;
457
+        $decodeValue = $this->invokePrivate($this->backend, 'decodeValueFromDatabase', [$propertyValue, $propertyType]);
458
+        $this->assertInstanceOf(\Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp::class, $decodeValue);
459
+        $this->assertEquals('opaque', $decodeValue->getValue());
460
+    }
461
+
462
+    public function testDecodeValueFromDatabaseObjectLegacy(): void {
463
+        $propertyValue = 'O:48:"Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp":1:{s:8:"' . chr(0) . '*' . chr(0) . 'value";s:6:"opaque";}';
464
+        $propertyType = 3;
465
+        $decodeValue = $this->invokePrivate($this->backend, 'decodeValueFromDatabase', [$propertyValue, $propertyType]);
466
+        $this->assertInstanceOf(\Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp::class, $decodeValue);
467
+        $this->assertEquals('opaque', $decodeValue->getValue());
468
+    }
469 469
 }
Please login to merge, or discard this patch.
Spacing   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -112,7 +112,7 @@  discard block
 block discarded – undo
112 112
 		$data = [];
113 113
 		while ($row = $result->fetch()) {
114 114
 			$value = $row['propertyvalue'];
115
-			if ((int)$row['valuetype'] === CustomPropertiesBackend::PROPERTY_TYPE_HREF) {
115
+			if ((int) $row['valuetype'] === CustomPropertiesBackend::PROPERTY_TYPE_HREF) {
116 116
 				$value = new Href($value);
117 117
 			}
118 118
 			$data[$row['propertyname']] = $value;
@@ -183,7 +183,7 @@  discard block
 block discarded – undo
183 183
 
184 184
 		$setProps = [];
185 185
 		$propFind->method('set')
186
-			->willReturnCallback(function ($name, $value, $status) use (&$setProps): void {
186
+			->willReturnCallback(function($name, $value, $status) use (&$setProps): void {
187 187
 				$setProps[$name] = $value;
188 188
 			});
189 189
 
@@ -193,7 +193,7 @@  discard block
 block discarded – undo
193 193
 
194 194
 	public function testPropFindPrincipalCall(): void {
195 195
 		$this->tree->method('getNodeForPath')
196
-			->willReturnCallback(function ($uri) {
196
+			->willReturnCallback(function($uri) {
197 197
 				$node = $this->createMock(Calendar::class);
198 198
 				$node->method('getOwner')
199 199
 					->willReturn('principals/users/dummy_user_42');
@@ -228,7 +228,7 @@  discard block
 block discarded – undo
228 228
 
229 229
 		$setProps = [];
230 230
 		$propFind->method('set')
231
-			->willReturnCallback(function ($name, $value, $status) use (&$setProps): void {
231
+			->willReturnCallback(function($name, $value, $status) use (&$setProps): void {
232 232
 				$setProps[$name] = $value;
233 233
 			});
234 234
 
@@ -239,28 +239,28 @@  discard block
 block discarded – undo
239 239
 	public static function propFindPrincipalScheduleDefaultCalendarProviderUrlProvider(): array {
240 240
 		// [ user, nodes, existingProps, requestedProps, returnedProps ]
241 241
 		return [
242
-			[ // Exists
242
+			[// Exists
243 243
 				'dummy_user_42',
244 244
 				['calendars/dummy_user_42/foo/' => Calendar::class],
245 245
 				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('calendars/dummy_user_42/foo/')],
246 246
 				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL'],
247 247
 				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('calendars/dummy_user_42/foo/')],
248 248
 			],
249
-			[ // Doesn't exist
249
+			[// Doesn't exist
250 250
 				'dummy_user_42',
251 251
 				['calendars/dummy_user_42/foo/' => Calendar::class],
252 252
 				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('calendars/dummy_user_42/bar/')],
253 253
 				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL'],
254 254
 				[],
255 255
 			],
256
-			[ // No privilege
256
+			[// No privilege
257 257
 				'dummy_user_42',
258 258
 				['calendars/user2/baz/' => Calendar::class],
259 259
 				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('calendars/user2/baz/')],
260 260
 				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL'],
261 261
 				[],
262 262
 			],
263
-			[ // Not a calendar
263
+			[// Not a calendar
264 264
 				'dummy_user_42',
265 265
 				['foo/dummy_user_42/bar/' => IACL::class],
266 266
 				['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/dummy_user_42/bar/')],
@@ -302,14 +302,14 @@  discard block
 block discarded – undo
302 302
 			));
303 303
 
304 304
 		$this->server->method('calculateUri')
305
-			->willReturnCallback(function ($uri) {
305
+			->willReturnCallback(function($uri) {
306 306
 				if (!str_starts_with($uri, self::BASE_URI)) {
307 307
 					return trim(substr($uri, strlen(self::BASE_URI)), '/');
308 308
 				}
309 309
 				return null;
310 310
 			});
311 311
 		$this->tree->method('getNodeForPath')
312
-			->willReturnCallback(function ($uri) use ($nodes) {
312
+			->willReturnCallback(function($uri) use ($nodes) {
313 313
 				if (str_starts_with($uri, 'principals/')) {
314 314
 					return $this->createMock(IPrincipal::class);
315 315
 				}
@@ -327,7 +327,7 @@  discard block
 block discarded – undo
327 327
 
328 328
 		$setProps = [];
329 329
 		$propFind->method('set')
330
-			->willReturnCallback(function ($name, $value, $status) use (&$setProps): void {
330
+			->willReturnCallback(function($name, $value, $status) use (&$setProps): void {
331 331
 				$setProps[$name] = $value;
332 332
 			});
333 333
 
@@ -340,17 +340,17 @@  discard block
 block discarded – undo
340 340
 	 */
341 341
 	public function testPropPatch(string $path, array $existing, array $props, array $result): void {
342 342
 		$this->server->method('calculateUri')
343
-			->willReturnCallback(function ($uri) {
343
+			->willReturnCallback(function($uri) {
344 344
 				if (str_starts_with($uri, self::BASE_URI)) {
345 345
 					return trim(substr($uri, strlen(self::BASE_URI)), '/');
346 346
 				}
347 347
 				return null;
348 348
 			});
349 349
 		$this->tree->method('getNodeForPath')
350
-			->willReturnCallback(function ($uri) {
350
+			->willReturnCallback(function($uri) {
351 351
 				$node = $this->createMock(Calendar::class);
352 352
 				$node->method('getOwner')
353
-					->willReturn('principals/users/' . $this->user->getUID());
353
+					->willReturn('principals/users/'.$this->user->getUID());
354 354
 				return $node;
355 355
 			});
356 356
 
@@ -372,12 +372,12 @@  discard block
 block discarded – undo
372 372
 			['foo_bar_path_1337', ['{DAV:}displayname' => 'foo'], ['{DAV:}displayname' => null], []],
373 373
 			[$longPath, [], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
374 374
 			['principals/users/dummy_user_42', [], ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/bar/')], ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/bar/')]],
375
-			['principals/users/dummy_user_42', [], ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href(self::BASE_URI . 'foo/bar/')], ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/bar/')]],
375
+			['principals/users/dummy_user_42', [], ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href(self::BASE_URI.'foo/bar/')], ['{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/bar/')]],
376 376
 		];
377 377
 	}
378 378
 
379 379
 	public function testPropPatchWithUnsuitableCalendar(): void {
380
-		$path = 'principals/users/' . $this->user->getUID();
380
+		$path = 'principals/users/'.$this->user->getUID();
381 381
 
382 382
 		$node = $this->createMock(Calendar::class);
383 383
 		$node->expects(self::once())
@@ -390,7 +390,7 @@  discard block
 block discarded – undo
390 390
 			->willThrowException(new \Sabre\DAV\Exception('Invalid calendar'));
391 391
 
392 392
 		$this->server->method('calculateUri')
393
-			->willReturnCallback(function ($uri) {
393
+			->willReturnCallback(function($uri) {
394 394
 				if (str_starts_with($uri, self::BASE_URI)) {
395 395
 					return trim(substr($uri, strlen(self::BASE_URI)), '/');
396 396
 				}
@@ -460,7 +460,7 @@  discard block
 block discarded – undo
460 460
 	}
461 461
 
462 462
 	public function testDecodeValueFromDatabaseObjectLegacy(): void {
463
-		$propertyValue = 'O:48:"Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp":1:{s:8:"' . chr(0) . '*' . chr(0) . 'value";s:6:"opaque";}';
463
+		$propertyValue = 'O:48:"Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp":1:{s:8:"'.chr(0).'*'.chr(0).'value";s:6:"opaque";}';
464 464
 		$propertyType = 3;
465 465
 		$decodeValue = $this->invokePrivate($this->backend, 'decodeValueFromDatabase', [$propertyValue, $propertyType]);
466 466
 		$this->assertInstanceOf(\Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp::class, $decodeValue);
Please login to merge, or discard this patch.
apps/dav/tests/unit/DAV/ViewOnlyPluginTest.php 1 patch
Indentation   +128 added lines, -128 removed lines patch added patch discarded remove patch
@@ -28,132 +28,132 @@
 block discarded – undo
28 28
 use Test\TestCase;
29 29
 
30 30
 class ViewOnlyPluginTest extends TestCase {
31
-	private Tree&MockObject $tree;
32
-	private RequestInterface&MockObject $request;
33
-	private Folder&MockObject $userFolder;
34
-	private ViewOnlyPlugin $plugin;
35
-
36
-	public function setUp(): void {
37
-		parent::setUp();
38
-
39
-		$this->userFolder = $this->createMock(Folder::class);
40
-		$this->request = $this->createMock(RequestInterface::class);
41
-		$this->tree = $this->createMock(Tree::class);
42
-		$server = $this->createMock(Server::class);
43
-
44
-		$this->plugin = new ViewOnlyPlugin(
45
-			$this->userFolder,
46
-		);
47
-		$server->tree = $this->tree;
48
-
49
-		$this->plugin->initialize($server);
50
-	}
51
-
52
-	public function testCanGetNonDav(): void {
53
-		$this->request->expects($this->once())->method('getPath')->willReturn('files/test/target');
54
-		$this->tree->method('getNodeForPath')->willReturn(null);
55
-
56
-		$this->assertTrue($this->plugin->checkViewOnly($this->request));
57
-	}
58
-
59
-	public function testCanGetNonShared(): void {
60
-		$this->request->expects($this->once())->method('getPath')->willReturn('files/test/target');
61
-		$davNode = $this->createMock(DavFile::class);
62
-		$this->tree->method('getNodeForPath')->willReturn($davNode);
63
-
64
-		$file = $this->createMock(File::class);
65
-		$davNode->method('getNode')->willReturn($file);
66
-
67
-		$storage = $this->createMock(IStorage::class);
68
-		$file->method('getStorage')->willReturn($storage);
69
-		$storage->method('instanceOfStorage')->with(ISharedStorage::class)->willReturn(false);
70
-
71
-		$this->assertTrue($this->plugin->checkViewOnly($this->request));
72
-	}
73
-
74
-	public static function providesDataForCanGet(): array {
75
-		return [
76
-			// has attribute permissions-download enabled - can get file
77
-			[false, true, true],
78
-			// has no attribute permissions-download - can get file
79
-			[false, null, true],
80
-			// has attribute permissions-download disabled- cannot get the file
81
-			[false, false, false],
82
-			// has attribute permissions-download enabled - can get file version
83
-			[true, true, true],
84
-			// has no attribute permissions-download - can get file version
85
-			[true, null, true],
86
-			// has attribute permissions-download disabled- cannot get the file version
87
-			[true, false, false],
88
-		];
89
-	}
90
-
91
-	/**
92
-	 * @dataProvider providesDataForCanGet
93
-	 */
94
-	public function testCanGet(bool $isVersion, ?bool $attrEnabled, bool $expectCanDownloadFile): void {
95
-		$nodeInfo = $this->createMock(File::class);
96
-		if ($isVersion) {
97
-			$davPath = 'versions/alice/versions/117/123456';
98
-			$version = $this->createMock(IVersion::class);
99
-			$version->expects($this->once())
100
-				->method('getSourceFile')
101
-				->willReturn($nodeInfo);
102
-			$davNode = $this->createMock(VersionFile::class);
103
-			$davNode->expects($this->once())
104
-				->method('getVersion')
105
-				->willReturn($version);
106
-
107
-			$currentUser = $this->createMock(IUser::class);
108
-			$currentUser->expects($this->once())
109
-				->method('getUID')
110
-				->willReturn('alice');
111
-			$nodeInfo->expects($this->once())
112
-				->method('getOwner')
113
-				->willReturn($currentUser);
114
-
115
-			$nodeInfo = $this->createMock(File::class);
116
-			$owner = $this->createMock(IUser::class);
117
-			$owner->expects($this->once())
118
-				->method('getUID')
119
-				->willReturn('bob');
120
-			$this->userFolder->expects($this->once())
121
-				->method('getById')
122
-				->willReturn([$nodeInfo]);
123
-			$this->userFolder->expects($this->once())
124
-				->method('getOwner')
125
-				->willReturn($owner);
126
-		} else {
127
-			$davPath = 'files/path/to/file.odt';
128
-			$davNode = $this->createMock(DavFile::class);
129
-			$davNode->method('getNode')->willReturn($nodeInfo);
130
-		}
131
-
132
-		$this->request->expects($this->once())->method('getPath')->willReturn($davPath);
133
-
134
-		$this->tree->expects($this->once())
135
-			->method('getNodeForPath')
136
-			->with($davPath)
137
-			->willReturn($davNode);
138
-
139
-		$storage = $this->createMock(SharedStorage::class);
140
-		$share = $this->createMock(IShare::class);
141
-		$nodeInfo->expects($this->once())
142
-			->method('getStorage')
143
-			->willReturn($storage);
144
-		$storage->method('instanceOfStorage')->with(ISharedStorage::class)->willReturn(true);
145
-		$storage->method('getShare')->willReturn($share);
146
-
147
-		$extAttr = $this->createMock(IAttributes::class);
148
-		$share->method('getAttributes')->willReturn($extAttr);
149
-		$extAttr->expects($this->once())
150
-			->method('getAttribute')
151
-			->with('permissions', 'download')
152
-			->willReturn($attrEnabled);
153
-
154
-		if (!$expectCanDownloadFile) {
155
-			$this->expectException(Forbidden::class);
156
-		}
157
-		$this->plugin->checkViewOnly($this->request);
158
-	}
31
+    private Tree&MockObject $tree;
32
+    private RequestInterface&MockObject $request;
33
+    private Folder&MockObject $userFolder;
34
+    private ViewOnlyPlugin $plugin;
35
+
36
+    public function setUp(): void {
37
+        parent::setUp();
38
+
39
+        $this->userFolder = $this->createMock(Folder::class);
40
+        $this->request = $this->createMock(RequestInterface::class);
41
+        $this->tree = $this->createMock(Tree::class);
42
+        $server = $this->createMock(Server::class);
43
+
44
+        $this->plugin = new ViewOnlyPlugin(
45
+            $this->userFolder,
46
+        );
47
+        $server->tree = $this->tree;
48
+
49
+        $this->plugin->initialize($server);
50
+    }
51
+
52
+    public function testCanGetNonDav(): void {
53
+        $this->request->expects($this->once())->method('getPath')->willReturn('files/test/target');
54
+        $this->tree->method('getNodeForPath')->willReturn(null);
55
+
56
+        $this->assertTrue($this->plugin->checkViewOnly($this->request));
57
+    }
58
+
59
+    public function testCanGetNonShared(): void {
60
+        $this->request->expects($this->once())->method('getPath')->willReturn('files/test/target');
61
+        $davNode = $this->createMock(DavFile::class);
62
+        $this->tree->method('getNodeForPath')->willReturn($davNode);
63
+
64
+        $file = $this->createMock(File::class);
65
+        $davNode->method('getNode')->willReturn($file);
66
+
67
+        $storage = $this->createMock(IStorage::class);
68
+        $file->method('getStorage')->willReturn($storage);
69
+        $storage->method('instanceOfStorage')->with(ISharedStorage::class)->willReturn(false);
70
+
71
+        $this->assertTrue($this->plugin->checkViewOnly($this->request));
72
+    }
73
+
74
+    public static function providesDataForCanGet(): array {
75
+        return [
76
+            // has attribute permissions-download enabled - can get file
77
+            [false, true, true],
78
+            // has no attribute permissions-download - can get file
79
+            [false, null, true],
80
+            // has attribute permissions-download disabled- cannot get the file
81
+            [false, false, false],
82
+            // has attribute permissions-download enabled - can get file version
83
+            [true, true, true],
84
+            // has no attribute permissions-download - can get file version
85
+            [true, null, true],
86
+            // has attribute permissions-download disabled- cannot get the file version
87
+            [true, false, false],
88
+        ];
89
+    }
90
+
91
+    /**
92
+     * @dataProvider providesDataForCanGet
93
+     */
94
+    public function testCanGet(bool $isVersion, ?bool $attrEnabled, bool $expectCanDownloadFile): void {
95
+        $nodeInfo = $this->createMock(File::class);
96
+        if ($isVersion) {
97
+            $davPath = 'versions/alice/versions/117/123456';
98
+            $version = $this->createMock(IVersion::class);
99
+            $version->expects($this->once())
100
+                ->method('getSourceFile')
101
+                ->willReturn($nodeInfo);
102
+            $davNode = $this->createMock(VersionFile::class);
103
+            $davNode->expects($this->once())
104
+                ->method('getVersion')
105
+                ->willReturn($version);
106
+
107
+            $currentUser = $this->createMock(IUser::class);
108
+            $currentUser->expects($this->once())
109
+                ->method('getUID')
110
+                ->willReturn('alice');
111
+            $nodeInfo->expects($this->once())
112
+                ->method('getOwner')
113
+                ->willReturn($currentUser);
114
+
115
+            $nodeInfo = $this->createMock(File::class);
116
+            $owner = $this->createMock(IUser::class);
117
+            $owner->expects($this->once())
118
+                ->method('getUID')
119
+                ->willReturn('bob');
120
+            $this->userFolder->expects($this->once())
121
+                ->method('getById')
122
+                ->willReturn([$nodeInfo]);
123
+            $this->userFolder->expects($this->once())
124
+                ->method('getOwner')
125
+                ->willReturn($owner);
126
+        } else {
127
+            $davPath = 'files/path/to/file.odt';
128
+            $davNode = $this->createMock(DavFile::class);
129
+            $davNode->method('getNode')->willReturn($nodeInfo);
130
+        }
131
+
132
+        $this->request->expects($this->once())->method('getPath')->willReturn($davPath);
133
+
134
+        $this->tree->expects($this->once())
135
+            ->method('getNodeForPath')
136
+            ->with($davPath)
137
+            ->willReturn($davNode);
138
+
139
+        $storage = $this->createMock(SharedStorage::class);
140
+        $share = $this->createMock(IShare::class);
141
+        $nodeInfo->expects($this->once())
142
+            ->method('getStorage')
143
+            ->willReturn($storage);
144
+        $storage->method('instanceOfStorage')->with(ISharedStorage::class)->willReturn(true);
145
+        $storage->method('getShare')->willReturn($share);
146
+
147
+        $extAttr = $this->createMock(IAttributes::class);
148
+        $share->method('getAttributes')->willReturn($extAttr);
149
+        $extAttr->expects($this->once())
150
+            ->method('getAttribute')
151
+            ->with('permissions', 'download')
152
+            ->willReturn($attrEnabled);
153
+
154
+        if (!$expectCanDownloadFile) {
155
+            $this->expectException(Forbidden::class);
156
+        }
157
+        $this->plugin->checkViewOnly($this->request);
158
+    }
159 159
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/DAV/SystemPrincipalBackendTest.php 1 patch
Indentation   +80 added lines, -80 removed lines patch added patch discarded remove patch
@@ -14,95 +14,95 @@
 block discarded – undo
14 14
 
15 15
 class SystemPrincipalBackendTest extends TestCase {
16 16
 
17
-	/**
18
-	 * @dataProvider providesPrefix
19
-	 */
20
-	public function testGetPrincipalsByPrefix(array $expected, string $prefix): void {
21
-		$backend = new SystemPrincipalBackend();
22
-		$result = $backend->getPrincipalsByPrefix($prefix);
23
-		$this->assertEquals($expected, $result);
24
-	}
17
+    /**
18
+     * @dataProvider providesPrefix
19
+     */
20
+    public function testGetPrincipalsByPrefix(array $expected, string $prefix): void {
21
+        $backend = new SystemPrincipalBackend();
22
+        $result = $backend->getPrincipalsByPrefix($prefix);
23
+        $this->assertEquals($expected, $result);
24
+    }
25 25
 
26
-	public static function providesPrefix(): array {
27
-		return [
28
-			[[], ''],
29
-			[[[
30
-				'uri' => 'principals/system/system',
31
-				'{DAV:}displayname' => 'system',
32
-			],
33
-				[
34
-					'uri' => 'principals/system/public',
35
-					'{DAV:}displayname' => 'public',
36
-				]
37
-			], 'principals/system'],
38
-		];
39
-	}
26
+    public static function providesPrefix(): array {
27
+        return [
28
+            [[], ''],
29
+            [[[
30
+                'uri' => 'principals/system/system',
31
+                '{DAV:}displayname' => 'system',
32
+            ],
33
+                [
34
+                    'uri' => 'principals/system/public',
35
+                    '{DAV:}displayname' => 'public',
36
+                ]
37
+            ], 'principals/system'],
38
+        ];
39
+    }
40 40
 
41
-	/**
42
-	 * @dataProvider providesPath
43
-	 */
44
-	public function testGetPrincipalByPath(?array $expected, string $path): void {
45
-		$backend = new SystemPrincipalBackend();
46
-		$result = $backend->getPrincipalByPath($path);
47
-		$this->assertEquals($expected, $result);
48
-	}
41
+    /**
42
+     * @dataProvider providesPath
43
+     */
44
+    public function testGetPrincipalByPath(?array $expected, string $path): void {
45
+        $backend = new SystemPrincipalBackend();
46
+        $result = $backend->getPrincipalByPath($path);
47
+        $this->assertEquals($expected, $result);
48
+    }
49 49
 
50
-	public static function providesPath(): array {
51
-		return [
52
-			[null, ''],
53
-			[null, 'principals'],
54
-			[null, 'principals/system'],
55
-			[[
56
-				'uri' => 'principals/system/system',
57
-				'{DAV:}displayname' => 'system',
58
-			], 'principals/system/system'],
59
-		];
60
-	}
50
+    public static function providesPath(): array {
51
+        return [
52
+            [null, ''],
53
+            [null, 'principals'],
54
+            [null, 'principals/system'],
55
+            [[
56
+                'uri' => 'principals/system/system',
57
+                '{DAV:}displayname' => 'system',
58
+            ], 'principals/system/system'],
59
+        ];
60
+    }
61 61
 
62
-	/**
63
-	 * @dataProvider providesPrincipalForGetGroupMemberSet
64
-	 */
65
-	public function testGetGroupMemberSetExceptional(?string $principal): void {
66
-		$this->expectException(Exception::class);
67
-		$this->expectExceptionMessage('Principal not found');
62
+    /**
63
+     * @dataProvider providesPrincipalForGetGroupMemberSet
64
+     */
65
+    public function testGetGroupMemberSetExceptional(?string $principal): void {
66
+        $this->expectException(Exception::class);
67
+        $this->expectExceptionMessage('Principal not found');
68 68
 
69
-		$backend = new SystemPrincipalBackend();
70
-		$backend->getGroupMemberSet($principal);
71
-	}
69
+        $backend = new SystemPrincipalBackend();
70
+        $backend->getGroupMemberSet($principal);
71
+    }
72 72
 
73
-	public static function providesPrincipalForGetGroupMemberSet(): array {
74
-		return [
75
-			[null],
76
-			['principals/system'],
77
-		];
78
-	}
73
+    public static function providesPrincipalForGetGroupMemberSet(): array {
74
+        return [
75
+            [null],
76
+            ['principals/system'],
77
+        ];
78
+    }
79 79
 
80
-	public function testGetGroupMemberSet(): void {
81
-		$backend = new SystemPrincipalBackend();
82
-		$result = $backend->getGroupMemberSet('principals/system/system');
83
-		$this->assertEquals(['principals/system/system'], $result);
84
-	}
80
+    public function testGetGroupMemberSet(): void {
81
+        $backend = new SystemPrincipalBackend();
82
+        $result = $backend->getGroupMemberSet('principals/system/system');
83
+        $this->assertEquals(['principals/system/system'], $result);
84
+    }
85 85
 
86
-	/**
87
-	 * @dataProvider providesPrincipalForGetGroupMembership
88
-	 */
89
-	public function testGetGroupMembershipExceptional(string $principal): void {
90
-		$this->expectException(Exception::class);
91
-		$this->expectExceptionMessage('Principal not found');
86
+    /**
87
+     * @dataProvider providesPrincipalForGetGroupMembership
88
+     */
89
+    public function testGetGroupMembershipExceptional(string $principal): void {
90
+        $this->expectException(Exception::class);
91
+        $this->expectExceptionMessage('Principal not found');
92 92
 
93
-		$backend = new SystemPrincipalBackend();
94
-		$backend->getGroupMembership($principal);
95
-	}
93
+        $backend = new SystemPrincipalBackend();
94
+        $backend->getGroupMembership($principal);
95
+    }
96 96
 
97
-	public static function providesPrincipalForGetGroupMembership(): array {
98
-		return [
99
-			['principals/system/a'],
100
-		];
101
-	}
97
+    public static function providesPrincipalForGetGroupMembership(): array {
98
+        return [
99
+            ['principals/system/a'],
100
+        ];
101
+    }
102 102
 
103
-	public function testGetGroupMembership(): void {
104
-		$backend = new SystemPrincipalBackend();
105
-		$result = $backend->getGroupMembership('principals/system/system');
106
-		$this->assertEquals([], $result);
107
-	}
103
+    public function testGetGroupMembership(): void {
104
+        $backend = new SystemPrincipalBackend();
105
+        $result = $backend->getGroupMembership('principals/system/system');
106
+        $this->assertEquals([], $result);
107
+    }
108 108
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php 1 patch
Indentation   +220 added lines, -220 removed lines patch added patch discarded remove patch
@@ -21,238 +21,238 @@
 block discarded – undo
21 21
 
22 22
 class FilesDropPluginTest extends TestCase {
23 23
 
24
-	private FilesDropPlugin $plugin;
24
+    private FilesDropPlugin $plugin;
25 25
 
26
-	private Folder&MockObject $node;
27
-	private IShare&MockObject $share;
28
-	private Server&MockObject $server;
29
-	private RequestInterface&MockObject $request;
30
-	private ResponseInterface&MockObject $response;
26
+    private Folder&MockObject $node;
27
+    private IShare&MockObject $share;
28
+    private Server&MockObject $server;
29
+    private RequestInterface&MockObject $request;
30
+    private ResponseInterface&MockObject $response;
31 31
 
32
-	protected function setUp(): void {
33
-		parent::setUp();
32
+    protected function setUp(): void {
33
+        parent::setUp();
34 34
 
35
-		$this->node = $this->createMock(Folder::class);
36
-		$this->node->method('getPath')
37
-			->willReturn('/files/token');
35
+        $this->node = $this->createMock(Folder::class);
36
+        $this->node->method('getPath')
37
+            ->willReturn('/files/token');
38 38
 
39
-		$this->share = $this->createMock(IShare::class);
40
-		$this->share->expects(self::any())
41
-			->method('getNode')
42
-			->willReturn($this->node);
43
-		$this->server = $this->createMock(Server::class);
44
-		$this->plugin = new FilesDropPlugin();
39
+        $this->share = $this->createMock(IShare::class);
40
+        $this->share->expects(self::any())
41
+            ->method('getNode')
42
+            ->willReturn($this->node);
43
+        $this->server = $this->createMock(Server::class);
44
+        $this->plugin = new FilesDropPlugin();
45 45
 
46
-		$this->request = $this->createMock(RequestInterface::class);
47
-		$this->response = $this->createMock(ResponseInterface::class);
46
+        $this->request = $this->createMock(RequestInterface::class);
47
+        $this->response = $this->createMock(ResponseInterface::class);
48 48
 
49
-		$attributes = $this->createMock(IAttributes::class);
50
-		$this->share->expects($this->any())
51
-			->method('getAttributes')
52
-			->willReturn($attributes);
49
+        $attributes = $this->createMock(IAttributes::class);
50
+        $this->share->expects($this->any())
51
+            ->method('getAttributes')
52
+            ->willReturn($attributes);
53 53
 
54
-		$this->share
55
-			->method('getToken')
56
-			->willReturn('token');
57
-	}
54
+        $this->share
55
+            ->method('getToken')
56
+            ->willReturn('token');
57
+    }
58 58
 
59
-	public function testNotEnabled(): void {
60
-		$this->request->expects($this->never())
61
-			->method($this->anything());
59
+    public function testNotEnabled(): void {
60
+        $this->request->expects($this->never())
61
+            ->method($this->anything());
62 62
 
63
-		$this->plugin->beforeMethod($this->request, $this->response);
64
-	}
63
+        $this->plugin->beforeMethod($this->request, $this->response);
64
+    }
65 65
 
66
-	public function testValid(): void {
67
-		$this->plugin->enable();
68
-		$this->plugin->setShare($this->share);
66
+    public function testValid(): void {
67
+        $this->plugin->enable();
68
+        $this->plugin->setShare($this->share);
69 69
 
70
-		$this->request->method('getMethod')
71
-			->willReturn('PUT');
70
+        $this->request->method('getMethod')
71
+            ->willReturn('PUT');
72 72
 
73
-		$this->request->method('getPath')
74
-			->willReturn('/files/token/file.txt');
73
+        $this->request->method('getPath')
74
+            ->willReturn('/files/token/file.txt');
75 75
 
76
-		$this->request->method('getBaseUrl')
77
-			->willReturn('https://example.com');
76
+        $this->request->method('getBaseUrl')
77
+            ->willReturn('https://example.com');
78 78
 
79
-		$this->node->expects(self::once())
80
-			->method('getNonExistingName')
81
-			->with('file.txt')
82
-			->willReturn('file.txt');
83
-
84
-		$this->request->expects($this->once())
85
-			->method('setUrl')
86
-			->with('https://example.com/files/token/file.txt');
87
-
88
-		$this->plugin->beforeMethod($this->request, $this->response);
89
-	}
90
-
91
-	public function testFileAlreadyExistsValid(): void {
92
-		$this->plugin->enable();
93
-		$this->plugin->setShare($this->share);
94
-
95
-		$this->request->method('getMethod')
96
-			->willReturn('PUT');
97
-
98
-		$this->request->method('getPath')
99
-			->willReturn('/files/token/file.txt');
100
-
101
-		$this->request->method('getBaseUrl')
102
-			->willReturn('https://example.com');
103
-
104
-		$this->node->method('getNonExistingName')
105
-			->with('file.txt')
106
-			->willReturn('file (2).txt');
107
-
108
-		$this->request->expects($this->once())
109
-			->method('setUrl')
110
-			->with($this->equalTo('https://example.com/files/token/file (2).txt'));
111
-
112
-		$this->plugin->beforeMethod($this->request, $this->response);
113
-	}
114
-
115
-	public function testNoMKCOLWithoutNickname(): void {
116
-		$this->plugin->enable();
117
-		$this->plugin->setShare($this->share);
118
-
119
-		$this->request->method('getMethod')
120
-			->willReturn('MKCOL');
121
-
122
-		$this->expectException(MethodNotAllowed::class);
123
-
124
-		$this->plugin->beforeMethod($this->request, $this->response);
125
-	}
126
-
127
-	public function testMKCOLWithNickname(): void {
128
-		$this->plugin->enable();
129
-		$this->plugin->setShare($this->share);
130
-
131
-		$this->request->method('getMethod')
132
-			->willReturn('MKCOL');
133
-
134
-		$this->request->method('hasHeader')
135
-			->with('X-NC-Nickname')
136
-			->willReturn(true);
137
-		$this->request->method('getHeader')
138
-			->with('X-NC-Nickname')
139
-			->willReturn('nickname');
140
-
141
-		$this->expectNotToPerformAssertions();
142
-
143
-		$this->plugin->beforeMethod($this->request, $this->response);
144
-	}
145
-
146
-	public function testSubdirPut(): void {
147
-		$this->plugin->enable();
148
-		$this->plugin->setShare($this->share);
149
-
150
-		$this->request->method('getMethod')
151
-			->willReturn('PUT');
152
-
153
-		$this->request->method('hasHeader')
154
-			->with('X-NC-Nickname')
155
-			->willReturn(true);
156
-		$this->request->method('getHeader')
157
-			->with('X-NC-Nickname')
158
-			->willReturn('nickname');
159
-
160
-		$this->request->method('getPath')
161
-			->willReturn('/files/token/folder/file.txt');
162
-
163
-		$this->request->method('getBaseUrl')
164
-			->willReturn('https://example.com');
165
-
166
-		$nodeName = $this->createMock(Folder::class);
167
-		$nodeFolder = $this->createMock(Folder::class);
168
-		$nodeFolder->expects(self::once())
169
-			->method('getPath')
170
-			->willReturn('/files/token/nickname/folder');
171
-		$nodeFolder->method('getNonExistingName')
172
-			->with('file.txt')
173
-			->willReturn('file.txt');
174
-		$nodeName->expects(self::once())
175
-			->method('get')
176
-			->with('folder')
177
-			->willThrowException(new NotFoundException());
178
-		$nodeName->expects(self::once())
179
-			->method('newFolder')
180
-			->with('folder')
181
-			->willReturn($nodeFolder);
182
-
183
-		$this->node->expects(self::once())
184
-			->method('get')
185
-			->willThrowException(new NotFoundException());
186
-		$this->node->expects(self::once())
187
-			->method('newFolder')
188
-			->with('nickname')
189
-			->willReturn($nodeName);
190
-
191
-		$this->request->expects($this->once())
192
-			->method('setUrl')
193
-			->with($this->equalTo('https://example.com/files/token/nickname/folder/file.txt'));
194
-
195
-		$this->plugin->beforeMethod($this->request, $this->response);
196
-	}
197
-
198
-	public function testRecursiveFolderCreation(): void {
199
-		$this->plugin->enable();
200
-		$this->plugin->setShare($this->share);
201
-
202
-		$this->request->method('getMethod')
203
-			->willReturn('PUT');
204
-		$this->request->method('hasHeader')
205
-			->with('X-NC-Nickname')
206
-			->willReturn(true);
207
-		$this->request->method('getHeader')
208
-			->with('X-NC-Nickname')
209
-			->willReturn('nickname');
210
-
211
-		$this->request->method('getPath')
212
-			->willReturn('/files/token/folder/subfolder/file.txt');
213
-		$this->request->method('getBaseUrl')
214
-			->willReturn('https://example.com');
215
-
216
-		$this->request->expects($this->once())
217
-			->method('setUrl')
218
-			->with($this->equalTo('https://example.com/files/token/nickname/folder/subfolder/file.txt'));
219
-
220
-		$subfolder = $this->createMock(Folder::class);
221
-		$subfolder->expects(self::once())
222
-			->method('getNonExistingName')
223
-			->with('file.txt')
224
-			->willReturn('file.txt');
225
-		$subfolder->expects(self::once())
226
-			->method('getPath')
227
-			->willReturn('/files/token/nickname/folder/subfolder');
228
-
229
-		$folder = $this->createMock(Folder::class);
230
-		$folder->expects(self::once())
231
-			->method('get')
232
-			->with('subfolder')
233
-			->willReturn($subfolder);
234
-
235
-		$nickname = $this->createMock(Folder::class);
236
-		$nickname->expects(self::once())
237
-			->method('get')
238
-			->with('folder')
239
-			->willReturn($folder);
240
-
241
-		$this->node->method('get')
242
-			->with('nickname')
243
-			->willReturn($nickname);
244
-		$this->plugin->beforeMethod($this->request, $this->response);
245
-	}
246
-
247
-	public function testOnMkcol(): void {
248
-		$this->plugin->enable();
249
-		$this->plugin->setShare($this->share);
250
-
251
-		$this->response->expects($this->once())
252
-			->method('setStatus')
253
-			->with(201);
254
-
255
-		$response = $this->plugin->onMkcol($this->request, $this->response);
256
-		$this->assertFalse($response);
257
-	}
79
+        $this->node->expects(self::once())
80
+            ->method('getNonExistingName')
81
+            ->with('file.txt')
82
+            ->willReturn('file.txt');
83
+
84
+        $this->request->expects($this->once())
85
+            ->method('setUrl')
86
+            ->with('https://example.com/files/token/file.txt');
87
+
88
+        $this->plugin->beforeMethod($this->request, $this->response);
89
+    }
90
+
91
+    public function testFileAlreadyExistsValid(): void {
92
+        $this->plugin->enable();
93
+        $this->plugin->setShare($this->share);
94
+
95
+        $this->request->method('getMethod')
96
+            ->willReturn('PUT');
97
+
98
+        $this->request->method('getPath')
99
+            ->willReturn('/files/token/file.txt');
100
+
101
+        $this->request->method('getBaseUrl')
102
+            ->willReturn('https://example.com');
103
+
104
+        $this->node->method('getNonExistingName')
105
+            ->with('file.txt')
106
+            ->willReturn('file (2).txt');
107
+
108
+        $this->request->expects($this->once())
109
+            ->method('setUrl')
110
+            ->with($this->equalTo('https://example.com/files/token/file (2).txt'));
111
+
112
+        $this->plugin->beforeMethod($this->request, $this->response);
113
+    }
114
+
115
+    public function testNoMKCOLWithoutNickname(): void {
116
+        $this->plugin->enable();
117
+        $this->plugin->setShare($this->share);
118
+
119
+        $this->request->method('getMethod')
120
+            ->willReturn('MKCOL');
121
+
122
+        $this->expectException(MethodNotAllowed::class);
123
+
124
+        $this->plugin->beforeMethod($this->request, $this->response);
125
+    }
126
+
127
+    public function testMKCOLWithNickname(): void {
128
+        $this->plugin->enable();
129
+        $this->plugin->setShare($this->share);
130
+
131
+        $this->request->method('getMethod')
132
+            ->willReturn('MKCOL');
133
+
134
+        $this->request->method('hasHeader')
135
+            ->with('X-NC-Nickname')
136
+            ->willReturn(true);
137
+        $this->request->method('getHeader')
138
+            ->with('X-NC-Nickname')
139
+            ->willReturn('nickname');
140
+
141
+        $this->expectNotToPerformAssertions();
142
+
143
+        $this->plugin->beforeMethod($this->request, $this->response);
144
+    }
145
+
146
+    public function testSubdirPut(): void {
147
+        $this->plugin->enable();
148
+        $this->plugin->setShare($this->share);
149
+
150
+        $this->request->method('getMethod')
151
+            ->willReturn('PUT');
152
+
153
+        $this->request->method('hasHeader')
154
+            ->with('X-NC-Nickname')
155
+            ->willReturn(true);
156
+        $this->request->method('getHeader')
157
+            ->with('X-NC-Nickname')
158
+            ->willReturn('nickname');
159
+
160
+        $this->request->method('getPath')
161
+            ->willReturn('/files/token/folder/file.txt');
162
+
163
+        $this->request->method('getBaseUrl')
164
+            ->willReturn('https://example.com');
165
+
166
+        $nodeName = $this->createMock(Folder::class);
167
+        $nodeFolder = $this->createMock(Folder::class);
168
+        $nodeFolder->expects(self::once())
169
+            ->method('getPath')
170
+            ->willReturn('/files/token/nickname/folder');
171
+        $nodeFolder->method('getNonExistingName')
172
+            ->with('file.txt')
173
+            ->willReturn('file.txt');
174
+        $nodeName->expects(self::once())
175
+            ->method('get')
176
+            ->with('folder')
177
+            ->willThrowException(new NotFoundException());
178
+        $nodeName->expects(self::once())
179
+            ->method('newFolder')
180
+            ->with('folder')
181
+            ->willReturn($nodeFolder);
182
+
183
+        $this->node->expects(self::once())
184
+            ->method('get')
185
+            ->willThrowException(new NotFoundException());
186
+        $this->node->expects(self::once())
187
+            ->method('newFolder')
188
+            ->with('nickname')
189
+            ->willReturn($nodeName);
190
+
191
+        $this->request->expects($this->once())
192
+            ->method('setUrl')
193
+            ->with($this->equalTo('https://example.com/files/token/nickname/folder/file.txt'));
194
+
195
+        $this->plugin->beforeMethod($this->request, $this->response);
196
+    }
197
+
198
+    public function testRecursiveFolderCreation(): void {
199
+        $this->plugin->enable();
200
+        $this->plugin->setShare($this->share);
201
+
202
+        $this->request->method('getMethod')
203
+            ->willReturn('PUT');
204
+        $this->request->method('hasHeader')
205
+            ->with('X-NC-Nickname')
206
+            ->willReturn(true);
207
+        $this->request->method('getHeader')
208
+            ->with('X-NC-Nickname')
209
+            ->willReturn('nickname');
210
+
211
+        $this->request->method('getPath')
212
+            ->willReturn('/files/token/folder/subfolder/file.txt');
213
+        $this->request->method('getBaseUrl')
214
+            ->willReturn('https://example.com');
215
+
216
+        $this->request->expects($this->once())
217
+            ->method('setUrl')
218
+            ->with($this->equalTo('https://example.com/files/token/nickname/folder/subfolder/file.txt'));
219
+
220
+        $subfolder = $this->createMock(Folder::class);
221
+        $subfolder->expects(self::once())
222
+            ->method('getNonExistingName')
223
+            ->with('file.txt')
224
+            ->willReturn('file.txt');
225
+        $subfolder->expects(self::once())
226
+            ->method('getPath')
227
+            ->willReturn('/files/token/nickname/folder/subfolder');
228
+
229
+        $folder = $this->createMock(Folder::class);
230
+        $folder->expects(self::once())
231
+            ->method('get')
232
+            ->with('subfolder')
233
+            ->willReturn($subfolder);
234
+
235
+        $nickname = $this->createMock(Folder::class);
236
+        $nickname->expects(self::once())
237
+            ->method('get')
238
+            ->with('folder')
239
+            ->willReturn($folder);
240
+
241
+        $this->node->method('get')
242
+            ->with('nickname')
243
+            ->willReturn($nickname);
244
+        $this->plugin->beforeMethod($this->request, $this->response);
245
+    }
246
+
247
+    public function testOnMkcol(): void {
248
+        $this->plugin->enable();
249
+        $this->plugin->setShare($this->share);
250
+
251
+        $this->response->expects($this->once())
252
+            ->method('setStatus')
253
+            ->with(201);
254
+
255
+        $response = $this->plugin->onMkcol($this->request, $this->response);
256
+        $this->assertFalse($response);
257
+    }
258 258
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Files/MultipartRequestParserTest.php 1 patch
Indentation   +303 added lines, -303 removed lines patch added patch discarded remove patch
@@ -16,307 +16,307 @@
 block discarded – undo
16 16
 
17 17
 class MultipartRequestParserTest extends TestCase {
18 18
 
19
-	protected LoggerInterface&MockObject $logger;
20
-
21
-	protected function setUp(): void {
22
-		parent::setUp();
23
-		$this->logger = $this->createMock(LoggerInterface::class);
24
-	}
25
-
26
-	private static function getValidBodyObject(): array {
27
-		return [
28
-			[
29
-				'headers' => [
30
-					'Content-Length' => 7,
31
-					'X-File-MD5' => '4f2377b4d911f7ec46325fe603c3af03',
32
-					'OC-Checksum' => 'md5:4f2377b4d911f7ec46325fe603c3af03',
33
-					'X-File-Path' => '/coucou.txt'
34
-				],
35
-				'content' => "Coucou\n"
36
-			]
37
-		];
38
-	}
39
-
40
-	private function getMultipartParser(array $parts, array $headers = [], string $boundary = 'boundary_azertyuiop'): MultipartRequestParser {
41
-		/** @var RequestInterface&MockObject $request */
42
-		$request = $this->getMockBuilder(RequestInterface::class)
43
-			->disableOriginalConstructor()
44
-			->getMock();
45
-
46
-		$headers = array_merge(['Content-Type' => 'multipart/related; boundary=' . $boundary], $headers);
47
-		$request->expects($this->any())
48
-			->method('getHeader')
49
-			->willReturnCallback(function (string $key) use (&$headers) {
50
-				return $headers[$key];
51
-			});
52
-
53
-		$body = '';
54
-		foreach ($parts as $part) {
55
-			$body .= '--' . $boundary . "\r\n";
56
-
57
-			foreach ($part['headers'] as $headerKey => $headerPart) {
58
-				$body .= $headerKey . ': ' . $headerPart . "\r\n";
59
-			}
60
-
61
-			$body .= "\r\n";
62
-			$body .= $part['content'] . "\r\n";
63
-		}
64
-
65
-		$body .= '--' . $boundary . '--';
66
-
67
-		$stream = fopen('php://temp', 'r+');
68
-		fwrite($stream, $body);
69
-		rewind($stream);
70
-
71
-		$request->expects($this->any())
72
-			->method('getBody')
73
-			->willReturn($stream);
74
-
75
-		return new MultipartRequestParser($request, $this->logger);
76
-	}
77
-
78
-
79
-	/**
80
-	 * Test validation of the request's body type
81
-	 */
82
-	public function testBodyTypeValidation(): void {
83
-		$bodyStream = 'I am not a stream, but pretend to be';
84
-		/** @var RequestInterface&MockObject $request */
85
-		$request = $this->getMockBuilder(RequestInterface::class)
86
-			->disableOriginalConstructor()
87
-			->getMock();
88
-		$request->expects($this->any())
89
-			->method('getBody')
90
-			->willReturn($bodyStream);
91
-
92
-		$this->expectExceptionMessage('Body should be of type resource');
93
-		new MultipartRequestParser($request, $this->logger);
94
-	}
95
-
96
-	/**
97
-	 * Test with valid request.
98
-	 * - valid boundary
99
-	 * - valid hash
100
-	 * - valid content-length
101
-	 * - valid file content
102
-	 * - valid file path
103
-	 */
104
-	public function testValidRequest(): void {
105
-		$bodyObject = self::getValidBodyObject();
106
-		unset($bodyObject['0']['headers']['X-File-MD5']);
107
-
108
-		$multipartParser = $this->getMultipartParser($bodyObject);
109
-
110
-		[$headers, $content] = $multipartParser->parseNextPart();
111
-
112
-		$this->assertSame((int)$headers['content-length'], 7, 'Content-Length header should be the same as provided.');
113
-		$this->assertSame($headers['oc-checksum'], 'md5:4f2377b4d911f7ec46325fe603c3af03', 'OC-Checksum header should be the same as provided.');
114
-		$this->assertSame($headers['x-file-path'], '/coucou.txt', 'X-File-Path header should be the same as provided.');
115
-
116
-		$this->assertSame($content, "Coucou\n", 'Content should be the same');
117
-	}
118
-
119
-	/**
120
-	 * Test with valid request.
121
-	 * - valid boundary
122
-	 * - valid md5 hash
123
-	 * - valid content-length
124
-	 * - valid file content
125
-	 * - valid file path
126
-	 */
127
-	public function testValidRequestWithMd5(): void {
128
-		$bodyObject = self::getValidBodyObject();
129
-		unset($bodyObject['0']['headers']['OC-Checksum']);
130
-
131
-		$multipartParser = $this->getMultipartParser($bodyObject);
132
-
133
-		[$headers, $content] = $multipartParser->parseNextPart();
134
-
135
-		$this->assertSame((int)$headers['content-length'], 7, 'Content-Length header should be the same as provided.');
136
-		$this->assertSame($headers['x-file-md5'], '4f2377b4d911f7ec46325fe603c3af03', 'X-File-MD5 header should be the same as provided.');
137
-		$this->assertSame($headers['x-file-path'], '/coucou.txt', 'X-File-Path header should be the same as provided.');
138
-
139
-		$this->assertSame($content, "Coucou\n", 'Content should be the same');
140
-	}
141
-
142
-	/**
143
-	 * Test with invalid hash.
144
-	 */
145
-	public function testInvalidHash(): void {
146
-		$bodyObject = self::getValidBodyObject();
147
-		$bodyObject['0']['headers']['OC-Checksum'] = 'md5:f2377b4d911f7ec46325fe603c3af03';
148
-		unset($bodyObject['0']['headers']['X-File-MD5']);
149
-		$multipartParser = $this->getMultipartParser(
150
-			$bodyObject
151
-		);
152
-
153
-		$this->expectExceptionMessage('Computed md5 hash is incorrect (4f2377b4d911f7ec46325fe603c3af03).');
154
-		$multipartParser->parseNextPart();
155
-	}
156
-
157
-	/**
158
-	 * Test with invalid md5 hash.
159
-	 */
160
-	public function testInvalidMd5Hash(): void {
161
-		$bodyObject = self::getValidBodyObject();
162
-		unset($bodyObject['0']['headers']['OC-Checksum']);
163
-		$bodyObject['0']['headers']['X-File-MD5'] = 'f2377b4d911f7ec46325fe603c3af03';
164
-		$multipartParser = $this->getMultipartParser(
165
-			$bodyObject
166
-		);
167
-
168
-		$this->expectExceptionMessage('Computed md5 hash is incorrect (4f2377b4d911f7ec46325fe603c3af03).');
169
-		$multipartParser->parseNextPart();
170
-	}
171
-
172
-	/**
173
-	 * Test with a null hash headers.
174
-	 */
175
-	public function testNullHash(): void {
176
-		$bodyObject = self::getValidBodyObject();
177
-		unset($bodyObject['0']['headers']['OC-Checksum']);
178
-		unset($bodyObject['0']['headers']['X-File-MD5']);
179
-		$multipartParser = $this->getMultipartParser(
180
-			$bodyObject
181
-		);
182
-
183
-		$this->expectExceptionMessage('The hash headers must not be null.');
184
-		$multipartParser->parseNextPart();
185
-	}
186
-
187
-	/**
188
-	 * Test with a null Content-Length.
189
-	 */
190
-	public function testNullContentLength(): void {
191
-		$bodyObject = self::getValidBodyObject();
192
-		unset($bodyObject['0']['headers']['Content-Length']);
193
-		$multipartParser = $this->getMultipartParser(
194
-			$bodyObject
195
-		);
196
-
197
-		$this->expectExceptionMessage('The Content-Length header must not be null.');
198
-		$multipartParser->parseNextPart();
199
-	}
200
-
201
-	/**
202
-	 * Test with a lower Content-Length.
203
-	 */
204
-	public function testLowerContentLength(): void {
205
-		$bodyObject = self::getValidBodyObject();
206
-		$bodyObject['0']['headers']['Content-Length'] = 6;
207
-		$multipartParser = $this->getMultipartParser(
208
-			$bodyObject
209
-		);
210
-
211
-		$this->expectExceptionMessage('Computed md5 hash is incorrect (41060d3ddfdf63e68fc2bf196f652ee9).');
212
-		$multipartParser->parseNextPart();
213
-	}
214
-
215
-	/**
216
-	 * Test with a higher Content-Length.
217
-	 */
218
-	public function testHigherContentLength(): void {
219
-		$bodyObject = self::getValidBodyObject();
220
-		$bodyObject['0']['headers']['Content-Length'] = 8;
221
-		$multipartParser = $this->getMultipartParser(
222
-			$bodyObject
223
-		);
224
-
225
-		$this->expectExceptionMessage('Computed md5 hash is incorrect (0161002bbee6a744f18741b8a914e413).');
226
-		$multipartParser->parseNextPart();
227
-	}
228
-
229
-	/**
230
-	 * Test with wrong boundary in body.
231
-	 */
232
-	public function testWrongBoundary(): void {
233
-		$bodyObject = self::getValidBodyObject();
234
-		$multipartParser = $this->getMultipartParser(
235
-			$bodyObject,
236
-			['Content-Type' => 'multipart/related; boundary=boundary_poiuytreza']
237
-		);
238
-
239
-		$this->expectExceptionMessage('Boundary not found where it should be.');
240
-		$multipartParser->parseNextPart();
241
-	}
242
-
243
-	/**
244
-	 * Test with no boundary in request headers.
245
-	 */
246
-	public function testNoBoundaryInHeader(): void {
247
-		$bodyObject = self::getValidBodyObject();
248
-		$this->expectExceptionMessage('Error while parsing boundary in Content-Type header.');
249
-		$this->getMultipartParser(
250
-			$bodyObject,
251
-			['Content-Type' => 'multipart/related']
252
-		);
253
-	}
254
-
255
-	/**
256
-	 * Test with no boundary in the request's headers.
257
-	 */
258
-	public function testNoBoundaryInBody(): void {
259
-		$bodyObject = self::getValidBodyObject();
260
-		$multipartParser = $this->getMultipartParser(
261
-			$bodyObject,
262
-			['Content-Type' => 'multipart/related; boundary=boundary_azertyuiop'],
263
-			''
264
-		);
265
-
266
-		$this->expectExceptionMessage('Boundary not found where it should be.');
267
-		$multipartParser->parseNextPart();
268
-	}
269
-
270
-	/**
271
-	 * Test with a boundary with quotes in the request's headers.
272
-	 */
273
-	public function testBoundaryWithQuotes(): void {
274
-		$bodyObject = self::getValidBodyObject();
275
-		$multipartParser = $this->getMultipartParser(
276
-			$bodyObject,
277
-			['Content-Type' => 'multipart/related; boundary="boundary_azertyuiop"'],
278
-		);
279
-
280
-		$multipartParser->parseNextPart();
281
-
282
-		// Dummy assertion, we just want to test that the parsing works.
283
-		$this->assertTrue(true);
284
-	}
285
-
286
-	/**
287
-	 * Test with a wrong Content-Type in the request's headers.
288
-	 */
289
-	public function testWrongContentType(): void {
290
-		$bodyObject = self::getValidBodyObject();
291
-		$this->expectExceptionMessage('Content-Type must be multipart/related');
292
-		$this->getMultipartParser(
293
-			$bodyObject,
294
-			['Content-Type' => 'multipart/form-data; boundary="boundary_azertyuiop"'],
295
-		);
296
-	}
297
-
298
-	/**
299
-	 * Test with a wrong key after the content type in the request's headers.
300
-	 */
301
-	public function testWrongKeyInContentType(): void {
302
-		$bodyObject = self::getValidBodyObject();
303
-		$this->expectExceptionMessage('Boundary is invalid');
304
-		$this->getMultipartParser(
305
-			$bodyObject,
306
-			['Content-Type' => 'multipart/related; wrongkey="boundary_azertyuiop"'],
307
-		);
308
-	}
309
-
310
-	/**
311
-	 * Test with a null Content-Type in the request's headers.
312
-	 */
313
-	public function testNullContentType(): void {
314
-		$bodyObject = self::getValidBodyObject();
315
-		$this->expectExceptionMessage('Content-Type can not be null');
316
-		$this->getMultipartParser(
317
-			$bodyObject,
318
-			['Content-Type' => null],
319
-
320
-		);
321
-	}
19
+    protected LoggerInterface&MockObject $logger;
20
+
21
+    protected function setUp(): void {
22
+        parent::setUp();
23
+        $this->logger = $this->createMock(LoggerInterface::class);
24
+    }
25
+
26
+    private static function getValidBodyObject(): array {
27
+        return [
28
+            [
29
+                'headers' => [
30
+                    'Content-Length' => 7,
31
+                    'X-File-MD5' => '4f2377b4d911f7ec46325fe603c3af03',
32
+                    'OC-Checksum' => 'md5:4f2377b4d911f7ec46325fe603c3af03',
33
+                    'X-File-Path' => '/coucou.txt'
34
+                ],
35
+                'content' => "Coucou\n"
36
+            ]
37
+        ];
38
+    }
39
+
40
+    private function getMultipartParser(array $parts, array $headers = [], string $boundary = 'boundary_azertyuiop'): MultipartRequestParser {
41
+        /** @var RequestInterface&MockObject $request */
42
+        $request = $this->getMockBuilder(RequestInterface::class)
43
+            ->disableOriginalConstructor()
44
+            ->getMock();
45
+
46
+        $headers = array_merge(['Content-Type' => 'multipart/related; boundary=' . $boundary], $headers);
47
+        $request->expects($this->any())
48
+            ->method('getHeader')
49
+            ->willReturnCallback(function (string $key) use (&$headers) {
50
+                return $headers[$key];
51
+            });
52
+
53
+        $body = '';
54
+        foreach ($parts as $part) {
55
+            $body .= '--' . $boundary . "\r\n";
56
+
57
+            foreach ($part['headers'] as $headerKey => $headerPart) {
58
+                $body .= $headerKey . ': ' . $headerPart . "\r\n";
59
+            }
60
+
61
+            $body .= "\r\n";
62
+            $body .= $part['content'] . "\r\n";
63
+        }
64
+
65
+        $body .= '--' . $boundary . '--';
66
+
67
+        $stream = fopen('php://temp', 'r+');
68
+        fwrite($stream, $body);
69
+        rewind($stream);
70
+
71
+        $request->expects($this->any())
72
+            ->method('getBody')
73
+            ->willReturn($stream);
74
+
75
+        return new MultipartRequestParser($request, $this->logger);
76
+    }
77
+
78
+
79
+    /**
80
+     * Test validation of the request's body type
81
+     */
82
+    public function testBodyTypeValidation(): void {
83
+        $bodyStream = 'I am not a stream, but pretend to be';
84
+        /** @var RequestInterface&MockObject $request */
85
+        $request = $this->getMockBuilder(RequestInterface::class)
86
+            ->disableOriginalConstructor()
87
+            ->getMock();
88
+        $request->expects($this->any())
89
+            ->method('getBody')
90
+            ->willReturn($bodyStream);
91
+
92
+        $this->expectExceptionMessage('Body should be of type resource');
93
+        new MultipartRequestParser($request, $this->logger);
94
+    }
95
+
96
+    /**
97
+     * Test with valid request.
98
+     * - valid boundary
99
+     * - valid hash
100
+     * - valid content-length
101
+     * - valid file content
102
+     * - valid file path
103
+     */
104
+    public function testValidRequest(): void {
105
+        $bodyObject = self::getValidBodyObject();
106
+        unset($bodyObject['0']['headers']['X-File-MD5']);
107
+
108
+        $multipartParser = $this->getMultipartParser($bodyObject);
109
+
110
+        [$headers, $content] = $multipartParser->parseNextPart();
111
+
112
+        $this->assertSame((int)$headers['content-length'], 7, 'Content-Length header should be the same as provided.');
113
+        $this->assertSame($headers['oc-checksum'], 'md5:4f2377b4d911f7ec46325fe603c3af03', 'OC-Checksum header should be the same as provided.');
114
+        $this->assertSame($headers['x-file-path'], '/coucou.txt', 'X-File-Path header should be the same as provided.');
115
+
116
+        $this->assertSame($content, "Coucou\n", 'Content should be the same');
117
+    }
118
+
119
+    /**
120
+     * Test with valid request.
121
+     * - valid boundary
122
+     * - valid md5 hash
123
+     * - valid content-length
124
+     * - valid file content
125
+     * - valid file path
126
+     */
127
+    public function testValidRequestWithMd5(): void {
128
+        $bodyObject = self::getValidBodyObject();
129
+        unset($bodyObject['0']['headers']['OC-Checksum']);
130
+
131
+        $multipartParser = $this->getMultipartParser($bodyObject);
132
+
133
+        [$headers, $content] = $multipartParser->parseNextPart();
134
+
135
+        $this->assertSame((int)$headers['content-length'], 7, 'Content-Length header should be the same as provided.');
136
+        $this->assertSame($headers['x-file-md5'], '4f2377b4d911f7ec46325fe603c3af03', 'X-File-MD5 header should be the same as provided.');
137
+        $this->assertSame($headers['x-file-path'], '/coucou.txt', 'X-File-Path header should be the same as provided.');
138
+
139
+        $this->assertSame($content, "Coucou\n", 'Content should be the same');
140
+    }
141
+
142
+    /**
143
+     * Test with invalid hash.
144
+     */
145
+    public function testInvalidHash(): void {
146
+        $bodyObject = self::getValidBodyObject();
147
+        $bodyObject['0']['headers']['OC-Checksum'] = 'md5:f2377b4d911f7ec46325fe603c3af03';
148
+        unset($bodyObject['0']['headers']['X-File-MD5']);
149
+        $multipartParser = $this->getMultipartParser(
150
+            $bodyObject
151
+        );
152
+
153
+        $this->expectExceptionMessage('Computed md5 hash is incorrect (4f2377b4d911f7ec46325fe603c3af03).');
154
+        $multipartParser->parseNextPart();
155
+    }
156
+
157
+    /**
158
+     * Test with invalid md5 hash.
159
+     */
160
+    public function testInvalidMd5Hash(): void {
161
+        $bodyObject = self::getValidBodyObject();
162
+        unset($bodyObject['0']['headers']['OC-Checksum']);
163
+        $bodyObject['0']['headers']['X-File-MD5'] = 'f2377b4d911f7ec46325fe603c3af03';
164
+        $multipartParser = $this->getMultipartParser(
165
+            $bodyObject
166
+        );
167
+
168
+        $this->expectExceptionMessage('Computed md5 hash is incorrect (4f2377b4d911f7ec46325fe603c3af03).');
169
+        $multipartParser->parseNextPart();
170
+    }
171
+
172
+    /**
173
+     * Test with a null hash headers.
174
+     */
175
+    public function testNullHash(): void {
176
+        $bodyObject = self::getValidBodyObject();
177
+        unset($bodyObject['0']['headers']['OC-Checksum']);
178
+        unset($bodyObject['0']['headers']['X-File-MD5']);
179
+        $multipartParser = $this->getMultipartParser(
180
+            $bodyObject
181
+        );
182
+
183
+        $this->expectExceptionMessage('The hash headers must not be null.');
184
+        $multipartParser->parseNextPart();
185
+    }
186
+
187
+    /**
188
+     * Test with a null Content-Length.
189
+     */
190
+    public function testNullContentLength(): void {
191
+        $bodyObject = self::getValidBodyObject();
192
+        unset($bodyObject['0']['headers']['Content-Length']);
193
+        $multipartParser = $this->getMultipartParser(
194
+            $bodyObject
195
+        );
196
+
197
+        $this->expectExceptionMessage('The Content-Length header must not be null.');
198
+        $multipartParser->parseNextPart();
199
+    }
200
+
201
+    /**
202
+     * Test with a lower Content-Length.
203
+     */
204
+    public function testLowerContentLength(): void {
205
+        $bodyObject = self::getValidBodyObject();
206
+        $bodyObject['0']['headers']['Content-Length'] = 6;
207
+        $multipartParser = $this->getMultipartParser(
208
+            $bodyObject
209
+        );
210
+
211
+        $this->expectExceptionMessage('Computed md5 hash is incorrect (41060d3ddfdf63e68fc2bf196f652ee9).');
212
+        $multipartParser->parseNextPart();
213
+    }
214
+
215
+    /**
216
+     * Test with a higher Content-Length.
217
+     */
218
+    public function testHigherContentLength(): void {
219
+        $bodyObject = self::getValidBodyObject();
220
+        $bodyObject['0']['headers']['Content-Length'] = 8;
221
+        $multipartParser = $this->getMultipartParser(
222
+            $bodyObject
223
+        );
224
+
225
+        $this->expectExceptionMessage('Computed md5 hash is incorrect (0161002bbee6a744f18741b8a914e413).');
226
+        $multipartParser->parseNextPart();
227
+    }
228
+
229
+    /**
230
+     * Test with wrong boundary in body.
231
+     */
232
+    public function testWrongBoundary(): void {
233
+        $bodyObject = self::getValidBodyObject();
234
+        $multipartParser = $this->getMultipartParser(
235
+            $bodyObject,
236
+            ['Content-Type' => 'multipart/related; boundary=boundary_poiuytreza']
237
+        );
238
+
239
+        $this->expectExceptionMessage('Boundary not found where it should be.');
240
+        $multipartParser->parseNextPart();
241
+    }
242
+
243
+    /**
244
+     * Test with no boundary in request headers.
245
+     */
246
+    public function testNoBoundaryInHeader(): void {
247
+        $bodyObject = self::getValidBodyObject();
248
+        $this->expectExceptionMessage('Error while parsing boundary in Content-Type header.');
249
+        $this->getMultipartParser(
250
+            $bodyObject,
251
+            ['Content-Type' => 'multipart/related']
252
+        );
253
+    }
254
+
255
+    /**
256
+     * Test with no boundary in the request's headers.
257
+     */
258
+    public function testNoBoundaryInBody(): void {
259
+        $bodyObject = self::getValidBodyObject();
260
+        $multipartParser = $this->getMultipartParser(
261
+            $bodyObject,
262
+            ['Content-Type' => 'multipart/related; boundary=boundary_azertyuiop'],
263
+            ''
264
+        );
265
+
266
+        $this->expectExceptionMessage('Boundary not found where it should be.');
267
+        $multipartParser->parseNextPart();
268
+    }
269
+
270
+    /**
271
+     * Test with a boundary with quotes in the request's headers.
272
+     */
273
+    public function testBoundaryWithQuotes(): void {
274
+        $bodyObject = self::getValidBodyObject();
275
+        $multipartParser = $this->getMultipartParser(
276
+            $bodyObject,
277
+            ['Content-Type' => 'multipart/related; boundary="boundary_azertyuiop"'],
278
+        );
279
+
280
+        $multipartParser->parseNextPart();
281
+
282
+        // Dummy assertion, we just want to test that the parsing works.
283
+        $this->assertTrue(true);
284
+    }
285
+
286
+    /**
287
+     * Test with a wrong Content-Type in the request's headers.
288
+     */
289
+    public function testWrongContentType(): void {
290
+        $bodyObject = self::getValidBodyObject();
291
+        $this->expectExceptionMessage('Content-Type must be multipart/related');
292
+        $this->getMultipartParser(
293
+            $bodyObject,
294
+            ['Content-Type' => 'multipart/form-data; boundary="boundary_azertyuiop"'],
295
+        );
296
+    }
297
+
298
+    /**
299
+     * Test with a wrong key after the content type in the request's headers.
300
+     */
301
+    public function testWrongKeyInContentType(): void {
302
+        $bodyObject = self::getValidBodyObject();
303
+        $this->expectExceptionMessage('Boundary is invalid');
304
+        $this->getMultipartParser(
305
+            $bodyObject,
306
+            ['Content-Type' => 'multipart/related; wrongkey="boundary_azertyuiop"'],
307
+        );
308
+    }
309
+
310
+    /**
311
+     * Test with a null Content-Type in the request's headers.
312
+     */
313
+    public function testNullContentType(): void {
314
+        $bodyObject = self::getValidBodyObject();
315
+        $this->expectExceptionMessage('Content-Type can not be null');
316
+        $this->getMultipartParser(
317
+            $bodyObject,
318
+            ['Content-Type' => null],
319
+
320
+        );
321
+    }
322 322
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Files/FileSearchBackendTest.php 2 patches
Indentation   +367 added lines, -367 removed lines patch added patch discarded remove patch
@@ -35,371 +35,371 @@
 block discarded – undo
35 35
 use Test\TestCase;
36 36
 
37 37
 class FileSearchBackendTest extends TestCase {
38
-	private ObjectTree&MockObject $tree;
39
-	private IUser&MockObject $user;
40
-	private IRootFolder&MockObject $rootFolder;
41
-	private IManager&MockObject $shareManager;
42
-	private View&MockObject $view;
43
-	private Folder&MockObject $searchFolder;
44
-	private Directory&MockObject $davFolder;
45
-	private FileSearchBackend $search;
46
-
47
-	protected function setUp(): void {
48
-		parent::setUp();
49
-
50
-		$this->user = $this->createMock(IUser::class);
51
-		$this->user->expects($this->any())
52
-			->method('getUID')
53
-			->willReturn('test');
54
-
55
-		$this->tree = $this->createMock(ObjectTree::class);
56
-		$this->view = $this->createMock(View::class);
57
-		$this->rootFolder = $this->createMock(IRootFolder::class);
58
-		$this->shareManager = $this->createMock(IManager::class);
59
-		$this->searchFolder = $this->createMock(Folder::class);
60
-		$fileInfo = $this->createMock(FileInfo::class);
61
-		$this->davFolder = $this->createMock(Directory::class);
62
-
63
-		$this->view->expects($this->any())
64
-			->method('getRoot')
65
-			->willReturn('');
66
-
67
-		$this->view->expects($this->any())
68
-			->method('getRelativePath')
69
-			->willReturnArgument(0);
70
-
71
-		$this->davFolder->expects($this->any())
72
-			->method('getFileInfo')
73
-			->willReturn($fileInfo);
74
-
75
-		$this->rootFolder->expects($this->any())
76
-			->method('get')
77
-			->willReturn($this->searchFolder);
78
-
79
-		$filesMetadataManager = $this->createMock(IFilesMetadataManager::class);
80
-
81
-		$this->search = new FileSearchBackend($this->tree, $this->user, $this->rootFolder, $this->shareManager, $this->view, $filesMetadataManager);
82
-	}
83
-
84
-	public function testSearchFilename(): void {
85
-		$this->tree->expects($this->any())
86
-			->method('getNodeForPath')
87
-			->willReturn($this->davFolder);
88
-
89
-		$this->searchFolder->expects($this->once())
90
-			->method('search')
91
-			->with(new SearchQuery(
92
-				new SearchComparison(
93
-					ISearchComparison::COMPARE_EQUAL,
94
-					'name',
95
-					'foo'
96
-				),
97
-				0,
98
-				0,
99
-				[],
100
-				$this->user
101
-			))
102
-			->willReturn([
103
-				new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
104
-			]);
105
-
106
-		$query = $this->getBasicQuery(Operator::OPERATION_EQUAL, '{DAV:}displayname', 'foo');
107
-		$result = $this->search->search($query);
108
-
109
-		$this->assertCount(1, $result);
110
-		$this->assertEquals('/files/test/test/path', $result[0]->href);
111
-	}
112
-
113
-	public function testSearchMimetype(): void {
114
-		$this->tree->expects($this->any())
115
-			->method('getNodeForPath')
116
-			->willReturn($this->davFolder);
117
-
118
-		$this->searchFolder->expects($this->once())
119
-			->method('search')
120
-			->with(new SearchQuery(
121
-				new SearchComparison(
122
-					ISearchComparison::COMPARE_EQUAL,
123
-					'mimetype',
124
-					'foo'
125
-				),
126
-				0,
127
-				0,
128
-				[],
129
-				$this->user
130
-			))
131
-			->willReturn([
132
-				new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
133
-			]);
134
-
135
-		$query = $this->getBasicQuery(Operator::OPERATION_EQUAL, '{DAV:}getcontenttype', 'foo');
136
-		$result = $this->search->search($query);
137
-
138
-		$this->assertCount(1, $result);
139
-		$this->assertEquals('/files/test/test/path', $result[0]->href);
140
-	}
141
-
142
-	public function testSearchSize(): void {
143
-		$this->tree->expects($this->any())
144
-			->method('getNodeForPath')
145
-			->willReturn($this->davFolder);
146
-
147
-		$this->searchFolder->expects($this->once())
148
-			->method('search')
149
-			->with(new SearchQuery(
150
-				new SearchComparison(
151
-					ISearchComparison::COMPARE_GREATER_THAN,
152
-					'size',
153
-					10
154
-				),
155
-				0,
156
-				0,
157
-				[],
158
-				$this->user
159
-			))
160
-			->willReturn([
161
-				new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
162
-			]);
163
-
164
-		$query = $this->getBasicQuery(Operator::OPERATION_GREATER_THAN, FilesPlugin::SIZE_PROPERTYNAME, 10);
165
-		$result = $this->search->search($query);
166
-
167
-		$this->assertCount(1, $result);
168
-		$this->assertEquals('/files/test/test/path', $result[0]->href);
169
-	}
170
-
171
-	public function testSearchMtime(): void {
172
-		$this->tree->expects($this->any())
173
-			->method('getNodeForPath')
174
-			->willReturn($this->davFolder);
175
-
176
-		$this->searchFolder->expects($this->once())
177
-			->method('search')
178
-			->with(new SearchQuery(
179
-				new SearchComparison(
180
-					ISearchComparison::COMPARE_GREATER_THAN,
181
-					'mtime',
182
-					10
183
-				),
184
-				0,
185
-				0,
186
-				[],
187
-				$this->user
188
-			))
189
-			->willReturn([
190
-				new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
191
-			]);
192
-
193
-		$query = $this->getBasicQuery(Operator::OPERATION_GREATER_THAN, '{DAV:}getlastmodified', 10);
194
-		$result = $this->search->search($query);
195
-
196
-		$this->assertCount(1, $result);
197
-		$this->assertEquals('/files/test/test/path', $result[0]->href);
198
-	}
199
-
200
-	public function testSearchIsCollection(): void {
201
-		$this->tree->expects($this->any())
202
-			->method('getNodeForPath')
203
-			->willReturn($this->davFolder);
204
-
205
-		$this->searchFolder->expects($this->once())
206
-			->method('search')
207
-			->with(new SearchQuery(
208
-				new SearchComparison(
209
-					ISearchComparison::COMPARE_EQUAL,
210
-					'mimetype',
211
-					FileInfo::MIMETYPE_FOLDER
212
-				),
213
-				0,
214
-				0,
215
-				[],
216
-				$this->user
217
-			))
218
-			->willReturn([
219
-				new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
220
-			]);
221
-
222
-		$query = $this->getBasicQuery(Operator::OPERATION_IS_COLLECTION, 'yes');
223
-		$result = $this->search->search($query);
224
-
225
-		$this->assertCount(1, $result);
226
-		$this->assertEquals('/files/test/test/path', $result[0]->href);
227
-	}
228
-
229
-
230
-	public function testSearchInvalidProp(): void {
231
-		$this->expectException(\InvalidArgumentException::class);
232
-
233
-		$this->tree->expects($this->any())
234
-			->method('getNodeForPath')
235
-			->willReturn($this->davFolder);
236
-
237
-		$this->searchFolder->expects($this->never())
238
-			->method('search');
239
-
240
-		$query = $this->getBasicQuery(Operator::OPERATION_EQUAL, '{DAV:}getetag', 'foo');
241
-		$this->search->search($query);
242
-	}
243
-
244
-	private function getBasicQuery(string $type, string $property, int|string|null $value = null) {
245
-		$scope = new Scope('/', 'infinite');
246
-		$scope->path = '/';
247
-		$from = [$scope];
248
-		$orderBy = [];
249
-		$select = [];
250
-		if (is_null($value)) {
251
-			$where = new Operator(
252
-				$type,
253
-				[new Literal($property)]
254
-			);
255
-		} else {
256
-			$where = new Operator(
257
-				$type,
258
-				[new SearchPropertyDefinition($property, true, true, true), new Literal($value)]
259
-			);
260
-		}
261
-		$limit = new Limit();
262
-
263
-		return new Query($select, $from, $where, $orderBy, $limit);
264
-	}
265
-
266
-
267
-	public function testSearchNonFolder(): void {
268
-		$this->expectException(\InvalidArgumentException::class);
269
-
270
-		$davNode = $this->createMock(File::class);
271
-
272
-		$this->tree->expects($this->any())
273
-			->method('getNodeForPath')
274
-			->willReturn($davNode);
275
-
276
-		$query = $this->getBasicQuery(Operator::OPERATION_EQUAL, '{DAV:}displayname', 'foo');
277
-		$this->search->search($query);
278
-	}
279
-
280
-	public function testSearchLimitOwnerBasic(): void {
281
-		$this->tree->expects($this->any())
282
-			->method('getNodeForPath')
283
-			->willReturn($this->davFolder);
284
-
285
-		/** @var ISearchQuery|null $receivedQuery */
286
-		$receivedQuery = null;
287
-		$this->searchFolder
288
-			->method('search')
289
-			->willReturnCallback(function ($query) use (&$receivedQuery) {
290
-				$receivedQuery = $query;
291
-				return [
292
-					new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
293
-				];
294
-			});
295
-
296
-		$query = $this->getBasicQuery(Operator::OPERATION_EQUAL, FilesPlugin::OWNER_ID_PROPERTYNAME, $this->user->getUID());
297
-		$this->search->search($query);
298
-
299
-		$this->assertNotNull($receivedQuery);
300
-		$this->assertTrue($receivedQuery->limitToHome());
301
-
302
-		/** @var ISearchBinaryOperator $operator */
303
-		$operator = $receivedQuery->getSearchOperation();
304
-		$this->assertInstanceOf(ISearchBinaryOperator::class, $operator);
305
-		$this->assertEquals(ISearchBinaryOperator::OPERATOR_AND, $operator->getType());
306
-		$this->assertEmpty($operator->getArguments());
307
-	}
308
-
309
-	public function testSearchLimitOwnerNested(): void {
310
-		$this->tree->expects($this->any())
311
-			->method('getNodeForPath')
312
-			->willReturn($this->davFolder);
313
-
314
-		/** @var ISearchQuery|null $receivedQuery */
315
-		$receivedQuery = null;
316
-		$this->searchFolder
317
-			->method('search')
318
-			->willReturnCallback(function ($query) use (&$receivedQuery) {
319
-				$receivedQuery = $query;
320
-				return [
321
-					new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
322
-				];
323
-			});
324
-
325
-		$query = $this->getBasicQuery(Operator::OPERATION_EQUAL, FilesPlugin::OWNER_ID_PROPERTYNAME, $this->user->getUID());
326
-		$query->where = new Operator(
327
-			Operator::OPERATION_AND,
328
-			[
329
-				new Operator(
330
-					Operator::OPERATION_EQUAL,
331
-					[new SearchPropertyDefinition('{DAV:}getcontenttype', true, true, true), new Literal('image/png')]
332
-				),
333
-				new Operator(
334
-					Operator::OPERATION_EQUAL,
335
-					[new SearchPropertyDefinition(FilesPlugin::OWNER_ID_PROPERTYNAME, true, true, true), new Literal($this->user->getUID())]
336
-				),
337
-			]
338
-		);
339
-		$this->search->search($query);
340
-
341
-		$this->assertNotNull($receivedQuery);
342
-		$this->assertTrue($receivedQuery->limitToHome());
343
-
344
-		/** @var ISearchBinaryOperator $operator */
345
-		$operator = $receivedQuery->getSearchOperation();
346
-		$this->assertInstanceOf(ISearchBinaryOperator::class, $operator);
347
-		$this->assertEquals(ISearchBinaryOperator::OPERATOR_AND, $operator->getType());
348
-		$this->assertCount(2, $operator->getArguments());
349
-
350
-		/** @var ISearchBinaryOperator $operator */
351
-		$operator = $operator->getArguments()[1];
352
-		$this->assertInstanceOf(ISearchBinaryOperator::class, $operator);
353
-		$this->assertEquals(ISearchBinaryOperator::OPERATOR_AND, $operator->getType());
354
-		$this->assertEmpty($operator->getArguments());
355
-	}
356
-
357
-	public function testSearchOperatorLimit(): void {
358
-		$this->tree->expects($this->any())
359
-			->method('getNodeForPath')
360
-			->willReturn($this->davFolder);
361
-
362
-		$innerOperator = new Operator(
363
-			Operator::OPERATION_EQUAL,
364
-			[new SearchPropertyDefinition('{DAV:}getcontenttype', true, true, true), new Literal('image/png')]
365
-		);
366
-		// 5 child operators
367
-		$level1Operator = new Operator(
368
-			Operator::OPERATION_AND,
369
-			[
370
-				$innerOperator,
371
-				$innerOperator,
372
-				$innerOperator,
373
-				$innerOperator,
374
-				$innerOperator,
375
-			]
376
-		);
377
-		// 5^2 = 25 child operators
378
-		$level2Operator = new Operator(
379
-			Operator::OPERATION_AND,
380
-			[
381
-				$level1Operator,
382
-				$level1Operator,
383
-				$level1Operator,
384
-				$level1Operator,
385
-				$level1Operator,
386
-			]
387
-		);
388
-		// 5^3 = 125 child operators
389
-		$level3Operator = new Operator(
390
-			Operator::OPERATION_AND,
391
-			[
392
-				$level2Operator,
393
-				$level2Operator,
394
-				$level2Operator,
395
-				$level2Operator,
396
-				$level2Operator,
397
-			]
398
-		);
399
-
400
-		$query = $this->getBasicQuery(Operator::OPERATION_EQUAL, FilesPlugin::OWNER_ID_PROPERTYNAME, $this->user->getUID());
401
-		$query->where = $level3Operator;
402
-		$this->expectException(\InvalidArgumentException::class);
403
-		$this->search->search($query);
404
-	}
38
+    private ObjectTree&MockObject $tree;
39
+    private IUser&MockObject $user;
40
+    private IRootFolder&MockObject $rootFolder;
41
+    private IManager&MockObject $shareManager;
42
+    private View&MockObject $view;
43
+    private Folder&MockObject $searchFolder;
44
+    private Directory&MockObject $davFolder;
45
+    private FileSearchBackend $search;
46
+
47
+    protected function setUp(): void {
48
+        parent::setUp();
49
+
50
+        $this->user = $this->createMock(IUser::class);
51
+        $this->user->expects($this->any())
52
+            ->method('getUID')
53
+            ->willReturn('test');
54
+
55
+        $this->tree = $this->createMock(ObjectTree::class);
56
+        $this->view = $this->createMock(View::class);
57
+        $this->rootFolder = $this->createMock(IRootFolder::class);
58
+        $this->shareManager = $this->createMock(IManager::class);
59
+        $this->searchFolder = $this->createMock(Folder::class);
60
+        $fileInfo = $this->createMock(FileInfo::class);
61
+        $this->davFolder = $this->createMock(Directory::class);
62
+
63
+        $this->view->expects($this->any())
64
+            ->method('getRoot')
65
+            ->willReturn('');
66
+
67
+        $this->view->expects($this->any())
68
+            ->method('getRelativePath')
69
+            ->willReturnArgument(0);
70
+
71
+        $this->davFolder->expects($this->any())
72
+            ->method('getFileInfo')
73
+            ->willReturn($fileInfo);
74
+
75
+        $this->rootFolder->expects($this->any())
76
+            ->method('get')
77
+            ->willReturn($this->searchFolder);
78
+
79
+        $filesMetadataManager = $this->createMock(IFilesMetadataManager::class);
80
+
81
+        $this->search = new FileSearchBackend($this->tree, $this->user, $this->rootFolder, $this->shareManager, $this->view, $filesMetadataManager);
82
+    }
83
+
84
+    public function testSearchFilename(): void {
85
+        $this->tree->expects($this->any())
86
+            ->method('getNodeForPath')
87
+            ->willReturn($this->davFolder);
88
+
89
+        $this->searchFolder->expects($this->once())
90
+            ->method('search')
91
+            ->with(new SearchQuery(
92
+                new SearchComparison(
93
+                    ISearchComparison::COMPARE_EQUAL,
94
+                    'name',
95
+                    'foo'
96
+                ),
97
+                0,
98
+                0,
99
+                [],
100
+                $this->user
101
+            ))
102
+            ->willReturn([
103
+                new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
104
+            ]);
105
+
106
+        $query = $this->getBasicQuery(Operator::OPERATION_EQUAL, '{DAV:}displayname', 'foo');
107
+        $result = $this->search->search($query);
108
+
109
+        $this->assertCount(1, $result);
110
+        $this->assertEquals('/files/test/test/path', $result[0]->href);
111
+    }
112
+
113
+    public function testSearchMimetype(): void {
114
+        $this->tree->expects($this->any())
115
+            ->method('getNodeForPath')
116
+            ->willReturn($this->davFolder);
117
+
118
+        $this->searchFolder->expects($this->once())
119
+            ->method('search')
120
+            ->with(new SearchQuery(
121
+                new SearchComparison(
122
+                    ISearchComparison::COMPARE_EQUAL,
123
+                    'mimetype',
124
+                    'foo'
125
+                ),
126
+                0,
127
+                0,
128
+                [],
129
+                $this->user
130
+            ))
131
+            ->willReturn([
132
+                new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
133
+            ]);
134
+
135
+        $query = $this->getBasicQuery(Operator::OPERATION_EQUAL, '{DAV:}getcontenttype', 'foo');
136
+        $result = $this->search->search($query);
137
+
138
+        $this->assertCount(1, $result);
139
+        $this->assertEquals('/files/test/test/path', $result[0]->href);
140
+    }
141
+
142
+    public function testSearchSize(): void {
143
+        $this->tree->expects($this->any())
144
+            ->method('getNodeForPath')
145
+            ->willReturn($this->davFolder);
146
+
147
+        $this->searchFolder->expects($this->once())
148
+            ->method('search')
149
+            ->with(new SearchQuery(
150
+                new SearchComparison(
151
+                    ISearchComparison::COMPARE_GREATER_THAN,
152
+                    'size',
153
+                    10
154
+                ),
155
+                0,
156
+                0,
157
+                [],
158
+                $this->user
159
+            ))
160
+            ->willReturn([
161
+                new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
162
+            ]);
163
+
164
+        $query = $this->getBasicQuery(Operator::OPERATION_GREATER_THAN, FilesPlugin::SIZE_PROPERTYNAME, 10);
165
+        $result = $this->search->search($query);
166
+
167
+        $this->assertCount(1, $result);
168
+        $this->assertEquals('/files/test/test/path', $result[0]->href);
169
+    }
170
+
171
+    public function testSearchMtime(): void {
172
+        $this->tree->expects($this->any())
173
+            ->method('getNodeForPath')
174
+            ->willReturn($this->davFolder);
175
+
176
+        $this->searchFolder->expects($this->once())
177
+            ->method('search')
178
+            ->with(new SearchQuery(
179
+                new SearchComparison(
180
+                    ISearchComparison::COMPARE_GREATER_THAN,
181
+                    'mtime',
182
+                    10
183
+                ),
184
+                0,
185
+                0,
186
+                [],
187
+                $this->user
188
+            ))
189
+            ->willReturn([
190
+                new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
191
+            ]);
192
+
193
+        $query = $this->getBasicQuery(Operator::OPERATION_GREATER_THAN, '{DAV:}getlastmodified', 10);
194
+        $result = $this->search->search($query);
195
+
196
+        $this->assertCount(1, $result);
197
+        $this->assertEquals('/files/test/test/path', $result[0]->href);
198
+    }
199
+
200
+    public function testSearchIsCollection(): void {
201
+        $this->tree->expects($this->any())
202
+            ->method('getNodeForPath')
203
+            ->willReturn($this->davFolder);
204
+
205
+        $this->searchFolder->expects($this->once())
206
+            ->method('search')
207
+            ->with(new SearchQuery(
208
+                new SearchComparison(
209
+                    ISearchComparison::COMPARE_EQUAL,
210
+                    'mimetype',
211
+                    FileInfo::MIMETYPE_FOLDER
212
+                ),
213
+                0,
214
+                0,
215
+                [],
216
+                $this->user
217
+            ))
218
+            ->willReturn([
219
+                new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
220
+            ]);
221
+
222
+        $query = $this->getBasicQuery(Operator::OPERATION_IS_COLLECTION, 'yes');
223
+        $result = $this->search->search($query);
224
+
225
+        $this->assertCount(1, $result);
226
+        $this->assertEquals('/files/test/test/path', $result[0]->href);
227
+    }
228
+
229
+
230
+    public function testSearchInvalidProp(): void {
231
+        $this->expectException(\InvalidArgumentException::class);
232
+
233
+        $this->tree->expects($this->any())
234
+            ->method('getNodeForPath')
235
+            ->willReturn($this->davFolder);
236
+
237
+        $this->searchFolder->expects($this->never())
238
+            ->method('search');
239
+
240
+        $query = $this->getBasicQuery(Operator::OPERATION_EQUAL, '{DAV:}getetag', 'foo');
241
+        $this->search->search($query);
242
+    }
243
+
244
+    private function getBasicQuery(string $type, string $property, int|string|null $value = null) {
245
+        $scope = new Scope('/', 'infinite');
246
+        $scope->path = '/';
247
+        $from = [$scope];
248
+        $orderBy = [];
249
+        $select = [];
250
+        if (is_null($value)) {
251
+            $where = new Operator(
252
+                $type,
253
+                [new Literal($property)]
254
+            );
255
+        } else {
256
+            $where = new Operator(
257
+                $type,
258
+                [new SearchPropertyDefinition($property, true, true, true), new Literal($value)]
259
+            );
260
+        }
261
+        $limit = new Limit();
262
+
263
+        return new Query($select, $from, $where, $orderBy, $limit);
264
+    }
265
+
266
+
267
+    public function testSearchNonFolder(): void {
268
+        $this->expectException(\InvalidArgumentException::class);
269
+
270
+        $davNode = $this->createMock(File::class);
271
+
272
+        $this->tree->expects($this->any())
273
+            ->method('getNodeForPath')
274
+            ->willReturn($davNode);
275
+
276
+        $query = $this->getBasicQuery(Operator::OPERATION_EQUAL, '{DAV:}displayname', 'foo');
277
+        $this->search->search($query);
278
+    }
279
+
280
+    public function testSearchLimitOwnerBasic(): void {
281
+        $this->tree->expects($this->any())
282
+            ->method('getNodeForPath')
283
+            ->willReturn($this->davFolder);
284
+
285
+        /** @var ISearchQuery|null $receivedQuery */
286
+        $receivedQuery = null;
287
+        $this->searchFolder
288
+            ->method('search')
289
+            ->willReturnCallback(function ($query) use (&$receivedQuery) {
290
+                $receivedQuery = $query;
291
+                return [
292
+                    new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
293
+                ];
294
+            });
295
+
296
+        $query = $this->getBasicQuery(Operator::OPERATION_EQUAL, FilesPlugin::OWNER_ID_PROPERTYNAME, $this->user->getUID());
297
+        $this->search->search($query);
298
+
299
+        $this->assertNotNull($receivedQuery);
300
+        $this->assertTrue($receivedQuery->limitToHome());
301
+
302
+        /** @var ISearchBinaryOperator $operator */
303
+        $operator = $receivedQuery->getSearchOperation();
304
+        $this->assertInstanceOf(ISearchBinaryOperator::class, $operator);
305
+        $this->assertEquals(ISearchBinaryOperator::OPERATOR_AND, $operator->getType());
306
+        $this->assertEmpty($operator->getArguments());
307
+    }
308
+
309
+    public function testSearchLimitOwnerNested(): void {
310
+        $this->tree->expects($this->any())
311
+            ->method('getNodeForPath')
312
+            ->willReturn($this->davFolder);
313
+
314
+        /** @var ISearchQuery|null $receivedQuery */
315
+        $receivedQuery = null;
316
+        $this->searchFolder
317
+            ->method('search')
318
+            ->willReturnCallback(function ($query) use (&$receivedQuery) {
319
+                $receivedQuery = $query;
320
+                return [
321
+                    new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
322
+                ];
323
+            });
324
+
325
+        $query = $this->getBasicQuery(Operator::OPERATION_EQUAL, FilesPlugin::OWNER_ID_PROPERTYNAME, $this->user->getUID());
326
+        $query->where = new Operator(
327
+            Operator::OPERATION_AND,
328
+            [
329
+                new Operator(
330
+                    Operator::OPERATION_EQUAL,
331
+                    [new SearchPropertyDefinition('{DAV:}getcontenttype', true, true, true), new Literal('image/png')]
332
+                ),
333
+                new Operator(
334
+                    Operator::OPERATION_EQUAL,
335
+                    [new SearchPropertyDefinition(FilesPlugin::OWNER_ID_PROPERTYNAME, true, true, true), new Literal($this->user->getUID())]
336
+                ),
337
+            ]
338
+        );
339
+        $this->search->search($query);
340
+
341
+        $this->assertNotNull($receivedQuery);
342
+        $this->assertTrue($receivedQuery->limitToHome());
343
+
344
+        /** @var ISearchBinaryOperator $operator */
345
+        $operator = $receivedQuery->getSearchOperation();
346
+        $this->assertInstanceOf(ISearchBinaryOperator::class, $operator);
347
+        $this->assertEquals(ISearchBinaryOperator::OPERATOR_AND, $operator->getType());
348
+        $this->assertCount(2, $operator->getArguments());
349
+
350
+        /** @var ISearchBinaryOperator $operator */
351
+        $operator = $operator->getArguments()[1];
352
+        $this->assertInstanceOf(ISearchBinaryOperator::class, $operator);
353
+        $this->assertEquals(ISearchBinaryOperator::OPERATOR_AND, $operator->getType());
354
+        $this->assertEmpty($operator->getArguments());
355
+    }
356
+
357
+    public function testSearchOperatorLimit(): void {
358
+        $this->tree->expects($this->any())
359
+            ->method('getNodeForPath')
360
+            ->willReturn($this->davFolder);
361
+
362
+        $innerOperator = new Operator(
363
+            Operator::OPERATION_EQUAL,
364
+            [new SearchPropertyDefinition('{DAV:}getcontenttype', true, true, true), new Literal('image/png')]
365
+        );
366
+        // 5 child operators
367
+        $level1Operator = new Operator(
368
+            Operator::OPERATION_AND,
369
+            [
370
+                $innerOperator,
371
+                $innerOperator,
372
+                $innerOperator,
373
+                $innerOperator,
374
+                $innerOperator,
375
+            ]
376
+        );
377
+        // 5^2 = 25 child operators
378
+        $level2Operator = new Operator(
379
+            Operator::OPERATION_AND,
380
+            [
381
+                $level1Operator,
382
+                $level1Operator,
383
+                $level1Operator,
384
+                $level1Operator,
385
+                $level1Operator,
386
+            ]
387
+        );
388
+        // 5^3 = 125 child operators
389
+        $level3Operator = new Operator(
390
+            Operator::OPERATION_AND,
391
+            [
392
+                $level2Operator,
393
+                $level2Operator,
394
+                $level2Operator,
395
+                $level2Operator,
396
+                $level2Operator,
397
+            ]
398
+        );
399
+
400
+        $query = $this->getBasicQuery(Operator::OPERATION_EQUAL, FilesPlugin::OWNER_ID_PROPERTYNAME, $this->user->getUID());
401
+        $query->where = $level3Operator;
402
+        $this->expectException(\InvalidArgumentException::class);
403
+        $this->search->search($query);
404
+    }
405 405
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -241,7 +241,7 @@  discard block
 block discarded – undo
241 241
 		$this->search->search($query);
242 242
 	}
243 243
 
244
-	private function getBasicQuery(string $type, string $property, int|string|null $value = null) {
244
+	private function getBasicQuery(string $type, string $property, int | string | null $value = null) {
245 245
 		$scope = new Scope('/', 'infinite');
246 246
 		$scope->path = '/';
247 247
 		$from = [$scope];
@@ -286,7 +286,7 @@  discard block
 block discarded – undo
286 286
 		$receivedQuery = null;
287 287
 		$this->searchFolder
288 288
 			->method('search')
289
-			->willReturnCallback(function ($query) use (&$receivedQuery) {
289
+			->willReturnCallback(function($query) use (&$receivedQuery) {
290 290
 				$receivedQuery = $query;
291 291
 				return [
292 292
 					new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
@@ -315,7 +315,7 @@  discard block
 block discarded – undo
315 315
 		$receivedQuery = null;
316 316
 		$this->searchFolder
317 317
 			->method('search')
318
-			->willReturnCallback(function ($query) use (&$receivedQuery) {
318
+			->willReturnCallback(function($query) use (&$receivedQuery) {
319 319
 				$receivedQuery = $query;
320 320
 				return [
321 321
 					new \OC\Files\Node\Folder($this->rootFolder, $this->view, '/test/path'),
Please login to merge, or discard this patch.