Completed
Push — master ( 5d14f8...2337bd )
by Robin
27:19 queued 16s
created
apps/dav/tests/unit/DAV/GroupPrincipalTest.php 1 patch
Indentation   +308 added lines, -308 removed lines patch added patch discarded remove patch
@@ -20,312 +20,312 @@
 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
-	#[\PHPUnit\Framework\Attributes\DataProvider('searchPrincipalsDataProvider')]
196
-	public function testSearchPrincipals(bool $sharingEnabled, bool $groupSharingEnabled, bool $groupsOnly, string $test, array $result): void {
197
-		$this->shareManager->expects($this->once())
198
-			->method('shareAPIEnabled')
199
-			->willReturn($sharingEnabled);
200
-
201
-		$this->shareManager->expects($sharingEnabled ? $this->once() : $this->never())
202
-			->method('allowGroupSharing')
203
-			->willReturn($groupSharingEnabled);
204
-
205
-		if ($sharingEnabled && $groupSharingEnabled) {
206
-			$this->shareManager->expects($this->once())
207
-				->method('shareWithGroupMembersOnly')
208
-				->willReturn($groupsOnly);
209
-
210
-			if ($groupsOnly) {
211
-				$user = $this->createMock(IUser::class);
212
-				$this->userSession->expects($this->once())
213
-					->method('getUser')
214
-					->willReturn($user);
215
-
216
-				$this->groupManager->expects($this->once())
217
-					->method('getUserGroupIds')
218
-					->with($user)
219
-					->willReturn(['group1', 'group2', 'group5']);
220
-			}
221
-		} else {
222
-			$this->shareManager->expects($this->never())
223
-				->method('shareWithGroupMembersOnly');
224
-			$this->groupManager->expects($this->never())
225
-				->method($this->anything());
226
-		}
227
-
228
-		$group1 = $this->createMock(IGroup::class);
229
-		$group1->method('getGID')->willReturn('group1');
230
-		$group2 = $this->createMock(IGroup::class);
231
-		$group2->method('getGID')->willReturn('group2');
232
-		$group3 = $this->createMock(IGroup::class);
233
-		$group3->method('getGID')->willReturn('group3');
234
-		$group4 = $this->createMock(IGroup::class);
235
-		$group4->method('getGID')->willReturn('group4');
236
-		$group5 = $this->createMock(IGroup::class);
237
-		$group5->method('getGID')->willReturn('group5');
238
-
239
-		if ($sharingEnabled && $groupSharingEnabled) {
240
-			$this->groupManager->expects($this->once())
241
-				->method('search')
242
-				->with('Foo')
243
-				->willReturn([$group1, $group2, $group3, $group4, $group5]);
244
-		} else {
245
-			$this->groupManager->expects($this->never())
246
-				->method('search');
247
-		}
248
-
249
-		$this->assertSame($result, $this->connector->searchPrincipals('principals/groups',
250
-			['{DAV:}displayname' => 'Foo'], $test));
251
-	}
252
-
253
-	public static function searchPrincipalsDataProvider(): array {
254
-		return [
255
-			[true, true, false, 'allof', ['principals/groups/group1', 'principals/groups/group2', 'principals/groups/group3', 'principals/groups/group4', 'principals/groups/group5']],
256
-			[true, true, false, 'anyof', ['principals/groups/group1', 'principals/groups/group2', 'principals/groups/group3', 'principals/groups/group4', 'principals/groups/group5']],
257
-			[true, true, true, 'allof', ['principals/groups/group1', 'principals/groups/group2', 'principals/groups/group5']],
258
-			[true, true, true, 'anyof', ['principals/groups/group1', 'principals/groups/group2', 'principals/groups/group5']],
259
-			[true, false, false, 'allof', []],
260
-			[false, true, false, 'anyof', []],
261
-			[false, false, false, 'allof', []],
262
-			[false, false, false, 'anyof', []],
263
-		];
264
-	}
265
-
266
-	#[\PHPUnit\Framework\Attributes\DataProvider('findByUriDataProvider')]
267
-	public function testFindByUri(bool $sharingEnabled, bool $groupSharingEnabled, bool $groupsOnly, string $findUri, ?string $result): void {
268
-		$this->shareManager->expects($this->once())
269
-			->method('shareAPIEnabled')
270
-			->willReturn($sharingEnabled);
271
-
272
-		$this->shareManager->expects($sharingEnabled ? $this->once() : $this->never())
273
-			->method('allowGroupSharing')
274
-			->willReturn($groupSharingEnabled);
275
-
276
-		if ($sharingEnabled && $groupSharingEnabled) {
277
-			$this->shareManager->expects($this->once())
278
-				->method('shareWithGroupMembersOnly')
279
-				->willReturn($groupsOnly);
280
-
281
-			if ($groupsOnly) {
282
-				$user = $this->createMock(IUser::class);
283
-				$this->userSession->expects($this->once())
284
-					->method('getUser')
285
-					->willReturn($user);
286
-
287
-				$this->groupManager->expects($this->once())
288
-					->method('getUserGroupIds')
289
-					->with($user)
290
-					->willReturn(['group1', 'group2', 'group5']);
291
-			}
292
-		} else {
293
-			$this->shareManager->expects($this->never())
294
-				->method('shareWithGroupMembersOnly');
295
-			$this->groupManager->expects($this->never())
296
-				->method($this->anything());
297
-		}
298
-
299
-		$this->assertEquals($result, $this->connector->findByUri($findUri, 'principals/groups'));
300
-	}
301
-
302
-	public static function findByUriDataProvider(): array {
303
-		return [
304
-			[false, false, false, 'principal:principals/groups/group1', null],
305
-			[false, false, false, 'principal:principals/groups/group3', null],
306
-			[false, true, false, 'principal:principals/groups/group1', null],
307
-			[false, true, false, 'principal:principals/groups/group3', null],
308
-			[false, false, true, 'principal:principals/groups/group1', null],
309
-			[false, false, true, 'principal:principals/groups/group3', null],
310
-			[true, false, true, 'principal:principals/groups/group1', null],
311
-			[true, false, true, 'principal:principals/groups/group3', null],
312
-			[true, true, true, 'principal:principals/groups/group1', 'principals/groups/group1'],
313
-			[true, true, true, 'principal:principals/groups/group3', null],
314
-			[true, true, false, 'principal:principals/groups/group1', 'principals/groups/group1'],
315
-			[true, true, false, 'principal:principals/groups/group3', 'principals/groups/group3'],
316
-		];
317
-	}
318
-
319
-	private function mockGroup(string $gid): Group&MockObject {
320
-		$fooGroup = $this->createMock(Group::class);
321
-		$fooGroup
322
-			->expects($this->exactly(1))
323
-			->method('getGID')
324
-			->willReturn($gid);
325
-		$fooGroup
326
-			->expects($this->exactly(1))
327
-			->method('getDisplayName')
328
-			->willReturn('Group ' . $gid);
329
-		return $fooGroup;
330
-	}
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
+    #[\PHPUnit\Framework\Attributes\DataProvider('searchPrincipalsDataProvider')]
196
+    public function testSearchPrincipals(bool $sharingEnabled, bool $groupSharingEnabled, bool $groupsOnly, string $test, array $result): void {
197
+        $this->shareManager->expects($this->once())
198
+            ->method('shareAPIEnabled')
199
+            ->willReturn($sharingEnabled);
200
+
201
+        $this->shareManager->expects($sharingEnabled ? $this->once() : $this->never())
202
+            ->method('allowGroupSharing')
203
+            ->willReturn($groupSharingEnabled);
204
+
205
+        if ($sharingEnabled && $groupSharingEnabled) {
206
+            $this->shareManager->expects($this->once())
207
+                ->method('shareWithGroupMembersOnly')
208
+                ->willReturn($groupsOnly);
209
+
210
+            if ($groupsOnly) {
211
+                $user = $this->createMock(IUser::class);
212
+                $this->userSession->expects($this->once())
213
+                    ->method('getUser')
214
+                    ->willReturn($user);
215
+
216
+                $this->groupManager->expects($this->once())
217
+                    ->method('getUserGroupIds')
218
+                    ->with($user)
219
+                    ->willReturn(['group1', 'group2', 'group5']);
220
+            }
221
+        } else {
222
+            $this->shareManager->expects($this->never())
223
+                ->method('shareWithGroupMembersOnly');
224
+            $this->groupManager->expects($this->never())
225
+                ->method($this->anything());
226
+        }
227
+
228
+        $group1 = $this->createMock(IGroup::class);
229
+        $group1->method('getGID')->willReturn('group1');
230
+        $group2 = $this->createMock(IGroup::class);
231
+        $group2->method('getGID')->willReturn('group2');
232
+        $group3 = $this->createMock(IGroup::class);
233
+        $group3->method('getGID')->willReturn('group3');
234
+        $group4 = $this->createMock(IGroup::class);
235
+        $group4->method('getGID')->willReturn('group4');
236
+        $group5 = $this->createMock(IGroup::class);
237
+        $group5->method('getGID')->willReturn('group5');
238
+
239
+        if ($sharingEnabled && $groupSharingEnabled) {
240
+            $this->groupManager->expects($this->once())
241
+                ->method('search')
242
+                ->with('Foo')
243
+                ->willReturn([$group1, $group2, $group3, $group4, $group5]);
244
+        } else {
245
+            $this->groupManager->expects($this->never())
246
+                ->method('search');
247
+        }
248
+
249
+        $this->assertSame($result, $this->connector->searchPrincipals('principals/groups',
250
+            ['{DAV:}displayname' => 'Foo'], $test));
251
+    }
252
+
253
+    public static function searchPrincipalsDataProvider(): array {
254
+        return [
255
+            [true, true, false, 'allof', ['principals/groups/group1', 'principals/groups/group2', 'principals/groups/group3', 'principals/groups/group4', 'principals/groups/group5']],
256
+            [true, true, false, 'anyof', ['principals/groups/group1', 'principals/groups/group2', 'principals/groups/group3', 'principals/groups/group4', 'principals/groups/group5']],
257
+            [true, true, true, 'allof', ['principals/groups/group1', 'principals/groups/group2', 'principals/groups/group5']],
258
+            [true, true, true, 'anyof', ['principals/groups/group1', 'principals/groups/group2', 'principals/groups/group5']],
259
+            [true, false, false, 'allof', []],
260
+            [false, true, false, 'anyof', []],
261
+            [false, false, false, 'allof', []],
262
+            [false, false, false, 'anyof', []],
263
+        ];
264
+    }
265
+
266
+    #[\PHPUnit\Framework\Attributes\DataProvider('findByUriDataProvider')]
267
+    public function testFindByUri(bool $sharingEnabled, bool $groupSharingEnabled, bool $groupsOnly, string $findUri, ?string $result): void {
268
+        $this->shareManager->expects($this->once())
269
+            ->method('shareAPIEnabled')
270
+            ->willReturn($sharingEnabled);
271
+
272
+        $this->shareManager->expects($sharingEnabled ? $this->once() : $this->never())
273
+            ->method('allowGroupSharing')
274
+            ->willReturn($groupSharingEnabled);
275
+
276
+        if ($sharingEnabled && $groupSharingEnabled) {
277
+            $this->shareManager->expects($this->once())
278
+                ->method('shareWithGroupMembersOnly')
279
+                ->willReturn($groupsOnly);
280
+
281
+            if ($groupsOnly) {
282
+                $user = $this->createMock(IUser::class);
283
+                $this->userSession->expects($this->once())
284
+                    ->method('getUser')
285
+                    ->willReturn($user);
286
+
287
+                $this->groupManager->expects($this->once())
288
+                    ->method('getUserGroupIds')
289
+                    ->with($user)
290
+                    ->willReturn(['group1', 'group2', 'group5']);
291
+            }
292
+        } else {
293
+            $this->shareManager->expects($this->never())
294
+                ->method('shareWithGroupMembersOnly');
295
+            $this->groupManager->expects($this->never())
296
+                ->method($this->anything());
297
+        }
298
+
299
+        $this->assertEquals($result, $this->connector->findByUri($findUri, 'principals/groups'));
300
+    }
301
+
302
+    public static function findByUriDataProvider(): array {
303
+        return [
304
+            [false, false, false, 'principal:principals/groups/group1', null],
305
+            [false, false, false, 'principal:principals/groups/group3', null],
306
+            [false, true, false, 'principal:principals/groups/group1', null],
307
+            [false, true, false, 'principal:principals/groups/group3', null],
308
+            [false, false, true, 'principal:principals/groups/group1', null],
309
+            [false, false, true, 'principal:principals/groups/group3', null],
310
+            [true, false, true, 'principal:principals/groups/group1', null],
311
+            [true, false, true, 'principal:principals/groups/group3', null],
312
+            [true, true, true, 'principal:principals/groups/group1', 'principals/groups/group1'],
313
+            [true, true, true, 'principal:principals/groups/group3', null],
314
+            [true, true, false, 'principal:principals/groups/group1', 'principals/groups/group1'],
315
+            [true, true, false, 'principal:principals/groups/group3', 'principals/groups/group3'],
316
+        ];
317
+    }
318
+
319
+    private function mockGroup(string $gid): Group&MockObject {
320
+        $fooGroup = $this->createMock(Group::class);
321
+        $fooGroup
322
+            ->expects($this->exactly(1))
323
+            ->method('getGID')
324
+            ->willReturn($gid);
325
+        $fooGroup
326
+            ->expects($this->exactly(1))
327
+            ->method('getDisplayName')
328
+            ->willReturn('Group ' . $gid);
329
+        return $fooGroup;
330
+    }
331 331
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/DAV/CustomPropertiesBackendTest.php 2 patches
Indentation   +430 added lines, -430 removed lines patch added patch discarded remove patch
@@ -28,434 +28,434 @@
 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
-	#[\PHPUnit\Framework\Attributes\DataProvider('propFindPrincipalScheduleDefaultCalendarProviderUrlProvider')]
275
-	public function testPropFindPrincipalScheduleDefaultCalendarUrl(
276
-		string $user,
277
-		array $nodes,
278
-		array $existingProps,
279
-		array $requestedProps,
280
-		array $returnedProps,
281
-	): void {
282
-		$propFind = $this->createMock(PropFind::class);
283
-		$propFind->method('get404Properties')
284
-			->with()
285
-			->willReturn([
286
-				'{DAV:}getcontentlength',
287
-				'{DAV:}getcontenttype',
288
-				'{DAV:}getetag',
289
-			]);
290
-
291
-		$propFind->method('getRequestedProperties')
292
-			->with()
293
-			->willReturn(array_merge([
294
-				'{DAV:}getcontentlength',
295
-				'{DAV:}getcontenttype',
296
-				'{DAV:}getetag',
297
-				'{abc}def',
298
-			],
299
-				$requestedProps,
300
-			));
301
-
302
-		$this->server->method('calculateUri')
303
-			->willReturnCallback(function ($uri) {
304
-				if (!str_starts_with($uri, self::BASE_URI)) {
305
-					return trim(substr($uri, strlen(self::BASE_URI)), '/');
306
-				}
307
-				return null;
308
-			});
309
-		$this->tree->method('getNodeForPath')
310
-			->willReturnCallback(function ($uri) use ($nodes) {
311
-				if (str_starts_with($uri, 'principals/')) {
312
-					return $this->createMock(IPrincipal::class);
313
-				}
314
-				if (array_key_exists($uri, $nodes)) {
315
-					$owner = explode('/', $uri)[1];
316
-					$node = $this->createMock($nodes[$uri]);
317
-					$node->method('getOwner')
318
-						->willReturn("principals/users/$owner");
319
-					return $node;
320
-				}
321
-				throw new NotFound('Node not found');
322
-			});
323
-
324
-		$this->insertProps($user, "principals/users/$user", $existingProps);
325
-
326
-		$setProps = [];
327
-		$propFind->method('set')
328
-			->willReturnCallback(function ($name, $value, $status) use (&$setProps): void {
329
-				$setProps[$name] = $value;
330
-			});
331
-
332
-		$this->backend->propFind("principals/users/$user", $propFind);
333
-		$this->assertEquals($returnedProps, $setProps);
334
-	}
335
-
336
-	#[\PHPUnit\Framework\Attributes\DataProvider('propPatchProvider')]
337
-	public function testPropPatch(string $path, array $existing, array $props, array $result): void {
338
-		$this->server->method('calculateUri')
339
-			->willReturnCallback(function ($uri) {
340
-				if (str_starts_with($uri, self::BASE_URI)) {
341
-					return trim(substr($uri, strlen(self::BASE_URI)), '/');
342
-				}
343
-				return null;
344
-			});
345
-		$this->tree->method('getNodeForPath')
346
-			->willReturnCallback(function ($uri) {
347
-				$node = $this->createMock(Calendar::class);
348
-				$node->method('getOwner')
349
-					->willReturn('principals/users/' . $this->user->getUID());
350
-				return $node;
351
-			});
352
-
353
-		$this->insertProps($this->user->getUID(), $path, $existing);
354
-		$propPatch = new PropPatch($props);
355
-
356
-		$this->backend->propPatch($path, $propPatch);
357
-		$propPatch->commit();
358
-
359
-		$storedProps = $this->getProps($this->user->getUID(), $path);
360
-		$this->assertEquals($result, $storedProps);
361
-	}
362
-
363
-	public static function propPatchProvider(): array {
364
-		$longPath = str_repeat('long_path', 100);
365
-		return [
366
-			['foo_bar_path_1337', [], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
367
-			['foo_bar_path_1337', ['{DAV:}displayname' => 'foo'], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
368
-			['foo_bar_path_1337', ['{DAV:}displayname' => 'foo'], ['{DAV:}displayname' => null], []],
369
-			[$longPath, [], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
370
-			['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/')]],
371
-			['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/')]],
372
-		];
373
-	}
374
-
375
-	public function testPropPatchWithUnsuitableCalendar(): void {
376
-		$path = 'principals/users/' . $this->user->getUID();
377
-
378
-		$node = $this->createMock(Calendar::class);
379
-		$node->expects(self::once())
380
-			->method('getOwner')
381
-			->willReturn($path);
382
-
383
-		$this->defaultCalendarValidator->expects(self::once())
384
-			->method('validateScheduleDefaultCalendar')
385
-			->with($node)
386
-			->willThrowException(new \Sabre\DAV\Exception('Invalid calendar'));
387
-
388
-		$this->server->method('calculateUri')
389
-			->willReturnCallback(function ($uri) {
390
-				if (str_starts_with($uri, self::BASE_URI)) {
391
-					return trim(substr($uri, strlen(self::BASE_URI)), '/');
392
-				}
393
-				return null;
394
-			});
395
-		$this->tree->expects(self::once())
396
-			->method('getNodeForPath')
397
-			->with('foo/bar/')
398
-			->willReturn($node);
399
-
400
-		$storedProps = $this->getProps($this->user->getUID(), $path);
401
-		$this->assertEquals([], $storedProps);
402
-
403
-		$propPatch = new PropPatch([
404
-			'{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/bar/'),
405
-		]);
406
-		$this->backend->propPatch($path, $propPatch);
407
-		try {
408
-			$propPatch->commit();
409
-		} catch (\Throwable $e) {
410
-			$this->assertInstanceOf(\Sabre\DAV\Exception::class, $e);
411
-		}
412
-
413
-		$storedProps = $this->getProps($this->user->getUID(), $path);
414
-		$this->assertEquals([], $storedProps);
415
-	}
416
-
417
-	#[\PHPUnit\Framework\Attributes\DataProvider('deleteProvider')]
418
-	public function testDelete(string $path): void {
419
-		$this->insertProps('dummy_user_42', $path, ['foo' => 'bar']);
420
-		$this->backend->delete($path);
421
-		$this->assertEquals([], $this->getProps('dummy_user_42', $path));
422
-	}
423
-
424
-	public static function deleteProvider(): array {
425
-		return [
426
-			['foo_bar_path_1337'],
427
-			[str_repeat('long_path', 100)]
428
-		];
429
-	}
430
-
431
-	#[\PHPUnit\Framework\Attributes\DataProvider('moveProvider')]
432
-	public function testMove(string $source, string $target): void {
433
-		$this->insertProps('dummy_user_42', $source, ['foo' => 'bar']);
434
-		$this->backend->move($source, $target);
435
-		$this->assertEquals([], $this->getProps('dummy_user_42', $source));
436
-		$this->assertEquals(['foo' => 'bar'], $this->getProps('dummy_user_42', $target));
437
-	}
438
-
439
-	public static function moveProvider(): array {
440
-		return [
441
-			['foo_bar_path_1337', 'foo_bar_path_7333'],
442
-			[str_repeat('long_path1', 100), str_repeat('long_path2', 100)]
443
-		];
444
-	}
445
-
446
-	public function testDecodeValueFromDatabaseObjectCurrent(): void {
447
-		$propertyValue = 'O:48:"Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp":1:{s:8:"\x00*\x00value";s:6:"opaque";}';
448
-		$propertyType = 3;
449
-		$decodeValue = $this->invokePrivate($this->backend, 'decodeValueFromDatabase', [$propertyValue, $propertyType]);
450
-		$this->assertInstanceOf(\Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp::class, $decodeValue);
451
-		$this->assertEquals('opaque', $decodeValue->getValue());
452
-	}
453
-
454
-	public function testDecodeValueFromDatabaseObjectLegacy(): void {
455
-		$propertyValue = 'O:48:"Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp":1:{s:8:"' . chr(0) . '*' . chr(0) . 'value";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
-	}
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
+    #[\PHPUnit\Framework\Attributes\DataProvider('propFindPrincipalScheduleDefaultCalendarProviderUrlProvider')]
275
+    public function testPropFindPrincipalScheduleDefaultCalendarUrl(
276
+        string $user,
277
+        array $nodes,
278
+        array $existingProps,
279
+        array $requestedProps,
280
+        array $returnedProps,
281
+    ): void {
282
+        $propFind = $this->createMock(PropFind::class);
283
+        $propFind->method('get404Properties')
284
+            ->with()
285
+            ->willReturn([
286
+                '{DAV:}getcontentlength',
287
+                '{DAV:}getcontenttype',
288
+                '{DAV:}getetag',
289
+            ]);
290
+
291
+        $propFind->method('getRequestedProperties')
292
+            ->with()
293
+            ->willReturn(array_merge([
294
+                '{DAV:}getcontentlength',
295
+                '{DAV:}getcontenttype',
296
+                '{DAV:}getetag',
297
+                '{abc}def',
298
+            ],
299
+                $requestedProps,
300
+            ));
301
+
302
+        $this->server->method('calculateUri')
303
+            ->willReturnCallback(function ($uri) {
304
+                if (!str_starts_with($uri, self::BASE_URI)) {
305
+                    return trim(substr($uri, strlen(self::BASE_URI)), '/');
306
+                }
307
+                return null;
308
+            });
309
+        $this->tree->method('getNodeForPath')
310
+            ->willReturnCallback(function ($uri) use ($nodes) {
311
+                if (str_starts_with($uri, 'principals/')) {
312
+                    return $this->createMock(IPrincipal::class);
313
+                }
314
+                if (array_key_exists($uri, $nodes)) {
315
+                    $owner = explode('/', $uri)[1];
316
+                    $node = $this->createMock($nodes[$uri]);
317
+                    $node->method('getOwner')
318
+                        ->willReturn("principals/users/$owner");
319
+                    return $node;
320
+                }
321
+                throw new NotFound('Node not found');
322
+            });
323
+
324
+        $this->insertProps($user, "principals/users/$user", $existingProps);
325
+
326
+        $setProps = [];
327
+        $propFind->method('set')
328
+            ->willReturnCallback(function ($name, $value, $status) use (&$setProps): void {
329
+                $setProps[$name] = $value;
330
+            });
331
+
332
+        $this->backend->propFind("principals/users/$user", $propFind);
333
+        $this->assertEquals($returnedProps, $setProps);
334
+    }
335
+
336
+    #[\PHPUnit\Framework\Attributes\DataProvider('propPatchProvider')]
337
+    public function testPropPatch(string $path, array $existing, array $props, array $result): void {
338
+        $this->server->method('calculateUri')
339
+            ->willReturnCallback(function ($uri) {
340
+                if (str_starts_with($uri, self::BASE_URI)) {
341
+                    return trim(substr($uri, strlen(self::BASE_URI)), '/');
342
+                }
343
+                return null;
344
+            });
345
+        $this->tree->method('getNodeForPath')
346
+            ->willReturnCallback(function ($uri) {
347
+                $node = $this->createMock(Calendar::class);
348
+                $node->method('getOwner')
349
+                    ->willReturn('principals/users/' . $this->user->getUID());
350
+                return $node;
351
+            });
352
+
353
+        $this->insertProps($this->user->getUID(), $path, $existing);
354
+        $propPatch = new PropPatch($props);
355
+
356
+        $this->backend->propPatch($path, $propPatch);
357
+        $propPatch->commit();
358
+
359
+        $storedProps = $this->getProps($this->user->getUID(), $path);
360
+        $this->assertEquals($result, $storedProps);
361
+    }
362
+
363
+    public static function propPatchProvider(): array {
364
+        $longPath = str_repeat('long_path', 100);
365
+        return [
366
+            ['foo_bar_path_1337', [], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
367
+            ['foo_bar_path_1337', ['{DAV:}displayname' => 'foo'], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
368
+            ['foo_bar_path_1337', ['{DAV:}displayname' => 'foo'], ['{DAV:}displayname' => null], []],
369
+            [$longPath, [], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
370
+            ['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/')]],
371
+            ['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/')]],
372
+        ];
373
+    }
374
+
375
+    public function testPropPatchWithUnsuitableCalendar(): void {
376
+        $path = 'principals/users/' . $this->user->getUID();
377
+
378
+        $node = $this->createMock(Calendar::class);
379
+        $node->expects(self::once())
380
+            ->method('getOwner')
381
+            ->willReturn($path);
382
+
383
+        $this->defaultCalendarValidator->expects(self::once())
384
+            ->method('validateScheduleDefaultCalendar')
385
+            ->with($node)
386
+            ->willThrowException(new \Sabre\DAV\Exception('Invalid calendar'));
387
+
388
+        $this->server->method('calculateUri')
389
+            ->willReturnCallback(function ($uri) {
390
+                if (str_starts_with($uri, self::BASE_URI)) {
391
+                    return trim(substr($uri, strlen(self::BASE_URI)), '/');
392
+                }
393
+                return null;
394
+            });
395
+        $this->tree->expects(self::once())
396
+            ->method('getNodeForPath')
397
+            ->with('foo/bar/')
398
+            ->willReturn($node);
399
+
400
+        $storedProps = $this->getProps($this->user->getUID(), $path);
401
+        $this->assertEquals([], $storedProps);
402
+
403
+        $propPatch = new PropPatch([
404
+            '{urn:ietf:params:xml:ns:caldav}schedule-default-calendar-URL' => new Href('foo/bar/'),
405
+        ]);
406
+        $this->backend->propPatch($path, $propPatch);
407
+        try {
408
+            $propPatch->commit();
409
+        } catch (\Throwable $e) {
410
+            $this->assertInstanceOf(\Sabre\DAV\Exception::class, $e);
411
+        }
412
+
413
+        $storedProps = $this->getProps($this->user->getUID(), $path);
414
+        $this->assertEquals([], $storedProps);
415
+    }
416
+
417
+    #[\PHPUnit\Framework\Attributes\DataProvider('deleteProvider')]
418
+    public function testDelete(string $path): void {
419
+        $this->insertProps('dummy_user_42', $path, ['foo' => 'bar']);
420
+        $this->backend->delete($path);
421
+        $this->assertEquals([], $this->getProps('dummy_user_42', $path));
422
+    }
423
+
424
+    public static function deleteProvider(): array {
425
+        return [
426
+            ['foo_bar_path_1337'],
427
+            [str_repeat('long_path', 100)]
428
+        ];
429
+    }
430
+
431
+    #[\PHPUnit\Framework\Attributes\DataProvider('moveProvider')]
432
+    public function testMove(string $source, string $target): void {
433
+        $this->insertProps('dummy_user_42', $source, ['foo' => 'bar']);
434
+        $this->backend->move($source, $target);
435
+        $this->assertEquals([], $this->getProps('dummy_user_42', $source));
436
+        $this->assertEquals(['foo' => 'bar'], $this->getProps('dummy_user_42', $target));
437
+    }
438
+
439
+    public static function moveProvider(): array {
440
+        return [
441
+            ['foo_bar_path_1337', 'foo_bar_path_7333'],
442
+            [str_repeat('long_path1', 100), str_repeat('long_path2', 100)]
443
+        ];
444
+    }
445
+
446
+    public function testDecodeValueFromDatabaseObjectCurrent(): void {
447
+        $propertyValue = 'O:48:"Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp":1:{s:8:"\x00*\x00value";s:6:"opaque";}';
448
+        $propertyType = 3;
449
+        $decodeValue = $this->invokePrivate($this->backend, 'decodeValueFromDatabase', [$propertyValue, $propertyType]);
450
+        $this->assertInstanceOf(\Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp::class, $decodeValue);
451
+        $this->assertEquals('opaque', $decodeValue->getValue());
452
+    }
453
+
454
+    public function testDecodeValueFromDatabaseObjectLegacy(): void {
455
+        $propertyValue = 'O:48:"Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp":1:{s:8:"' . chr(0) . '*' . chr(0) . 'value";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 461
 }
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/')],
@@ -300,14 +300,14 @@  discard block
 block discarded – undo
300 300
 			));
301 301
 
302 302
 		$this->server->method('calculateUri')
303
-			->willReturnCallback(function ($uri) {
303
+			->willReturnCallback(function($uri) {
304 304
 				if (!str_starts_with($uri, self::BASE_URI)) {
305 305
 					return trim(substr($uri, strlen(self::BASE_URI)), '/');
306 306
 				}
307 307
 				return null;
308 308
 			});
309 309
 		$this->tree->method('getNodeForPath')
310
-			->willReturnCallback(function ($uri) use ($nodes) {
310
+			->willReturnCallback(function($uri) use ($nodes) {
311 311
 				if (str_starts_with($uri, 'principals/')) {
312 312
 					return $this->createMock(IPrincipal::class);
313 313
 				}
@@ -325,7 +325,7 @@  discard block
 block discarded – undo
325 325
 
326 326
 		$setProps = [];
327 327
 		$propFind->method('set')
328
-			->willReturnCallback(function ($name, $value, $status) use (&$setProps): void {
328
+			->willReturnCallback(function($name, $value, $status) use (&$setProps): void {
329 329
 				$setProps[$name] = $value;
330 330
 			});
331 331
 
@@ -336,17 +336,17 @@  discard block
 block discarded – undo
336 336
 	#[\PHPUnit\Framework\Attributes\DataProvider('propPatchProvider')]
337 337
 	public function testPropPatch(string $path, array $existing, array $props, array $result): void {
338 338
 		$this->server->method('calculateUri')
339
-			->willReturnCallback(function ($uri) {
339
+			->willReturnCallback(function($uri) {
340 340
 				if (str_starts_with($uri, self::BASE_URI)) {
341 341
 					return trim(substr($uri, strlen(self::BASE_URI)), '/');
342 342
 				}
343 343
 				return null;
344 344
 			});
345 345
 		$this->tree->method('getNodeForPath')
346
-			->willReturnCallback(function ($uri) {
346
+			->willReturnCallback(function($uri) {
347 347
 				$node = $this->createMock(Calendar::class);
348 348
 				$node->method('getOwner')
349
-					->willReturn('principals/users/' . $this->user->getUID());
349
+					->willReturn('principals/users/'.$this->user->getUID());
350 350
 				return $node;
351 351
 			});
352 352
 
@@ -368,12 +368,12 @@  discard block
 block discarded – undo
368 368
 			['foo_bar_path_1337', ['{DAV:}displayname' => 'foo'], ['{DAV:}displayname' => null], []],
369 369
 			[$longPath, [], ['{DAV:}displayname' => 'anything'], ['{DAV:}displayname' => 'anything']],
370 370
 			['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/')]],
371
-			['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/')]],
371
+			['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/')]],
372 372
 		];
373 373
 	}
374 374
 
375 375
 	public function testPropPatchWithUnsuitableCalendar(): void {
376
-		$path = 'principals/users/' . $this->user->getUID();
376
+		$path = 'principals/users/'.$this->user->getUID();
377 377
 
378 378
 		$node = $this->createMock(Calendar::class);
379 379
 		$node->expects(self::once())
@@ -386,7 +386,7 @@  discard block
 block discarded – undo
386 386
 			->willThrowException(new \Sabre\DAV\Exception('Invalid calendar'));
387 387
 
388 388
 		$this->server->method('calculateUri')
389
-			->willReturnCallback(function ($uri) {
389
+			->willReturnCallback(function($uri) {
390 390
 				if (str_starts_with($uri, self::BASE_URI)) {
391 391
 					return trim(substr($uri, strlen(self::BASE_URI)), '/');
392 392
 				}
@@ -452,7 +452,7 @@  discard block
 block discarded – undo
452 452
 	}
453 453
 
454 454
 	public function testDecodeValueFromDatabaseObjectLegacy(): void {
455
-		$propertyValue = 'O:48:"Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp":1:{s:8:"' . chr(0) . '*' . chr(0) . 'value";s:6:"opaque";}';
455
+		$propertyValue = 'O:48:"Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp":1:{s:8:"'.chr(0).'*'.chr(0).'value";s:6:"opaque";}';
456 456
 		$propertyType = 3;
457 457
 		$decodeValue = $this->invokePrivate($this->backend, 'decodeValueFromDatabase', [$propertyValue, $propertyType]);
458 458
 		$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   +136 added lines, -136 removed lines patch added patch discarded remove patch
@@ -28,140 +28,140 @@
 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, true],
78
-			// has no attribute permissions-download - can get file
79
-			[false, null, true, true],
80
-			// has attribute permissions-download enabled - can get file version
81
-			[true, true, true, true],
82
-			// has no attribute permissions-download - can get file version
83
-			[true, null, true, true],
84
-			// has attribute permissions-download disabled - cannot get the file
85
-			[false, false, false, false],
86
-			// has attribute permissions-download disabled - cannot get the file version
87
-			[true, false, false, false],
88
-
89
-			// Has global allowViewWithoutDownload option enabled
90
-			// has attribute permissions-download disabled - can get file
91
-			[false, false, false, true],
92
-			// has attribute permissions-download disabled - can get file version
93
-			[true, false, false, true],
94
-		];
95
-	}
96
-
97
-	#[\PHPUnit\Framework\Attributes\DataProvider('providesDataForCanGet')]
98
-	public function testCanGet(bool $isVersion, ?bool $attrEnabled, bool $expectCanDownloadFile, bool $allowViewWithoutDownload): void {
99
-		$nodeInfo = $this->createMock(File::class);
100
-		if ($isVersion) {
101
-			$davPath = 'versions/alice/versions/117/123456';
102
-			$version = $this->createMock(IVersion::class);
103
-			$version->expects($this->once())
104
-				->method('getSourceFile')
105
-				->willReturn($nodeInfo);
106
-			$davNode = $this->createMock(VersionFile::class);
107
-			$davNode->expects($this->once())
108
-				->method('getVersion')
109
-				->willReturn($version);
110
-
111
-			$currentUser = $this->createMock(IUser::class);
112
-			$currentUser->expects($this->once())
113
-				->method('getUID')
114
-				->willReturn('alice');
115
-			$nodeInfo->expects($this->once())
116
-				->method('getOwner')
117
-				->willReturn($currentUser);
118
-
119
-			$nodeInfo = $this->createMock(File::class);
120
-			$owner = $this->createMock(IUser::class);
121
-			$owner->expects($this->once())
122
-				->method('getUID')
123
-				->willReturn('bob');
124
-			$this->userFolder->expects($this->once())
125
-				->method('getById')
126
-				->willReturn([$nodeInfo]);
127
-			$this->userFolder->expects($this->once())
128
-				->method('getOwner')
129
-				->willReturn($owner);
130
-		} else {
131
-			$davPath = 'files/path/to/file.odt';
132
-			$davNode = $this->createMock(DavFile::class);
133
-			$davNode->method('getNode')->willReturn($nodeInfo);
134
-		}
135
-
136
-		$this->request->expects($this->once())->method('getPath')->willReturn($davPath);
137
-
138
-		$this->tree->expects($this->once())
139
-			->method('getNodeForPath')
140
-			->with($davPath)
141
-			->willReturn($davNode);
142
-
143
-		$storage = $this->createMock(SharedStorage::class);
144
-		$share = $this->createMock(IShare::class);
145
-		$nodeInfo->expects($this->once())
146
-			->method('getStorage')
147
-			->willReturn($storage);
148
-		$storage->method('instanceOfStorage')->with(ISharedStorage::class)->willReturn(true);
149
-		$storage->method('getShare')->willReturn($share);
150
-
151
-		$extAttr = $this->createMock(IAttributes::class);
152
-		$share->method('getAttributes')->willReturn($extAttr);
153
-		$extAttr->expects($this->once())
154
-			->method('getAttribute')
155
-			->with('permissions', 'download')
156
-			->willReturn($attrEnabled);
157
-
158
-		$share->expects($this->once())
159
-			->method('canSeeContent')
160
-			->willReturn($allowViewWithoutDownload);
161
-
162
-		if (!$expectCanDownloadFile) {
163
-			$this->expectException(Forbidden::class);
164
-		}
165
-		$this->plugin->checkViewOnly($this->request);
166
-	}
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, true],
78
+            // has no attribute permissions-download - can get file
79
+            [false, null, true, true],
80
+            // has attribute permissions-download enabled - can get file version
81
+            [true, true, true, true],
82
+            // has no attribute permissions-download - can get file version
83
+            [true, null, true, true],
84
+            // has attribute permissions-download disabled - cannot get the file
85
+            [false, false, false, false],
86
+            // has attribute permissions-download disabled - cannot get the file version
87
+            [true, false, false, false],
88
+
89
+            // Has global allowViewWithoutDownload option enabled
90
+            // has attribute permissions-download disabled - can get file
91
+            [false, false, false, true],
92
+            // has attribute permissions-download disabled - can get file version
93
+            [true, false, false, true],
94
+        ];
95
+    }
96
+
97
+    #[\PHPUnit\Framework\Attributes\DataProvider('providesDataForCanGet')]
98
+    public function testCanGet(bool $isVersion, ?bool $attrEnabled, bool $expectCanDownloadFile, bool $allowViewWithoutDownload): void {
99
+        $nodeInfo = $this->createMock(File::class);
100
+        if ($isVersion) {
101
+            $davPath = 'versions/alice/versions/117/123456';
102
+            $version = $this->createMock(IVersion::class);
103
+            $version->expects($this->once())
104
+                ->method('getSourceFile')
105
+                ->willReturn($nodeInfo);
106
+            $davNode = $this->createMock(VersionFile::class);
107
+            $davNode->expects($this->once())
108
+                ->method('getVersion')
109
+                ->willReturn($version);
110
+
111
+            $currentUser = $this->createMock(IUser::class);
112
+            $currentUser->expects($this->once())
113
+                ->method('getUID')
114
+                ->willReturn('alice');
115
+            $nodeInfo->expects($this->once())
116
+                ->method('getOwner')
117
+                ->willReturn($currentUser);
118
+
119
+            $nodeInfo = $this->createMock(File::class);
120
+            $owner = $this->createMock(IUser::class);
121
+            $owner->expects($this->once())
122
+                ->method('getUID')
123
+                ->willReturn('bob');
124
+            $this->userFolder->expects($this->once())
125
+                ->method('getById')
126
+                ->willReturn([$nodeInfo]);
127
+            $this->userFolder->expects($this->once())
128
+                ->method('getOwner')
129
+                ->willReturn($owner);
130
+        } else {
131
+            $davPath = 'files/path/to/file.odt';
132
+            $davNode = $this->createMock(DavFile::class);
133
+            $davNode->method('getNode')->willReturn($nodeInfo);
134
+        }
135
+
136
+        $this->request->expects($this->once())->method('getPath')->willReturn($davPath);
137
+
138
+        $this->tree->expects($this->once())
139
+            ->method('getNodeForPath')
140
+            ->with($davPath)
141
+            ->willReturn($davNode);
142
+
143
+        $storage = $this->createMock(SharedStorage::class);
144
+        $share = $this->createMock(IShare::class);
145
+        $nodeInfo->expects($this->once())
146
+            ->method('getStorage')
147
+            ->willReturn($storage);
148
+        $storage->method('instanceOfStorage')->with(ISharedStorage::class)->willReturn(true);
149
+        $storage->method('getShare')->willReturn($share);
150
+
151
+        $extAttr = $this->createMock(IAttributes::class);
152
+        $share->method('getAttributes')->willReturn($extAttr);
153
+        $extAttr->expects($this->once())
154
+            ->method('getAttribute')
155
+            ->with('permissions', 'download')
156
+            ->willReturn($attrEnabled);
157
+
158
+        $share->expects($this->once())
159
+            ->method('canSeeContent')
160
+            ->willReturn($allowViewWithoutDownload);
161
+
162
+        if (!$expectCanDownloadFile) {
163
+            $this->expectException(Forbidden::class);
164
+        }
165
+        $this->plugin->checkViewOnly($this->request);
166
+    }
167 167
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/DAV/SystemPrincipalBackendTest.php 1 patch
Indentation   +72 added lines, -72 removed lines patch added patch discarded remove patch
@@ -14,87 +14,87 @@
 block discarded – undo
14 14
 
15 15
 class SystemPrincipalBackendTest extends TestCase {
16 16
 
17
-	#[\PHPUnit\Framework\Attributes\DataProvider('providesPrefix')]
18
-	public function testGetPrincipalsByPrefix(array $expected, string $prefix): void {
19
-		$backend = new SystemPrincipalBackend();
20
-		$result = $backend->getPrincipalsByPrefix($prefix);
21
-		$this->assertEquals($expected, $result);
22
-	}
17
+    #[\PHPUnit\Framework\Attributes\DataProvider('providesPrefix')]
18
+    public function testGetPrincipalsByPrefix(array $expected, string $prefix): void {
19
+        $backend = new SystemPrincipalBackend();
20
+        $result = $backend->getPrincipalsByPrefix($prefix);
21
+        $this->assertEquals($expected, $result);
22
+    }
23 23
 
24
-	public static function providesPrefix(): array {
25
-		return [
26
-			[[], ''],
27
-			[[[
28
-				'uri' => 'principals/system/system',
29
-				'{DAV:}displayname' => 'system',
30
-			],
31
-				[
32
-					'uri' => 'principals/system/public',
33
-					'{DAV:}displayname' => 'public',
34
-				]
35
-			], 'principals/system'],
36
-		];
37
-	}
24
+    public static function providesPrefix(): array {
25
+        return [
26
+            [[], ''],
27
+            [[[
28
+                'uri' => 'principals/system/system',
29
+                '{DAV:}displayname' => 'system',
30
+            ],
31
+                [
32
+                    'uri' => 'principals/system/public',
33
+                    '{DAV:}displayname' => 'public',
34
+                ]
35
+            ], 'principals/system'],
36
+        ];
37
+    }
38 38
 
39
-	#[\PHPUnit\Framework\Attributes\DataProvider('providesPath')]
40
-	public function testGetPrincipalByPath(?array $expected, string $path): void {
41
-		$backend = new SystemPrincipalBackend();
42
-		$result = $backend->getPrincipalByPath($path);
43
-		$this->assertEquals($expected, $result);
44
-	}
39
+    #[\PHPUnit\Framework\Attributes\DataProvider('providesPath')]
40
+    public function testGetPrincipalByPath(?array $expected, string $path): void {
41
+        $backend = new SystemPrincipalBackend();
42
+        $result = $backend->getPrincipalByPath($path);
43
+        $this->assertEquals($expected, $result);
44
+    }
45 45
 
46
-	public static function providesPath(): array {
47
-		return [
48
-			[null, ''],
49
-			[null, 'principals'],
50
-			[null, 'principals/system'],
51
-			[[
52
-				'uri' => 'principals/system/system',
53
-				'{DAV:}displayname' => 'system',
54
-			], 'principals/system/system'],
55
-		];
56
-	}
46
+    public static function providesPath(): array {
47
+        return [
48
+            [null, ''],
49
+            [null, 'principals'],
50
+            [null, 'principals/system'],
51
+            [[
52
+                'uri' => 'principals/system/system',
53
+                '{DAV:}displayname' => 'system',
54
+            ], 'principals/system/system'],
55
+        ];
56
+    }
57 57
 
58
-	#[\PHPUnit\Framework\Attributes\DataProvider('providesPrincipalForGetGroupMemberSet')]
59
-	public function testGetGroupMemberSetExceptional(?string $principal): void {
60
-		$this->expectException(Exception::class);
61
-		$this->expectExceptionMessage('Principal not found');
58
+    #[\PHPUnit\Framework\Attributes\DataProvider('providesPrincipalForGetGroupMemberSet')]
59
+    public function testGetGroupMemberSetExceptional(?string $principal): void {
60
+        $this->expectException(Exception::class);
61
+        $this->expectExceptionMessage('Principal not found');
62 62
 
63
-		$backend = new SystemPrincipalBackend();
64
-		$backend->getGroupMemberSet($principal);
65
-	}
63
+        $backend = new SystemPrincipalBackend();
64
+        $backend->getGroupMemberSet($principal);
65
+    }
66 66
 
67
-	public static function providesPrincipalForGetGroupMemberSet(): array {
68
-		return [
69
-			[null],
70
-			['principals/system'],
71
-		];
72
-	}
67
+    public static function providesPrincipalForGetGroupMemberSet(): array {
68
+        return [
69
+            [null],
70
+            ['principals/system'],
71
+        ];
72
+    }
73 73
 
74
-	public function testGetGroupMemberSet(): void {
75
-		$backend = new SystemPrincipalBackend();
76
-		$result = $backend->getGroupMemberSet('principals/system/system');
77
-		$this->assertEquals(['principals/system/system'], $result);
78
-	}
74
+    public function testGetGroupMemberSet(): void {
75
+        $backend = new SystemPrincipalBackend();
76
+        $result = $backend->getGroupMemberSet('principals/system/system');
77
+        $this->assertEquals(['principals/system/system'], $result);
78
+    }
79 79
 
80
-	#[\PHPUnit\Framework\Attributes\DataProvider('providesPrincipalForGetGroupMembership')]
81
-	public function testGetGroupMembershipExceptional(string $principal): void {
82
-		$this->expectException(Exception::class);
83
-		$this->expectExceptionMessage('Principal not found');
80
+    #[\PHPUnit\Framework\Attributes\DataProvider('providesPrincipalForGetGroupMembership')]
81
+    public function testGetGroupMembershipExceptional(string $principal): void {
82
+        $this->expectException(Exception::class);
83
+        $this->expectExceptionMessage('Principal not found');
84 84
 
85
-		$backend = new SystemPrincipalBackend();
86
-		$backend->getGroupMembership($principal);
87
-	}
85
+        $backend = new SystemPrincipalBackend();
86
+        $backend->getGroupMembership($principal);
87
+    }
88 88
 
89
-	public static function providesPrincipalForGetGroupMembership(): array {
90
-		return [
91
-			['principals/system/a'],
92
-		];
93
-	}
89
+    public static function providesPrincipalForGetGroupMembership(): array {
90
+        return [
91
+            ['principals/system/a'],
92
+        ];
93
+    }
94 94
 
95
-	public function testGetGroupMembership(): void {
96
-		$backend = new SystemPrincipalBackend();
97
-		$result = $backend->getGroupMembership('principals/system/system');
98
-		$this->assertEquals([], $result);
99
-	}
95
+    public function testGetGroupMembership(): void {
96
+        $backend = new SystemPrincipalBackend();
97
+        $result = $backend->getGroupMembership('principals/system/system');
98
+        $this->assertEquals([], $result);
99
+    }
100 100
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Search/EventsSearchProviderTest.php 1 patch
Indentation   +424 added lines, -424 removed lines patch added patch discarded remove patch
@@ -23,428 +23,428 @@
 block discarded – undo
23 23
 use Test\TestCase;
24 24
 
25 25
 class EventsSearchProviderTest extends TestCase {
26
-	private IAppManager&MockObject $appManager;
27
-	private IL10N&MockObject $l10n;
28
-	private IURLGenerator&MockObject $urlGenerator;
29
-	private CalDavBackend&MockObject $backend;
30
-	private EventsSearchProvider $provider;
31
-
32
-	// NO SUMMARY
33
-	private static string $vEvent0 = 'BEGIN:VCALENDAR' . PHP_EOL
34
-		. 'VERSION:2.0' . PHP_EOL
35
-		. 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN' . PHP_EOL
36
-		. 'CALSCALE:GREGORIAN' . PHP_EOL
37
-		. 'BEGIN:VEVENT' . PHP_EOL
38
-		. 'CREATED:20161004T144433Z' . PHP_EOL
39
-		. 'UID:85560E76-1B0D-47E1-A735-21625767FCA4' . PHP_EOL
40
-		. 'DTEND;VALUE=DATE:20161008' . PHP_EOL
41
-		. 'TRANSP:TRANSPARENT' . PHP_EOL
42
-		. 'DTSTART;VALUE=DATE:20161005' . PHP_EOL
43
-		. 'DTSTAMP:20161004T144437Z' . PHP_EOL
44
-		. 'SEQUENCE:0' . PHP_EOL
45
-		. 'END:VEVENT' . PHP_EOL
46
-		. 'END:VCALENDAR';
47
-
48
-	// TIMED SAME DAY
49
-	private static string $vEvent1 = 'BEGIN:VCALENDAR' . PHP_EOL
50
-		. 'VERSION:2.0' . PHP_EOL
51
-		. 'PRODID:-//Tests//' . PHP_EOL
52
-		. 'CALSCALE:GREGORIAN' . PHP_EOL
53
-		. 'BEGIN:VTIMEZONE' . PHP_EOL
54
-		. 'TZID:Europe/Berlin' . PHP_EOL
55
-		. 'BEGIN:DAYLIGHT' . PHP_EOL
56
-		. 'TZOFFSETFROM:+0100' . PHP_EOL
57
-		. 'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU' . PHP_EOL
58
-		. 'DTSTART:19810329T020000' . PHP_EOL
59
-		. 'TZNAME:GMT+2' . PHP_EOL
60
-		. 'TZOFFSETTO:+0200' . PHP_EOL
61
-		. 'END:DAYLIGHT' . PHP_EOL
62
-		. 'BEGIN:STANDARD' . PHP_EOL
63
-		. 'TZOFFSETFROM:+0200' . PHP_EOL
64
-		. 'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU' . PHP_EOL
65
-		. 'DTSTART:19961027T030000' . PHP_EOL
66
-		. 'TZNAME:GMT+1' . PHP_EOL
67
-		. 'TZOFFSETTO:+0100' . PHP_EOL
68
-		. 'END:STANDARD' . PHP_EOL
69
-		. 'END:VTIMEZONE' . PHP_EOL
70
-		. 'BEGIN:VEVENT' . PHP_EOL
71
-		. 'CREATED:20160809T163629Z' . PHP_EOL
72
-		. 'UID:0AD16F58-01B3-463B-A215-FD09FC729A02' . PHP_EOL
73
-		. 'DTEND;TZID=Europe/Berlin:20160816T100000' . PHP_EOL
74
-		. 'TRANSP:OPAQUE' . PHP_EOL
75
-		. 'SUMMARY:Test Europe Berlin' . PHP_EOL
76
-		. 'DTSTART;TZID=Europe/Berlin:20160816T090000' . PHP_EOL
77
-		. 'DTSTAMP:20160809T163632Z' . PHP_EOL
78
-		. 'SEQUENCE:0' . PHP_EOL
79
-		. 'END:VEVENT' . PHP_EOL
80
-		. 'END:VCALENDAR';
81
-
82
-	// TIMED DIFFERENT DAY
83
-	private static string $vEvent2 = 'BEGIN:VCALENDAR' . PHP_EOL
84
-		. 'VERSION:2.0' . PHP_EOL
85
-		. 'PRODID:-//Tests//' . PHP_EOL
86
-		. 'CALSCALE:GREGORIAN' . PHP_EOL
87
-		. 'BEGIN:VTIMEZONE' . PHP_EOL
88
-		. 'TZID:Europe/Berlin' . PHP_EOL
89
-		. 'BEGIN:DAYLIGHT' . PHP_EOL
90
-		. 'TZOFFSETFROM:+0100' . PHP_EOL
91
-		. 'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU' . PHP_EOL
92
-		. 'DTSTART:19810329T020000' . PHP_EOL
93
-		. 'TZNAME:GMT+2' . PHP_EOL
94
-		. 'TZOFFSETTO:+0200' . PHP_EOL
95
-		. 'END:DAYLIGHT' . PHP_EOL
96
-		. 'BEGIN:STANDARD' . PHP_EOL
97
-		. 'TZOFFSETFROM:+0200' . PHP_EOL
98
-		. 'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU' . PHP_EOL
99
-		. 'DTSTART:19961027T030000' . PHP_EOL
100
-		. 'TZNAME:GMT+1' . PHP_EOL
101
-		. 'TZOFFSETTO:+0100' . PHP_EOL
102
-		. 'END:STANDARD' . PHP_EOL
103
-		. 'END:VTIMEZONE' . PHP_EOL
104
-		. 'BEGIN:VEVENT' . PHP_EOL
105
-		. 'CREATED:20160809T163629Z' . PHP_EOL
106
-		. 'UID:0AD16F58-01B3-463B-A215-FD09FC729A02' . PHP_EOL
107
-		. 'DTEND;TZID=Europe/Berlin:20160817T100000' . PHP_EOL
108
-		. 'TRANSP:OPAQUE' . PHP_EOL
109
-		. 'SUMMARY:Test Europe Berlin' . PHP_EOL
110
-		. 'DTSTART;TZID=Europe/Berlin:20160816T090000' . PHP_EOL
111
-		. 'DTSTAMP:20160809T163632Z' . PHP_EOL
112
-		. 'SEQUENCE:0' . PHP_EOL
113
-		. 'END:VEVENT' . PHP_EOL
114
-		. 'END:VCALENDAR';
115
-
116
-	// ALL-DAY ONE-DAY
117
-	private static string $vEvent3 = 'BEGIN:VCALENDAR' . PHP_EOL
118
-		. 'VERSION:2.0' . PHP_EOL
119
-		. 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN' . PHP_EOL
120
-		. 'CALSCALE:GREGORIAN' . PHP_EOL
121
-		. 'BEGIN:VEVENT' . PHP_EOL
122
-		. 'CREATED:20161004T144433Z' . PHP_EOL
123
-		. 'UID:85560E76-1B0D-47E1-A735-21625767FCA4' . PHP_EOL
124
-		. 'DTEND;VALUE=DATE:20161006' . PHP_EOL
125
-		. 'TRANSP:TRANSPARENT' . PHP_EOL
126
-		. 'DTSTART;VALUE=DATE:20161005' . PHP_EOL
127
-		. 'DTSTAMP:20161004T144437Z' . PHP_EOL
128
-		. 'SEQUENCE:0' . PHP_EOL
129
-		. 'END:VEVENT' . PHP_EOL
130
-		. 'END:VCALENDAR';
131
-
132
-	// ALL-DAY MULTIPLE DAYS
133
-	private static string $vEvent4 = 'BEGIN:VCALENDAR' . PHP_EOL
134
-		. 'VERSION:2.0' . PHP_EOL
135
-		. 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN' . PHP_EOL
136
-		. 'CALSCALE:GREGORIAN' . PHP_EOL
137
-		. 'BEGIN:VEVENT' . PHP_EOL
138
-		. 'CREATED:20161004T144433Z' . PHP_EOL
139
-		. 'UID:85560E76-1B0D-47E1-A735-21625767FCA4' . PHP_EOL
140
-		. 'DTEND;VALUE=DATE:20161008' . PHP_EOL
141
-		. 'TRANSP:TRANSPARENT' . PHP_EOL
142
-		. 'DTSTART;VALUE=DATE:20161005' . PHP_EOL
143
-		. 'DTSTAMP:20161004T144437Z' . PHP_EOL
144
-		. 'SEQUENCE:0' . PHP_EOL
145
-		. 'END:VEVENT' . PHP_EOL
146
-		. 'END:VCALENDAR';
147
-
148
-	// DURATION
149
-	private static string $vEvent5 = 'BEGIN:VCALENDAR' . PHP_EOL
150
-		. 'VERSION:2.0' . PHP_EOL
151
-		. 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN' . PHP_EOL
152
-		. 'CALSCALE:GREGORIAN' . PHP_EOL
153
-		. 'BEGIN:VEVENT' . PHP_EOL
154
-		. 'CREATED:20161004T144433Z' . PHP_EOL
155
-		. 'UID:85560E76-1B0D-47E1-A735-21625767FCA4' . PHP_EOL
156
-		. 'DURATION:P5D' . PHP_EOL
157
-		. 'TRANSP:TRANSPARENT' . PHP_EOL
158
-		. 'DTSTART;VALUE=DATE:20161005' . PHP_EOL
159
-		. 'DTSTAMP:20161004T144437Z' . PHP_EOL
160
-		. 'SEQUENCE:0' . PHP_EOL
161
-		. 'END:VEVENT' . PHP_EOL
162
-		. 'END:VCALENDAR';
163
-
164
-	// NO DTEND - DATE
165
-	private static string $vEvent6 = 'BEGIN:VCALENDAR' . PHP_EOL
166
-		. 'VERSION:2.0' . PHP_EOL
167
-		. 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN' . PHP_EOL
168
-		. 'CALSCALE:GREGORIAN' . PHP_EOL
169
-		. 'BEGIN:VEVENT' . PHP_EOL
170
-		. 'CREATED:20161004T144433Z' . PHP_EOL
171
-		. 'UID:85560E76-1B0D-47E1-A735-21625767FCA4' . PHP_EOL
172
-		. 'TRANSP:TRANSPARENT' . PHP_EOL
173
-		. 'DTSTART;VALUE=DATE:20161005' . PHP_EOL
174
-		. 'DTSTAMP:20161004T144437Z' . PHP_EOL
175
-		. 'SEQUENCE:0' . PHP_EOL
176
-		. 'END:VEVENT' . PHP_EOL
177
-		. 'END:VCALENDAR';
178
-
179
-	// NO DTEND - DATE-TIME
180
-	private static string $vEvent7 = 'BEGIN:VCALENDAR' . PHP_EOL
181
-		. 'VERSION:2.0' . PHP_EOL
182
-		. 'PRODID:-//Tests//' . PHP_EOL
183
-		. 'CALSCALE:GREGORIAN' . PHP_EOL
184
-		. 'BEGIN:VTIMEZONE' . PHP_EOL
185
-		. 'TZID:Europe/Berlin' . PHP_EOL
186
-		. 'BEGIN:DAYLIGHT' . PHP_EOL
187
-		. 'TZOFFSETFROM:+0100' . PHP_EOL
188
-		. 'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU' . PHP_EOL
189
-		. 'DTSTART:19810329T020000' . PHP_EOL
190
-		. 'TZNAME:GMT+2' . PHP_EOL
191
-		. 'TZOFFSETTO:+0200' . PHP_EOL
192
-		. 'END:DAYLIGHT' . PHP_EOL
193
-		. 'BEGIN:STANDARD' . PHP_EOL
194
-		. 'TZOFFSETFROM:+0200' . PHP_EOL
195
-		. 'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU' . PHP_EOL
196
-		. 'DTSTART:19961027T030000' . PHP_EOL
197
-		. 'TZNAME:GMT+1' . PHP_EOL
198
-		. 'TZOFFSETTO:+0100' . PHP_EOL
199
-		. 'END:STANDARD' . PHP_EOL
200
-		. 'END:VTIMEZONE' . PHP_EOL
201
-		. 'BEGIN:VEVENT' . PHP_EOL
202
-		. 'CREATED:20160809T163629Z' . PHP_EOL
203
-		. 'UID:0AD16F58-01B3-463B-A215-FD09FC729A02' . PHP_EOL
204
-		. 'TRANSP:OPAQUE' . PHP_EOL
205
-		. 'SUMMARY:Test Europe Berlin' . PHP_EOL
206
-		. 'DTSTART;TZID=Europe/Berlin:20160816T090000' . PHP_EOL
207
-		. 'DTSTAMP:20160809T163632Z' . PHP_EOL
208
-		. 'SEQUENCE:0' . PHP_EOL
209
-		. 'END:VEVENT' . PHP_EOL
210
-		. 'END:VCALENDAR';
211
-
212
-	protected function setUp(): void {
213
-		parent::setUp();
214
-
215
-		$this->appManager = $this->createMock(IAppManager::class);
216
-		$this->l10n = $this->createMock(IL10N::class);
217
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
218
-		$this->backend = $this->createMock(CalDavBackend::class);
219
-
220
-		$this->provider = new EventsSearchProvider(
221
-			$this->appManager,
222
-			$this->l10n,
223
-			$this->urlGenerator,
224
-			$this->backend
225
-		);
226
-	}
227
-
228
-	public function testGetId(): void {
229
-		$this->assertEquals('calendar', $this->provider->getId());
230
-	}
231
-
232
-	public function testGetName(): void {
233
-		$this->l10n->expects($this->exactly(1))
234
-			->method('t')
235
-			->with('Events')
236
-			->willReturnArgument(0);
237
-
238
-		$this->assertEquals('Events', $this->provider->getName());
239
-	}
240
-
241
-	public function testSearchAppDisabled(): void {
242
-		$user = $this->createMock(IUser::class);
243
-		$query = $this->createMock(ISearchQuery::class);
244
-		$this->appManager->expects($this->once())
245
-			->method('isEnabledForUser')
246
-			->with('calendar', $user)
247
-			->willReturn(false);
248
-		$this->l10n->expects($this->exactly(1))
249
-			->method('t')
250
-			->willReturnArgument(0);
251
-		$this->backend->expects($this->never())
252
-			->method('getCalendarsForUser');
253
-		$this->backend->expects($this->never())
254
-			->method('getSubscriptionsForUser');
255
-		$this->backend->expects($this->never())
256
-			->method('searchPrincipalUri');
257
-
258
-		$actual = $this->provider->search($user, $query);
259
-		$data = $actual->jsonSerialize();
260
-		$this->assertInstanceOf(SearchResult::class, $actual);
261
-		$this->assertEquals('Events', $data['name']);
262
-		$this->assertEmpty($data['entries']);
263
-		$this->assertFalse($data['isPaginated']);
264
-		$this->assertNull($data['cursor']);
265
-	}
266
-
267
-	public function testSearch(): void {
268
-		$user = $this->createMock(IUser::class);
269
-		$user->method('getUID')->willReturn('john.doe');
270
-		$query = $this->createMock(ISearchQuery::class);
271
-		$seachTermFilter = $this->createMock(IFilter::class);
272
-		$query->method('getFilter')->willReturnCallback(function ($name) use ($seachTermFilter) {
273
-			return match ($name) {
274
-				'term' => $seachTermFilter,
275
-				default => null,
276
-			};
277
-		});
278
-		$seachTermFilter->method('get')->willReturn('search term');
279
-		$query->method('getLimit')->willReturn(5);
280
-		$query->method('getCursor')->willReturn(20);
281
-		$this->appManager->expects($this->once())
282
-			->method('isEnabledForUser')
283
-			->with('calendar', $user)
284
-			->willReturn(true);
285
-		$this->l10n->method('t')->willReturnArgument(0);
286
-
287
-		$this->backend->expects($this->once())
288
-			->method('getCalendarsForUser')
289
-			->with('principals/users/john.doe')
290
-			->willReturn([
291
-				[
292
-					'id' => 99,
293
-					'principaluri' => 'principals/users/john.doe',
294
-					'uri' => 'calendar-uri-99',
295
-				], [
296
-					'id' => 123,
297
-					'principaluri' => 'principals/users/john.doe',
298
-					'uri' => 'calendar-uri-123',
299
-				]
300
-			]);
301
-		$this->backend->expects($this->once())
302
-			->method('getSubscriptionsForUser')
303
-			->with('principals/users/john.doe')
304
-			->willReturn([
305
-				[
306
-					'id' => 1337,
307
-					'principaluri' => 'principals/users/john.doe',
308
-					'uri' => 'subscription-uri-1337',
309
-				]
310
-			]);
311
-		$this->backend->expects($this->once())
312
-			->method('searchPrincipalUri')
313
-			->with('principals/users/john.doe', 'search term', ['VEVENT'],
314
-				['SUMMARY', 'LOCATION', 'DESCRIPTION', 'ATTENDEE', 'ORGANIZER', 'CATEGORIES'],
315
-				['ATTENDEE' => ['CN'], 'ORGANIZER' => ['CN']],
316
-				['limit' => 5, 'offset' => 20, 'timerange' => ['start' => null, 'end' => null]])
317
-			->willReturn([
318
-				[
319
-					'calendarid' => 99,
320
-					'calendartype' => CalDavBackend::CALENDAR_TYPE_CALENDAR,
321
-					'uri' => 'event0.ics',
322
-					'calendardata' => self::$vEvent0,
323
-				],
324
-				[
325
-					'calendarid' => 123,
326
-					'calendartype' => CalDavBackend::CALENDAR_TYPE_CALENDAR,
327
-					'uri' => 'event1.ics',
328
-					'calendardata' => self::$vEvent1,
329
-				],
330
-				[
331
-					'calendarid' => 1337,
332
-					'calendartype' => CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION,
333
-					'uri' => 'event2.ics',
334
-					'calendardata' => self::$vEvent2,
335
-				]
336
-			]);
337
-
338
-		$provider = $this->getMockBuilder(EventsSearchProvider::class)
339
-			->setConstructorArgs([
340
-				$this->appManager,
341
-				$this->l10n,
342
-				$this->urlGenerator,
343
-				$this->backend,
344
-			])
345
-			->onlyMethods([
346
-				'getDeepLinkToCalendarApp',
347
-				'generateSubline',
348
-			])
349
-			->getMock();
350
-
351
-		$provider->expects($this->exactly(3))
352
-			->method('generateSubline')
353
-			->willReturn('subline');
354
-		$provider->expects($this->exactly(3))
355
-			->method('getDeepLinkToCalendarApp')
356
-			->willReturnMap([
357
-				['principals/users/john.doe', 'calendar-uri-99', 'event0.ics', 'deep-link-to-calendar'],
358
-				['principals/users/john.doe', 'calendar-uri-123', 'event1.ics', 'deep-link-to-calendar'],
359
-				['principals/users/john.doe', 'subscription-uri-1337', 'event2.ics', 'deep-link-to-calendar']
360
-			]);
361
-
362
-		$actual = $provider->search($user, $query);
363
-		$data = $actual->jsonSerialize();
364
-		$this->assertInstanceOf(SearchResult::class, $actual);
365
-		$this->assertEquals('Events', $data['name']);
366
-		$this->assertCount(3, $data['entries']);
367
-		$this->assertTrue($data['isPaginated']);
368
-		$this->assertEquals(23, $data['cursor']);
369
-
370
-		$result0 = $data['entries'][0];
371
-		$result0Data = $result0->jsonSerialize();
372
-		$result1 = $data['entries'][1];
373
-		$result1Data = $result1->jsonSerialize();
374
-		$result2 = $data['entries'][2];
375
-		$result2Data = $result2->jsonSerialize();
376
-
377
-		$this->assertInstanceOf(SearchResultEntry::class, $result0);
378
-		$this->assertEmpty($result0Data['thumbnailUrl']);
379
-		$this->assertEquals('Untitled event', $result0Data['title']);
380
-		$this->assertEquals('subline', $result0Data['subline']);
381
-		$this->assertEquals('deep-link-to-calendar', $result0Data['resourceUrl']);
382
-		$this->assertEquals('icon-calendar-dark', $result0Data['icon']);
383
-		$this->assertFalse($result0Data['rounded']);
384
-
385
-		$this->assertInstanceOf(SearchResultEntry::class, $result1);
386
-		$this->assertEmpty($result1Data['thumbnailUrl']);
387
-		$this->assertEquals('Test Europe Berlin', $result1Data['title']);
388
-		$this->assertEquals('subline', $result1Data['subline']);
389
-		$this->assertEquals('deep-link-to-calendar', $result1Data['resourceUrl']);
390
-		$this->assertEquals('icon-calendar-dark', $result1Data['icon']);
391
-		$this->assertFalse($result1Data['rounded']);
392
-
393
-		$this->assertInstanceOf(SearchResultEntry::class, $result2);
394
-		$this->assertEmpty($result2Data['thumbnailUrl']);
395
-		$this->assertEquals('Test Europe Berlin', $result2Data['title']);
396
-		$this->assertEquals('subline', $result2Data['subline']);
397
-		$this->assertEquals('deep-link-to-calendar', $result2Data['resourceUrl']);
398
-		$this->assertEquals('icon-calendar-dark', $result2Data['icon']);
399
-		$this->assertFalse($result2Data['rounded']);
400
-	}
401
-
402
-	public function testGetDeepLinkToCalendarApp(): void {
403
-		$this->urlGenerator->expects($this->once())
404
-			->method('linkTo')
405
-			->with('', 'remote.php')
406
-			->willReturn('link-to-remote.php');
407
-		$this->urlGenerator->expects($this->once())
408
-			->method('linkToRoute')
409
-			->with('calendar.view.index')
410
-			->willReturn('link-to-route-calendar/');
411
-		$this->urlGenerator->expects($this->once())
412
-			->method('getAbsoluteURL')
413
-			->with('link-to-route-calendar/edit/bGluay10by1yZW1vdGUucGhwL2Rhdi9jYWxlbmRhcnMvam9obi5kb2UvZm9vL2Jhci5pY3M=')
414
-			->willReturn('absolute-url-to-route');
415
-
416
-		$actual = self::invokePrivate($this->provider, 'getDeepLinkToCalendarApp', ['principals/users/john.doe', 'foo', 'bar.ics']);
417
-
418
-		$this->assertEquals('absolute-url-to-route', $actual);
419
-	}
420
-
421
-	#[\PHPUnit\Framework\Attributes\DataProvider('generateSublineDataProvider')]
422
-	public function testGenerateSubline(string $ics, string $expectedSubline): void {
423
-		$vCalendar = Reader::read($ics, Reader::OPTION_FORGIVING);
424
-		$eventComponent = $vCalendar->VEVENT;
425
-
426
-		$this->l10n->method('l')
427
-			->willReturnCallback(static function (string $type, \DateTime $date, $_):string {
428
-				if ($type === 'time') {
429
-					return $date->format('H:i');
430
-				}
431
-
432
-				return $date->format('m-d');
433
-			});
434
-
435
-		$actual = self::invokePrivate($this->provider, 'generateSubline', [$eventComponent]);
436
-		$this->assertEquals($expectedSubline, $actual);
437
-	}
438
-
439
-	public static function generateSublineDataProvider(): array {
440
-		return [
441
-			[self::$vEvent1, '08-16 09:00 - 10:00'],
442
-			[self::$vEvent2, '08-16 09:00 - 08-17 10:00'],
443
-			[self::$vEvent3, '10-05'],
444
-			[self::$vEvent4, '10-05 - 10-07'],
445
-			[self::$vEvent5, '10-05 - 10-09'],
446
-			[self::$vEvent6, '10-05'],
447
-			[self::$vEvent7, '08-16 09:00 - 09:00'],
448
-		];
449
-	}
26
+    private IAppManager&MockObject $appManager;
27
+    private IL10N&MockObject $l10n;
28
+    private IURLGenerator&MockObject $urlGenerator;
29
+    private CalDavBackend&MockObject $backend;
30
+    private EventsSearchProvider $provider;
31
+
32
+    // NO SUMMARY
33
+    private static string $vEvent0 = 'BEGIN:VCALENDAR' . PHP_EOL
34
+        . 'VERSION:2.0' . PHP_EOL
35
+        . 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN' . PHP_EOL
36
+        . 'CALSCALE:GREGORIAN' . PHP_EOL
37
+        . 'BEGIN:VEVENT' . PHP_EOL
38
+        . 'CREATED:20161004T144433Z' . PHP_EOL
39
+        . 'UID:85560E76-1B0D-47E1-A735-21625767FCA4' . PHP_EOL
40
+        . 'DTEND;VALUE=DATE:20161008' . PHP_EOL
41
+        . 'TRANSP:TRANSPARENT' . PHP_EOL
42
+        . 'DTSTART;VALUE=DATE:20161005' . PHP_EOL
43
+        . 'DTSTAMP:20161004T144437Z' . PHP_EOL
44
+        . 'SEQUENCE:0' . PHP_EOL
45
+        . 'END:VEVENT' . PHP_EOL
46
+        . 'END:VCALENDAR';
47
+
48
+    // TIMED SAME DAY
49
+    private static string $vEvent1 = 'BEGIN:VCALENDAR' . PHP_EOL
50
+        . 'VERSION:2.0' . PHP_EOL
51
+        . 'PRODID:-//Tests//' . PHP_EOL
52
+        . 'CALSCALE:GREGORIAN' . PHP_EOL
53
+        . 'BEGIN:VTIMEZONE' . PHP_EOL
54
+        . 'TZID:Europe/Berlin' . PHP_EOL
55
+        . 'BEGIN:DAYLIGHT' . PHP_EOL
56
+        . 'TZOFFSETFROM:+0100' . PHP_EOL
57
+        . 'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU' . PHP_EOL
58
+        . 'DTSTART:19810329T020000' . PHP_EOL
59
+        . 'TZNAME:GMT+2' . PHP_EOL
60
+        . 'TZOFFSETTO:+0200' . PHP_EOL
61
+        . 'END:DAYLIGHT' . PHP_EOL
62
+        . 'BEGIN:STANDARD' . PHP_EOL
63
+        . 'TZOFFSETFROM:+0200' . PHP_EOL
64
+        . 'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU' . PHP_EOL
65
+        . 'DTSTART:19961027T030000' . PHP_EOL
66
+        . 'TZNAME:GMT+1' . PHP_EOL
67
+        . 'TZOFFSETTO:+0100' . PHP_EOL
68
+        . 'END:STANDARD' . PHP_EOL
69
+        . 'END:VTIMEZONE' . PHP_EOL
70
+        . 'BEGIN:VEVENT' . PHP_EOL
71
+        . 'CREATED:20160809T163629Z' . PHP_EOL
72
+        . 'UID:0AD16F58-01B3-463B-A215-FD09FC729A02' . PHP_EOL
73
+        . 'DTEND;TZID=Europe/Berlin:20160816T100000' . PHP_EOL
74
+        . 'TRANSP:OPAQUE' . PHP_EOL
75
+        . 'SUMMARY:Test Europe Berlin' . PHP_EOL
76
+        . 'DTSTART;TZID=Europe/Berlin:20160816T090000' . PHP_EOL
77
+        . 'DTSTAMP:20160809T163632Z' . PHP_EOL
78
+        . 'SEQUENCE:0' . PHP_EOL
79
+        . 'END:VEVENT' . PHP_EOL
80
+        . 'END:VCALENDAR';
81
+
82
+    // TIMED DIFFERENT DAY
83
+    private static string $vEvent2 = 'BEGIN:VCALENDAR' . PHP_EOL
84
+        . 'VERSION:2.0' . PHP_EOL
85
+        . 'PRODID:-//Tests//' . PHP_EOL
86
+        . 'CALSCALE:GREGORIAN' . PHP_EOL
87
+        . 'BEGIN:VTIMEZONE' . PHP_EOL
88
+        . 'TZID:Europe/Berlin' . PHP_EOL
89
+        . 'BEGIN:DAYLIGHT' . PHP_EOL
90
+        . 'TZOFFSETFROM:+0100' . PHP_EOL
91
+        . 'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU' . PHP_EOL
92
+        . 'DTSTART:19810329T020000' . PHP_EOL
93
+        . 'TZNAME:GMT+2' . PHP_EOL
94
+        . 'TZOFFSETTO:+0200' . PHP_EOL
95
+        . 'END:DAYLIGHT' . PHP_EOL
96
+        . 'BEGIN:STANDARD' . PHP_EOL
97
+        . 'TZOFFSETFROM:+0200' . PHP_EOL
98
+        . 'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU' . PHP_EOL
99
+        . 'DTSTART:19961027T030000' . PHP_EOL
100
+        . 'TZNAME:GMT+1' . PHP_EOL
101
+        . 'TZOFFSETTO:+0100' . PHP_EOL
102
+        . 'END:STANDARD' . PHP_EOL
103
+        . 'END:VTIMEZONE' . PHP_EOL
104
+        . 'BEGIN:VEVENT' . PHP_EOL
105
+        . 'CREATED:20160809T163629Z' . PHP_EOL
106
+        . 'UID:0AD16F58-01B3-463B-A215-FD09FC729A02' . PHP_EOL
107
+        . 'DTEND;TZID=Europe/Berlin:20160817T100000' . PHP_EOL
108
+        . 'TRANSP:OPAQUE' . PHP_EOL
109
+        . 'SUMMARY:Test Europe Berlin' . PHP_EOL
110
+        . 'DTSTART;TZID=Europe/Berlin:20160816T090000' . PHP_EOL
111
+        . 'DTSTAMP:20160809T163632Z' . PHP_EOL
112
+        . 'SEQUENCE:0' . PHP_EOL
113
+        . 'END:VEVENT' . PHP_EOL
114
+        . 'END:VCALENDAR';
115
+
116
+    // ALL-DAY ONE-DAY
117
+    private static string $vEvent3 = 'BEGIN:VCALENDAR' . PHP_EOL
118
+        . 'VERSION:2.0' . PHP_EOL
119
+        . 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN' . PHP_EOL
120
+        . 'CALSCALE:GREGORIAN' . PHP_EOL
121
+        . 'BEGIN:VEVENT' . PHP_EOL
122
+        . 'CREATED:20161004T144433Z' . PHP_EOL
123
+        . 'UID:85560E76-1B0D-47E1-A735-21625767FCA4' . PHP_EOL
124
+        . 'DTEND;VALUE=DATE:20161006' . PHP_EOL
125
+        . 'TRANSP:TRANSPARENT' . PHP_EOL
126
+        . 'DTSTART;VALUE=DATE:20161005' . PHP_EOL
127
+        . 'DTSTAMP:20161004T144437Z' . PHP_EOL
128
+        . 'SEQUENCE:0' . PHP_EOL
129
+        . 'END:VEVENT' . PHP_EOL
130
+        . 'END:VCALENDAR';
131
+
132
+    // ALL-DAY MULTIPLE DAYS
133
+    private static string $vEvent4 = 'BEGIN:VCALENDAR' . PHP_EOL
134
+        . 'VERSION:2.0' . PHP_EOL
135
+        . 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN' . PHP_EOL
136
+        . 'CALSCALE:GREGORIAN' . PHP_EOL
137
+        . 'BEGIN:VEVENT' . PHP_EOL
138
+        . 'CREATED:20161004T144433Z' . PHP_EOL
139
+        . 'UID:85560E76-1B0D-47E1-A735-21625767FCA4' . PHP_EOL
140
+        . 'DTEND;VALUE=DATE:20161008' . PHP_EOL
141
+        . 'TRANSP:TRANSPARENT' . PHP_EOL
142
+        . 'DTSTART;VALUE=DATE:20161005' . PHP_EOL
143
+        . 'DTSTAMP:20161004T144437Z' . PHP_EOL
144
+        . 'SEQUENCE:0' . PHP_EOL
145
+        . 'END:VEVENT' . PHP_EOL
146
+        . 'END:VCALENDAR';
147
+
148
+    // DURATION
149
+    private static string $vEvent5 = 'BEGIN:VCALENDAR' . PHP_EOL
150
+        . 'VERSION:2.0' . PHP_EOL
151
+        . 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN' . PHP_EOL
152
+        . 'CALSCALE:GREGORIAN' . PHP_EOL
153
+        . 'BEGIN:VEVENT' . PHP_EOL
154
+        . 'CREATED:20161004T144433Z' . PHP_EOL
155
+        . 'UID:85560E76-1B0D-47E1-A735-21625767FCA4' . PHP_EOL
156
+        . 'DURATION:P5D' . PHP_EOL
157
+        . 'TRANSP:TRANSPARENT' . PHP_EOL
158
+        . 'DTSTART;VALUE=DATE:20161005' . PHP_EOL
159
+        . 'DTSTAMP:20161004T144437Z' . PHP_EOL
160
+        . 'SEQUENCE:0' . PHP_EOL
161
+        . 'END:VEVENT' . PHP_EOL
162
+        . 'END:VCALENDAR';
163
+
164
+    // NO DTEND - DATE
165
+    private static string $vEvent6 = 'BEGIN:VCALENDAR' . PHP_EOL
166
+        . 'VERSION:2.0' . PHP_EOL
167
+        . 'PRODID:-//Apple Inc.//Mac OS X 10.11.6//EN' . PHP_EOL
168
+        . 'CALSCALE:GREGORIAN' . PHP_EOL
169
+        . 'BEGIN:VEVENT' . PHP_EOL
170
+        . 'CREATED:20161004T144433Z' . PHP_EOL
171
+        . 'UID:85560E76-1B0D-47E1-A735-21625767FCA4' . PHP_EOL
172
+        . 'TRANSP:TRANSPARENT' . PHP_EOL
173
+        . 'DTSTART;VALUE=DATE:20161005' . PHP_EOL
174
+        . 'DTSTAMP:20161004T144437Z' . PHP_EOL
175
+        . 'SEQUENCE:0' . PHP_EOL
176
+        . 'END:VEVENT' . PHP_EOL
177
+        . 'END:VCALENDAR';
178
+
179
+    // NO DTEND - DATE-TIME
180
+    private static string $vEvent7 = 'BEGIN:VCALENDAR' . PHP_EOL
181
+        . 'VERSION:2.0' . PHP_EOL
182
+        . 'PRODID:-//Tests//' . PHP_EOL
183
+        . 'CALSCALE:GREGORIAN' . PHP_EOL
184
+        . 'BEGIN:VTIMEZONE' . PHP_EOL
185
+        . 'TZID:Europe/Berlin' . PHP_EOL
186
+        . 'BEGIN:DAYLIGHT' . PHP_EOL
187
+        . 'TZOFFSETFROM:+0100' . PHP_EOL
188
+        . 'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU' . PHP_EOL
189
+        . 'DTSTART:19810329T020000' . PHP_EOL
190
+        . 'TZNAME:GMT+2' . PHP_EOL
191
+        . 'TZOFFSETTO:+0200' . PHP_EOL
192
+        . 'END:DAYLIGHT' . PHP_EOL
193
+        . 'BEGIN:STANDARD' . PHP_EOL
194
+        . 'TZOFFSETFROM:+0200' . PHP_EOL
195
+        . 'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU' . PHP_EOL
196
+        . 'DTSTART:19961027T030000' . PHP_EOL
197
+        . 'TZNAME:GMT+1' . PHP_EOL
198
+        . 'TZOFFSETTO:+0100' . PHP_EOL
199
+        . 'END:STANDARD' . PHP_EOL
200
+        . 'END:VTIMEZONE' . PHP_EOL
201
+        . 'BEGIN:VEVENT' . PHP_EOL
202
+        . 'CREATED:20160809T163629Z' . PHP_EOL
203
+        . 'UID:0AD16F58-01B3-463B-A215-FD09FC729A02' . PHP_EOL
204
+        . 'TRANSP:OPAQUE' . PHP_EOL
205
+        . 'SUMMARY:Test Europe Berlin' . PHP_EOL
206
+        . 'DTSTART;TZID=Europe/Berlin:20160816T090000' . PHP_EOL
207
+        . 'DTSTAMP:20160809T163632Z' . PHP_EOL
208
+        . 'SEQUENCE:0' . PHP_EOL
209
+        . 'END:VEVENT' . PHP_EOL
210
+        . 'END:VCALENDAR';
211
+
212
+    protected function setUp(): void {
213
+        parent::setUp();
214
+
215
+        $this->appManager = $this->createMock(IAppManager::class);
216
+        $this->l10n = $this->createMock(IL10N::class);
217
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
218
+        $this->backend = $this->createMock(CalDavBackend::class);
219
+
220
+        $this->provider = new EventsSearchProvider(
221
+            $this->appManager,
222
+            $this->l10n,
223
+            $this->urlGenerator,
224
+            $this->backend
225
+        );
226
+    }
227
+
228
+    public function testGetId(): void {
229
+        $this->assertEquals('calendar', $this->provider->getId());
230
+    }
231
+
232
+    public function testGetName(): void {
233
+        $this->l10n->expects($this->exactly(1))
234
+            ->method('t')
235
+            ->with('Events')
236
+            ->willReturnArgument(0);
237
+
238
+        $this->assertEquals('Events', $this->provider->getName());
239
+    }
240
+
241
+    public function testSearchAppDisabled(): void {
242
+        $user = $this->createMock(IUser::class);
243
+        $query = $this->createMock(ISearchQuery::class);
244
+        $this->appManager->expects($this->once())
245
+            ->method('isEnabledForUser')
246
+            ->with('calendar', $user)
247
+            ->willReturn(false);
248
+        $this->l10n->expects($this->exactly(1))
249
+            ->method('t')
250
+            ->willReturnArgument(0);
251
+        $this->backend->expects($this->never())
252
+            ->method('getCalendarsForUser');
253
+        $this->backend->expects($this->never())
254
+            ->method('getSubscriptionsForUser');
255
+        $this->backend->expects($this->never())
256
+            ->method('searchPrincipalUri');
257
+
258
+        $actual = $this->provider->search($user, $query);
259
+        $data = $actual->jsonSerialize();
260
+        $this->assertInstanceOf(SearchResult::class, $actual);
261
+        $this->assertEquals('Events', $data['name']);
262
+        $this->assertEmpty($data['entries']);
263
+        $this->assertFalse($data['isPaginated']);
264
+        $this->assertNull($data['cursor']);
265
+    }
266
+
267
+    public function testSearch(): void {
268
+        $user = $this->createMock(IUser::class);
269
+        $user->method('getUID')->willReturn('john.doe');
270
+        $query = $this->createMock(ISearchQuery::class);
271
+        $seachTermFilter = $this->createMock(IFilter::class);
272
+        $query->method('getFilter')->willReturnCallback(function ($name) use ($seachTermFilter) {
273
+            return match ($name) {
274
+                'term' => $seachTermFilter,
275
+                default => null,
276
+            };
277
+        });
278
+        $seachTermFilter->method('get')->willReturn('search term');
279
+        $query->method('getLimit')->willReturn(5);
280
+        $query->method('getCursor')->willReturn(20);
281
+        $this->appManager->expects($this->once())
282
+            ->method('isEnabledForUser')
283
+            ->with('calendar', $user)
284
+            ->willReturn(true);
285
+        $this->l10n->method('t')->willReturnArgument(0);
286
+
287
+        $this->backend->expects($this->once())
288
+            ->method('getCalendarsForUser')
289
+            ->with('principals/users/john.doe')
290
+            ->willReturn([
291
+                [
292
+                    'id' => 99,
293
+                    'principaluri' => 'principals/users/john.doe',
294
+                    'uri' => 'calendar-uri-99',
295
+                ], [
296
+                    'id' => 123,
297
+                    'principaluri' => 'principals/users/john.doe',
298
+                    'uri' => 'calendar-uri-123',
299
+                ]
300
+            ]);
301
+        $this->backend->expects($this->once())
302
+            ->method('getSubscriptionsForUser')
303
+            ->with('principals/users/john.doe')
304
+            ->willReturn([
305
+                [
306
+                    'id' => 1337,
307
+                    'principaluri' => 'principals/users/john.doe',
308
+                    'uri' => 'subscription-uri-1337',
309
+                ]
310
+            ]);
311
+        $this->backend->expects($this->once())
312
+            ->method('searchPrincipalUri')
313
+            ->with('principals/users/john.doe', 'search term', ['VEVENT'],
314
+                ['SUMMARY', 'LOCATION', 'DESCRIPTION', 'ATTENDEE', 'ORGANIZER', 'CATEGORIES'],
315
+                ['ATTENDEE' => ['CN'], 'ORGANIZER' => ['CN']],
316
+                ['limit' => 5, 'offset' => 20, 'timerange' => ['start' => null, 'end' => null]])
317
+            ->willReturn([
318
+                [
319
+                    'calendarid' => 99,
320
+                    'calendartype' => CalDavBackend::CALENDAR_TYPE_CALENDAR,
321
+                    'uri' => 'event0.ics',
322
+                    'calendardata' => self::$vEvent0,
323
+                ],
324
+                [
325
+                    'calendarid' => 123,
326
+                    'calendartype' => CalDavBackend::CALENDAR_TYPE_CALENDAR,
327
+                    'uri' => 'event1.ics',
328
+                    'calendardata' => self::$vEvent1,
329
+                ],
330
+                [
331
+                    'calendarid' => 1337,
332
+                    'calendartype' => CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION,
333
+                    'uri' => 'event2.ics',
334
+                    'calendardata' => self::$vEvent2,
335
+                ]
336
+            ]);
337
+
338
+        $provider = $this->getMockBuilder(EventsSearchProvider::class)
339
+            ->setConstructorArgs([
340
+                $this->appManager,
341
+                $this->l10n,
342
+                $this->urlGenerator,
343
+                $this->backend,
344
+            ])
345
+            ->onlyMethods([
346
+                'getDeepLinkToCalendarApp',
347
+                'generateSubline',
348
+            ])
349
+            ->getMock();
350
+
351
+        $provider->expects($this->exactly(3))
352
+            ->method('generateSubline')
353
+            ->willReturn('subline');
354
+        $provider->expects($this->exactly(3))
355
+            ->method('getDeepLinkToCalendarApp')
356
+            ->willReturnMap([
357
+                ['principals/users/john.doe', 'calendar-uri-99', 'event0.ics', 'deep-link-to-calendar'],
358
+                ['principals/users/john.doe', 'calendar-uri-123', 'event1.ics', 'deep-link-to-calendar'],
359
+                ['principals/users/john.doe', 'subscription-uri-1337', 'event2.ics', 'deep-link-to-calendar']
360
+            ]);
361
+
362
+        $actual = $provider->search($user, $query);
363
+        $data = $actual->jsonSerialize();
364
+        $this->assertInstanceOf(SearchResult::class, $actual);
365
+        $this->assertEquals('Events', $data['name']);
366
+        $this->assertCount(3, $data['entries']);
367
+        $this->assertTrue($data['isPaginated']);
368
+        $this->assertEquals(23, $data['cursor']);
369
+
370
+        $result0 = $data['entries'][0];
371
+        $result0Data = $result0->jsonSerialize();
372
+        $result1 = $data['entries'][1];
373
+        $result1Data = $result1->jsonSerialize();
374
+        $result2 = $data['entries'][2];
375
+        $result2Data = $result2->jsonSerialize();
376
+
377
+        $this->assertInstanceOf(SearchResultEntry::class, $result0);
378
+        $this->assertEmpty($result0Data['thumbnailUrl']);
379
+        $this->assertEquals('Untitled event', $result0Data['title']);
380
+        $this->assertEquals('subline', $result0Data['subline']);
381
+        $this->assertEquals('deep-link-to-calendar', $result0Data['resourceUrl']);
382
+        $this->assertEquals('icon-calendar-dark', $result0Data['icon']);
383
+        $this->assertFalse($result0Data['rounded']);
384
+
385
+        $this->assertInstanceOf(SearchResultEntry::class, $result1);
386
+        $this->assertEmpty($result1Data['thumbnailUrl']);
387
+        $this->assertEquals('Test Europe Berlin', $result1Data['title']);
388
+        $this->assertEquals('subline', $result1Data['subline']);
389
+        $this->assertEquals('deep-link-to-calendar', $result1Data['resourceUrl']);
390
+        $this->assertEquals('icon-calendar-dark', $result1Data['icon']);
391
+        $this->assertFalse($result1Data['rounded']);
392
+
393
+        $this->assertInstanceOf(SearchResultEntry::class, $result2);
394
+        $this->assertEmpty($result2Data['thumbnailUrl']);
395
+        $this->assertEquals('Test Europe Berlin', $result2Data['title']);
396
+        $this->assertEquals('subline', $result2Data['subline']);
397
+        $this->assertEquals('deep-link-to-calendar', $result2Data['resourceUrl']);
398
+        $this->assertEquals('icon-calendar-dark', $result2Data['icon']);
399
+        $this->assertFalse($result2Data['rounded']);
400
+    }
401
+
402
+    public function testGetDeepLinkToCalendarApp(): void {
403
+        $this->urlGenerator->expects($this->once())
404
+            ->method('linkTo')
405
+            ->with('', 'remote.php')
406
+            ->willReturn('link-to-remote.php');
407
+        $this->urlGenerator->expects($this->once())
408
+            ->method('linkToRoute')
409
+            ->with('calendar.view.index')
410
+            ->willReturn('link-to-route-calendar/');
411
+        $this->urlGenerator->expects($this->once())
412
+            ->method('getAbsoluteURL')
413
+            ->with('link-to-route-calendar/edit/bGluay10by1yZW1vdGUucGhwL2Rhdi9jYWxlbmRhcnMvam9obi5kb2UvZm9vL2Jhci5pY3M=')
414
+            ->willReturn('absolute-url-to-route');
415
+
416
+        $actual = self::invokePrivate($this->provider, 'getDeepLinkToCalendarApp', ['principals/users/john.doe', 'foo', 'bar.ics']);
417
+
418
+        $this->assertEquals('absolute-url-to-route', $actual);
419
+    }
420
+
421
+    #[\PHPUnit\Framework\Attributes\DataProvider('generateSublineDataProvider')]
422
+    public function testGenerateSubline(string $ics, string $expectedSubline): void {
423
+        $vCalendar = Reader::read($ics, Reader::OPTION_FORGIVING);
424
+        $eventComponent = $vCalendar->VEVENT;
425
+
426
+        $this->l10n->method('l')
427
+            ->willReturnCallback(static function (string $type, \DateTime $date, $_):string {
428
+                if ($type === 'time') {
429
+                    return $date->format('H:i');
430
+                }
431
+
432
+                return $date->format('m-d');
433
+            });
434
+
435
+        $actual = self::invokePrivate($this->provider, 'generateSubline', [$eventComponent]);
436
+        $this->assertEquals($expectedSubline, $actual);
437
+    }
438
+
439
+    public static function generateSublineDataProvider(): array {
440
+        return [
441
+            [self::$vEvent1, '08-16 09:00 - 10:00'],
442
+            [self::$vEvent2, '08-16 09:00 - 08-17 10:00'],
443
+            [self::$vEvent3, '10-05'],
444
+            [self::$vEvent4, '10-05 - 10-07'],
445
+            [self::$vEvent5, '10-05 - 10-09'],
446
+            [self::$vEvent6, '10-05'],
447
+            [self::$vEvent7, '08-16 09:00 - 09:00'],
448
+        ];
449
+    }
450 450
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Search/TasksSearchProviderTest.php 1 patch
Indentation   +288 added lines, -288 removed lines patch added patch discarded remove patch
@@ -22,292 +22,292 @@
 block discarded – undo
22 22
 use Test\TestCase;
23 23
 
24 24
 class TasksSearchProviderTest extends TestCase {
25
-	private IAppManager&MockObject $appManager;
26
-	private IL10N&MockObject $l10n;
27
-	private IURLGenerator&MockObject $urlGenerator;
28
-	private CalDavBackend&MockObject $backend;
29
-	private TasksSearchProvider $provider;
30
-
31
-	// NO DUE NOR COMPLETED NOR SUMMARY
32
-	private static string $vTodo0 = 'BEGIN:VCALENDAR' . PHP_EOL
33
-		. 'PRODID:TEST' . PHP_EOL
34
-		. 'VERSION:2.0' . PHP_EOL
35
-		. 'BEGIN:VTODO' . PHP_EOL
36
-		. 'UID:[email protected]' . PHP_EOL
37
-		. 'DTSTAMP:20070313T123432Z' . PHP_EOL
38
-		. 'STATUS:NEEDS-ACTION' . PHP_EOL
39
-		. 'END:VTODO' . PHP_EOL
40
-		. 'END:VCALENDAR';
41
-
42
-	// DUE AND COMPLETED
43
-	private static string $vTodo1 = 'BEGIN:VCALENDAR' . PHP_EOL
44
-		. 'PRODID:TEST' . PHP_EOL
45
-		. 'VERSION:2.0' . PHP_EOL
46
-		. 'BEGIN:VTODO' . PHP_EOL
47
-		. 'UID:[email protected]' . PHP_EOL
48
-		. 'DTSTAMP:20070313T123432Z' . PHP_EOL
49
-		. 'COMPLETED:20070707T100000Z' . PHP_EOL
50
-		. 'DUE;VALUE=DATE:20070501' . PHP_EOL
51
-		. 'SUMMARY:Task title' . PHP_EOL
52
-		. 'STATUS:NEEDS-ACTION' . PHP_EOL
53
-		. 'END:VTODO' . PHP_EOL
54
-		. 'END:VCALENDAR';
55
-
56
-	// COMPLETED ONLY
57
-	private static string $vTodo2 = 'BEGIN:VCALENDAR' . PHP_EOL
58
-		. 'PRODID:TEST' . PHP_EOL
59
-		. 'VERSION:2.0' . PHP_EOL
60
-		. 'BEGIN:VTODO' . PHP_EOL
61
-		. 'UID:[email protected]' . PHP_EOL
62
-		. 'DTSTAMP:20070313T123432Z' . PHP_EOL
63
-		. 'COMPLETED:20070707T100000Z' . PHP_EOL
64
-		. 'SUMMARY:Task title' . PHP_EOL
65
-		. 'STATUS:NEEDS-ACTION' . PHP_EOL
66
-		. 'END:VTODO' . PHP_EOL
67
-		. 'END:VCALENDAR';
68
-
69
-	// DUE DATE
70
-	private static string $vTodo3 = 'BEGIN:VCALENDAR' . PHP_EOL
71
-		. 'PRODID:TEST' . PHP_EOL
72
-		. 'VERSION:2.0' . PHP_EOL
73
-		. 'BEGIN:VTODO' . PHP_EOL
74
-		. 'UID:[email protected]' . PHP_EOL
75
-		. 'DTSTAMP:20070313T123432Z' . PHP_EOL
76
-		. 'DUE;VALUE=DATE:20070501' . PHP_EOL
77
-		. 'SUMMARY:Task title' . PHP_EOL
78
-		. 'STATUS:NEEDS-ACTION' . PHP_EOL
79
-		. 'END:VTODO' . PHP_EOL
80
-		. 'END:VCALENDAR';
81
-
82
-	// DUE DATETIME
83
-	private static string $vTodo4 = 'BEGIN:VCALENDAR' . PHP_EOL
84
-		. 'PRODID:TEST' . PHP_EOL
85
-		. 'VERSION:2.0' . PHP_EOL
86
-		. 'BEGIN:VTODO' . PHP_EOL
87
-		. 'UID:[email protected]' . PHP_EOL
88
-		. 'DTSTAMP:20070313T123432Z' . PHP_EOL
89
-		. 'DUE:20070709T130000Z' . PHP_EOL
90
-		. 'SUMMARY:Task title' . PHP_EOL
91
-		. 'STATUS:NEEDS-ACTION' . PHP_EOL
92
-		. 'END:VTODO' . PHP_EOL
93
-		. 'END:VCALENDAR';
94
-
95
-	protected function setUp(): void {
96
-		parent::setUp();
97
-
98
-		$this->appManager = $this->createMock(IAppManager::class);
99
-		$this->l10n = $this->createMock(IL10N::class);
100
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
101
-		$this->backend = $this->createMock(CalDavBackend::class);
102
-
103
-		$this->provider = new TasksSearchProvider(
104
-			$this->appManager,
105
-			$this->l10n,
106
-			$this->urlGenerator,
107
-			$this->backend
108
-		);
109
-	}
110
-
111
-	public function testGetId(): void {
112
-		$this->assertEquals('tasks', $this->provider->getId());
113
-	}
114
-
115
-	public function testGetName(): void {
116
-		$this->l10n->expects($this->exactly(1))
117
-			->method('t')
118
-			->with('Tasks')
119
-			->willReturnArgument(0);
120
-
121
-		$this->assertEquals('Tasks', $this->provider->getName());
122
-	}
123
-
124
-	public function testSearchAppDisabled(): void {
125
-		$user = $this->createMock(IUser::class);
126
-		$query = $this->createMock(ISearchQuery::class);
127
-		$this->appManager->expects($this->once())
128
-			->method('isEnabledForUser')
129
-			->with('tasks', $user)
130
-			->willReturn(false);
131
-		$this->l10n->expects($this->exactly(1))
132
-			->method('t')
133
-			->willReturnArgument(0);
134
-		$this->backend->expects($this->never())
135
-			->method('getCalendarsForUser');
136
-		$this->backend->expects($this->never())
137
-			->method('getSubscriptionsForUser');
138
-		$this->backend->expects($this->never())
139
-			->method('searchPrincipalUri');
140
-
141
-		$actual = $this->provider->search($user, $query);
142
-		$data = $actual->jsonSerialize();
143
-		$this->assertInstanceOf(SearchResult::class, $actual);
144
-		$this->assertEquals('Tasks', $data['name']);
145
-		$this->assertEmpty($data['entries']);
146
-		$this->assertFalse($data['isPaginated']);
147
-		$this->assertNull($data['cursor']);
148
-	}
149
-
150
-	public function testSearch(): void {
151
-		$user = $this->createMock(IUser::class);
152
-		$user->method('getUID')->willReturn('john.doe');
153
-		$query = $this->createMock(ISearchQuery::class);
154
-		$query->method('getTerm')->willReturn('search term');
155
-		$query->method('getLimit')->willReturn(5);
156
-		$query->method('getCursor')->willReturn(20);
157
-		$this->appManager->expects($this->once())
158
-			->method('isEnabledForUser')
159
-			->with('tasks', $user)
160
-			->willReturn(true);
161
-		$this->l10n->method('t')->willReturnArgument(0);
162
-
163
-		$this->backend->expects($this->once())
164
-			->method('getCalendarsForUser')
165
-			->with('principals/users/john.doe')
166
-			->willReturn([
167
-				[
168
-					'id' => 99,
169
-					'principaluri' => 'principals/users/john.doe',
170
-					'uri' => 'calendar-uri-99',
171
-				], [
172
-					'id' => 123,
173
-					'principaluri' => 'principals/users/john.doe',
174
-					'uri' => 'calendar-uri-123',
175
-				]
176
-			]);
177
-		$this->backend->expects($this->once())
178
-			->method('getSubscriptionsForUser')
179
-			->with('principals/users/john.doe')
180
-			->willReturn([
181
-				[
182
-					'id' => 1337,
183
-					'principaluri' => 'principals/users/john.doe',
184
-					'uri' => 'subscription-uri-1337',
185
-				]
186
-			]);
187
-		$this->backend->expects($this->once())
188
-			->method('searchPrincipalUri')
189
-			->with('principals/users/john.doe', '', ['VTODO'],
190
-				['SUMMARY', 'DESCRIPTION', 'CATEGORIES'],
191
-				[],
192
-				['limit' => 5, 'offset' => 20, 'since' => null, 'until' => null])
193
-			->willReturn([
194
-				[
195
-					'calendarid' => 99,
196
-					'calendartype' => CalDavBackend::CALENDAR_TYPE_CALENDAR,
197
-					'uri' => 'todo0.ics',
198
-					'calendardata' => self::$vTodo0,
199
-				],
200
-				[
201
-					'calendarid' => 123,
202
-					'calendartype' => CalDavBackend::CALENDAR_TYPE_CALENDAR,
203
-					'uri' => 'todo1.ics',
204
-					'calendardata' => self::$vTodo1,
205
-				],
206
-				[
207
-					'calendarid' => 1337,
208
-					'calendartype' => CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION,
209
-					'uri' => 'todo2.ics',
210
-					'calendardata' => self::$vTodo2,
211
-				]
212
-			]);
213
-
214
-		$provider = $this->getMockBuilder(TasksSearchProvider::class)
215
-			->setConstructorArgs([
216
-				$this->appManager,
217
-				$this->l10n,
218
-				$this->urlGenerator,
219
-				$this->backend,
220
-			])
221
-			->onlyMethods([
222
-				'getDeepLinkToTasksApp',
223
-				'generateSubline',
224
-			])
225
-			->getMock();
226
-
227
-		$provider->expects($this->exactly(3))
228
-			->method('generateSubline')
229
-			->willReturn('subline');
230
-		$provider->expects($this->exactly(3))
231
-			->method('getDeepLinkToTasksApp')
232
-			->willReturnMap([
233
-				['calendar-uri-99', 'todo0.ics', 'deep-link-to-tasks'],
234
-				['calendar-uri-123', 'todo1.ics', 'deep-link-to-tasks'],
235
-				['subscription-uri-1337', 'todo2.ics', 'deep-link-to-tasks']
236
-			]);
237
-
238
-		$actual = $provider->search($user, $query);
239
-		$data = $actual->jsonSerialize();
240
-		$this->assertInstanceOf(SearchResult::class, $actual);
241
-		$this->assertEquals('Tasks', $data['name']);
242
-		$this->assertCount(3, $data['entries']);
243
-		$this->assertTrue($data['isPaginated']);
244
-		$this->assertEquals(23, $data['cursor']);
245
-
246
-		$result0 = $data['entries'][0];
247
-		$result0Data = $result0->jsonSerialize();
248
-		$result1 = $data['entries'][1];
249
-		$result1Data = $result1->jsonSerialize();
250
-		$result2 = $data['entries'][2];
251
-		$result2Data = $result2->jsonSerialize();
252
-
253
-		$this->assertInstanceOf(SearchResultEntry::class, $result0);
254
-		$this->assertEmpty($result0Data['thumbnailUrl']);
255
-		$this->assertEquals('Untitled task', $result0Data['title']);
256
-		$this->assertEquals('subline', $result0Data['subline']);
257
-		$this->assertEquals('deep-link-to-tasks', $result0Data['resourceUrl']);
258
-		$this->assertEquals('icon-checkmark', $result0Data['icon']);
259
-		$this->assertFalse($result0Data['rounded']);
260
-
261
-		$this->assertInstanceOf(SearchResultEntry::class, $result1);
262
-		$this->assertEmpty($result1Data['thumbnailUrl']);
263
-		$this->assertEquals('Task title', $result1Data['title']);
264
-		$this->assertEquals('subline', $result1Data['subline']);
265
-		$this->assertEquals('deep-link-to-tasks', $result1Data['resourceUrl']);
266
-		$this->assertEquals('icon-checkmark', $result1Data['icon']);
267
-		$this->assertFalse($result1Data['rounded']);
268
-
269
-		$this->assertInstanceOf(SearchResultEntry::class, $result2);
270
-		$this->assertEmpty($result2Data['thumbnailUrl']);
271
-		$this->assertEquals('Task title', $result2Data['title']);
272
-		$this->assertEquals('subline', $result2Data['subline']);
273
-		$this->assertEquals('deep-link-to-tasks', $result2Data['resourceUrl']);
274
-		$this->assertEquals('icon-checkmark', $result2Data['icon']);
275
-		$this->assertFalse($result2Data['rounded']);
276
-	}
277
-
278
-	public function testGetDeepLinkToTasksApp(): void {
279
-		$this->urlGenerator->expects($this->once())
280
-			->method('linkToRoute')
281
-			->with('tasks.page.index')
282
-			->willReturn('link-to-route-tasks.index');
283
-		$this->urlGenerator->expects($this->once())
284
-			->method('getAbsoluteURL')
285
-			->with('link-to-route-tasks.indexcalendars/uri-john.doe/tasks/task-uri.ics')
286
-			->willReturn('absolute-url-link-to-route-tasks.indexcalendars/uri-john.doe/tasks/task-uri.ics');
287
-
288
-		$actual = self::invokePrivate($this->provider, 'getDeepLinkToTasksApp', ['uri-john.doe', 'task-uri.ics']);
289
-		$this->assertEquals('absolute-url-link-to-route-tasks.indexcalendars/uri-john.doe/tasks/task-uri.ics', $actual);
290
-	}
291
-
292
-	#[\PHPUnit\Framework\Attributes\DataProvider('generateSublineDataProvider')]
293
-	public function testGenerateSubline(string $ics, string $expectedSubline): void {
294
-		$vCalendar = Reader::read($ics, Reader::OPTION_FORGIVING);
295
-		$taskComponent = $vCalendar->VTODO;
296
-
297
-		$this->l10n->method('t')->willReturnArgument(0);
298
-		$this->l10n->method('l')->willReturnArgument(0);
299
-
300
-		$actual = self::invokePrivate($this->provider, 'generateSubline', [$taskComponent]);
301
-		$this->assertEquals($expectedSubline, $actual);
302
-	}
303
-
304
-	public static function generateSublineDataProvider(): array {
305
-		return [
306
-			[self::$vTodo0, ''],
307
-			[self::$vTodo1, 'Completed on %s'],
308
-			[self::$vTodo2, 'Completed on %s'],
309
-			[self::$vTodo3, 'Due on %s'],
310
-			[self::$vTodo4, 'Due on %s by %s'],
311
-		];
312
-	}
25
+    private IAppManager&MockObject $appManager;
26
+    private IL10N&MockObject $l10n;
27
+    private IURLGenerator&MockObject $urlGenerator;
28
+    private CalDavBackend&MockObject $backend;
29
+    private TasksSearchProvider $provider;
30
+
31
+    // NO DUE NOR COMPLETED NOR SUMMARY
32
+    private static string $vTodo0 = 'BEGIN:VCALENDAR' . PHP_EOL
33
+        . 'PRODID:TEST' . PHP_EOL
34
+        . 'VERSION:2.0' . PHP_EOL
35
+        . 'BEGIN:VTODO' . PHP_EOL
36
+        . 'UID:[email protected]' . PHP_EOL
37
+        . 'DTSTAMP:20070313T123432Z' . PHP_EOL
38
+        . 'STATUS:NEEDS-ACTION' . PHP_EOL
39
+        . 'END:VTODO' . PHP_EOL
40
+        . 'END:VCALENDAR';
41
+
42
+    // DUE AND COMPLETED
43
+    private static string $vTodo1 = 'BEGIN:VCALENDAR' . PHP_EOL
44
+        . 'PRODID:TEST' . PHP_EOL
45
+        . 'VERSION:2.0' . PHP_EOL
46
+        . 'BEGIN:VTODO' . PHP_EOL
47
+        . 'UID:[email protected]' . PHP_EOL
48
+        . 'DTSTAMP:20070313T123432Z' . PHP_EOL
49
+        . 'COMPLETED:20070707T100000Z' . PHP_EOL
50
+        . 'DUE;VALUE=DATE:20070501' . PHP_EOL
51
+        . 'SUMMARY:Task title' . PHP_EOL
52
+        . 'STATUS:NEEDS-ACTION' . PHP_EOL
53
+        . 'END:VTODO' . PHP_EOL
54
+        . 'END:VCALENDAR';
55
+
56
+    // COMPLETED ONLY
57
+    private static string $vTodo2 = 'BEGIN:VCALENDAR' . PHP_EOL
58
+        . 'PRODID:TEST' . PHP_EOL
59
+        . 'VERSION:2.0' . PHP_EOL
60
+        . 'BEGIN:VTODO' . PHP_EOL
61
+        . 'UID:[email protected]' . PHP_EOL
62
+        . 'DTSTAMP:20070313T123432Z' . PHP_EOL
63
+        . 'COMPLETED:20070707T100000Z' . PHP_EOL
64
+        . 'SUMMARY:Task title' . PHP_EOL
65
+        . 'STATUS:NEEDS-ACTION' . PHP_EOL
66
+        . 'END:VTODO' . PHP_EOL
67
+        . 'END:VCALENDAR';
68
+
69
+    // DUE DATE
70
+    private static string $vTodo3 = 'BEGIN:VCALENDAR' . PHP_EOL
71
+        . 'PRODID:TEST' . PHP_EOL
72
+        . 'VERSION:2.0' . PHP_EOL
73
+        . 'BEGIN:VTODO' . PHP_EOL
74
+        . 'UID:[email protected]' . PHP_EOL
75
+        . 'DTSTAMP:20070313T123432Z' . PHP_EOL
76
+        . 'DUE;VALUE=DATE:20070501' . PHP_EOL
77
+        . 'SUMMARY:Task title' . PHP_EOL
78
+        . 'STATUS:NEEDS-ACTION' . PHP_EOL
79
+        . 'END:VTODO' . PHP_EOL
80
+        . 'END:VCALENDAR';
81
+
82
+    // DUE DATETIME
83
+    private static string $vTodo4 = 'BEGIN:VCALENDAR' . PHP_EOL
84
+        . 'PRODID:TEST' . PHP_EOL
85
+        . 'VERSION:2.0' . PHP_EOL
86
+        . 'BEGIN:VTODO' . PHP_EOL
87
+        . 'UID:[email protected]' . PHP_EOL
88
+        . 'DTSTAMP:20070313T123432Z' . PHP_EOL
89
+        . 'DUE:20070709T130000Z' . PHP_EOL
90
+        . 'SUMMARY:Task title' . PHP_EOL
91
+        . 'STATUS:NEEDS-ACTION' . PHP_EOL
92
+        . 'END:VTODO' . PHP_EOL
93
+        . 'END:VCALENDAR';
94
+
95
+    protected function setUp(): void {
96
+        parent::setUp();
97
+
98
+        $this->appManager = $this->createMock(IAppManager::class);
99
+        $this->l10n = $this->createMock(IL10N::class);
100
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
101
+        $this->backend = $this->createMock(CalDavBackend::class);
102
+
103
+        $this->provider = new TasksSearchProvider(
104
+            $this->appManager,
105
+            $this->l10n,
106
+            $this->urlGenerator,
107
+            $this->backend
108
+        );
109
+    }
110
+
111
+    public function testGetId(): void {
112
+        $this->assertEquals('tasks', $this->provider->getId());
113
+    }
114
+
115
+    public function testGetName(): void {
116
+        $this->l10n->expects($this->exactly(1))
117
+            ->method('t')
118
+            ->with('Tasks')
119
+            ->willReturnArgument(0);
120
+
121
+        $this->assertEquals('Tasks', $this->provider->getName());
122
+    }
123
+
124
+    public function testSearchAppDisabled(): void {
125
+        $user = $this->createMock(IUser::class);
126
+        $query = $this->createMock(ISearchQuery::class);
127
+        $this->appManager->expects($this->once())
128
+            ->method('isEnabledForUser')
129
+            ->with('tasks', $user)
130
+            ->willReturn(false);
131
+        $this->l10n->expects($this->exactly(1))
132
+            ->method('t')
133
+            ->willReturnArgument(0);
134
+        $this->backend->expects($this->never())
135
+            ->method('getCalendarsForUser');
136
+        $this->backend->expects($this->never())
137
+            ->method('getSubscriptionsForUser');
138
+        $this->backend->expects($this->never())
139
+            ->method('searchPrincipalUri');
140
+
141
+        $actual = $this->provider->search($user, $query);
142
+        $data = $actual->jsonSerialize();
143
+        $this->assertInstanceOf(SearchResult::class, $actual);
144
+        $this->assertEquals('Tasks', $data['name']);
145
+        $this->assertEmpty($data['entries']);
146
+        $this->assertFalse($data['isPaginated']);
147
+        $this->assertNull($data['cursor']);
148
+    }
149
+
150
+    public function testSearch(): void {
151
+        $user = $this->createMock(IUser::class);
152
+        $user->method('getUID')->willReturn('john.doe');
153
+        $query = $this->createMock(ISearchQuery::class);
154
+        $query->method('getTerm')->willReturn('search term');
155
+        $query->method('getLimit')->willReturn(5);
156
+        $query->method('getCursor')->willReturn(20);
157
+        $this->appManager->expects($this->once())
158
+            ->method('isEnabledForUser')
159
+            ->with('tasks', $user)
160
+            ->willReturn(true);
161
+        $this->l10n->method('t')->willReturnArgument(0);
162
+
163
+        $this->backend->expects($this->once())
164
+            ->method('getCalendarsForUser')
165
+            ->with('principals/users/john.doe')
166
+            ->willReturn([
167
+                [
168
+                    'id' => 99,
169
+                    'principaluri' => 'principals/users/john.doe',
170
+                    'uri' => 'calendar-uri-99',
171
+                ], [
172
+                    'id' => 123,
173
+                    'principaluri' => 'principals/users/john.doe',
174
+                    'uri' => 'calendar-uri-123',
175
+                ]
176
+            ]);
177
+        $this->backend->expects($this->once())
178
+            ->method('getSubscriptionsForUser')
179
+            ->with('principals/users/john.doe')
180
+            ->willReturn([
181
+                [
182
+                    'id' => 1337,
183
+                    'principaluri' => 'principals/users/john.doe',
184
+                    'uri' => 'subscription-uri-1337',
185
+                ]
186
+            ]);
187
+        $this->backend->expects($this->once())
188
+            ->method('searchPrincipalUri')
189
+            ->with('principals/users/john.doe', '', ['VTODO'],
190
+                ['SUMMARY', 'DESCRIPTION', 'CATEGORIES'],
191
+                [],
192
+                ['limit' => 5, 'offset' => 20, 'since' => null, 'until' => null])
193
+            ->willReturn([
194
+                [
195
+                    'calendarid' => 99,
196
+                    'calendartype' => CalDavBackend::CALENDAR_TYPE_CALENDAR,
197
+                    'uri' => 'todo0.ics',
198
+                    'calendardata' => self::$vTodo0,
199
+                ],
200
+                [
201
+                    'calendarid' => 123,
202
+                    'calendartype' => CalDavBackend::CALENDAR_TYPE_CALENDAR,
203
+                    'uri' => 'todo1.ics',
204
+                    'calendardata' => self::$vTodo1,
205
+                ],
206
+                [
207
+                    'calendarid' => 1337,
208
+                    'calendartype' => CalDavBackend::CALENDAR_TYPE_SUBSCRIPTION,
209
+                    'uri' => 'todo2.ics',
210
+                    'calendardata' => self::$vTodo2,
211
+                ]
212
+            ]);
213
+
214
+        $provider = $this->getMockBuilder(TasksSearchProvider::class)
215
+            ->setConstructorArgs([
216
+                $this->appManager,
217
+                $this->l10n,
218
+                $this->urlGenerator,
219
+                $this->backend,
220
+            ])
221
+            ->onlyMethods([
222
+                'getDeepLinkToTasksApp',
223
+                'generateSubline',
224
+            ])
225
+            ->getMock();
226
+
227
+        $provider->expects($this->exactly(3))
228
+            ->method('generateSubline')
229
+            ->willReturn('subline');
230
+        $provider->expects($this->exactly(3))
231
+            ->method('getDeepLinkToTasksApp')
232
+            ->willReturnMap([
233
+                ['calendar-uri-99', 'todo0.ics', 'deep-link-to-tasks'],
234
+                ['calendar-uri-123', 'todo1.ics', 'deep-link-to-tasks'],
235
+                ['subscription-uri-1337', 'todo2.ics', 'deep-link-to-tasks']
236
+            ]);
237
+
238
+        $actual = $provider->search($user, $query);
239
+        $data = $actual->jsonSerialize();
240
+        $this->assertInstanceOf(SearchResult::class, $actual);
241
+        $this->assertEquals('Tasks', $data['name']);
242
+        $this->assertCount(3, $data['entries']);
243
+        $this->assertTrue($data['isPaginated']);
244
+        $this->assertEquals(23, $data['cursor']);
245
+
246
+        $result0 = $data['entries'][0];
247
+        $result0Data = $result0->jsonSerialize();
248
+        $result1 = $data['entries'][1];
249
+        $result1Data = $result1->jsonSerialize();
250
+        $result2 = $data['entries'][2];
251
+        $result2Data = $result2->jsonSerialize();
252
+
253
+        $this->assertInstanceOf(SearchResultEntry::class, $result0);
254
+        $this->assertEmpty($result0Data['thumbnailUrl']);
255
+        $this->assertEquals('Untitled task', $result0Data['title']);
256
+        $this->assertEquals('subline', $result0Data['subline']);
257
+        $this->assertEquals('deep-link-to-tasks', $result0Data['resourceUrl']);
258
+        $this->assertEquals('icon-checkmark', $result0Data['icon']);
259
+        $this->assertFalse($result0Data['rounded']);
260
+
261
+        $this->assertInstanceOf(SearchResultEntry::class, $result1);
262
+        $this->assertEmpty($result1Data['thumbnailUrl']);
263
+        $this->assertEquals('Task title', $result1Data['title']);
264
+        $this->assertEquals('subline', $result1Data['subline']);
265
+        $this->assertEquals('deep-link-to-tasks', $result1Data['resourceUrl']);
266
+        $this->assertEquals('icon-checkmark', $result1Data['icon']);
267
+        $this->assertFalse($result1Data['rounded']);
268
+
269
+        $this->assertInstanceOf(SearchResultEntry::class, $result2);
270
+        $this->assertEmpty($result2Data['thumbnailUrl']);
271
+        $this->assertEquals('Task title', $result2Data['title']);
272
+        $this->assertEquals('subline', $result2Data['subline']);
273
+        $this->assertEquals('deep-link-to-tasks', $result2Data['resourceUrl']);
274
+        $this->assertEquals('icon-checkmark', $result2Data['icon']);
275
+        $this->assertFalse($result2Data['rounded']);
276
+    }
277
+
278
+    public function testGetDeepLinkToTasksApp(): void {
279
+        $this->urlGenerator->expects($this->once())
280
+            ->method('linkToRoute')
281
+            ->with('tasks.page.index')
282
+            ->willReturn('link-to-route-tasks.index');
283
+        $this->urlGenerator->expects($this->once())
284
+            ->method('getAbsoluteURL')
285
+            ->with('link-to-route-tasks.indexcalendars/uri-john.doe/tasks/task-uri.ics')
286
+            ->willReturn('absolute-url-link-to-route-tasks.indexcalendars/uri-john.doe/tasks/task-uri.ics');
287
+
288
+        $actual = self::invokePrivate($this->provider, 'getDeepLinkToTasksApp', ['uri-john.doe', 'task-uri.ics']);
289
+        $this->assertEquals('absolute-url-link-to-route-tasks.indexcalendars/uri-john.doe/tasks/task-uri.ics', $actual);
290
+    }
291
+
292
+    #[\PHPUnit\Framework\Attributes\DataProvider('generateSublineDataProvider')]
293
+    public function testGenerateSubline(string $ics, string $expectedSubline): void {
294
+        $vCalendar = Reader::read($ics, Reader::OPTION_FORGIVING);
295
+        $taskComponent = $vCalendar->VTODO;
296
+
297
+        $this->l10n->method('t')->willReturnArgument(0);
298
+        $this->l10n->method('l')->willReturnArgument(0);
299
+
300
+        $actual = self::invokePrivate($this->provider, 'generateSubline', [$taskComponent]);
301
+        $this->assertEquals($expectedSubline, $actual);
302
+    }
303
+
304
+    public static function generateSublineDataProvider(): array {
305
+        return [
306
+            [self::$vTodo0, ''],
307
+            [self::$vTodo1, 'Completed on %s'],
308
+            [self::$vTodo2, 'Completed on %s'],
309
+            [self::$vTodo3, 'Due on %s'],
310
+            [self::$vTodo4, 'Due on %s by %s'],
311
+        ];
312
+    }
313 313
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Controller/InvitationResponseControllerTest.php 1 patch
Indentation   +359 added lines, -359 removed lines patch added patch discarded remove patch
@@ -23,50 +23,50 @@  discard block
 block discarded – undo
23 23
 use Test\TestCase;
24 24
 
25 25
 class InvitationResponseControllerTest extends TestCase {
26
-	private IDBConnection&MockObject $dbConnection;
27
-	private IRequest&MockObject $request;
28
-	private ITimeFactory&MockObject $timeFactory;
29
-	private InvitationResponseServer&MockObject $responseServer;
30
-	private InvitationResponseController $controller;
31
-
32
-	protected function setUp(): void {
33
-		parent::setUp();
34
-
35
-		$this->dbConnection = $this->createMock(IDBConnection::class);
36
-		$this->request = $this->createMock(IRequest::class);
37
-		$this->timeFactory = $this->createMock(ITimeFactory::class);
38
-		$this->responseServer = $this->createMock(InvitationResponseServer::class);
39
-
40
-		$this->controller = new InvitationResponseController(
41
-			'appName',
42
-			$this->request,
43
-			$this->dbConnection,
44
-			$this->timeFactory,
45
-			$this->responseServer
46
-		);
47
-	}
48
-
49
-	public static function attendeeProvider(): array {
50
-		return [
51
-			'local attendee' => [false],
52
-			'external attendee' => [true]
53
-		];
54
-	}
55
-
56
-	#[\PHPUnit\Framework\Attributes\DataProvider('attendeeProvider')]
57
-	public function testAccept(bool $isExternalAttendee): void {
58
-		$this->buildQueryExpects('TOKEN123', [
59
-			'id' => 0,
60
-			'uid' => 'this-is-the-events-uid',
61
-			'recurrenceid' => null,
62
-			'attendee' => 'mailto:[email protected]',
63
-			'organizer' => 'mailto:[email protected]',
64
-			'sequence' => null,
65
-			'token' => 'TOKEN123',
66
-			'expiration' => 420000,
67
-		], 1337);
68
-
69
-		$expected = <<<EOF
26
+    private IDBConnection&MockObject $dbConnection;
27
+    private IRequest&MockObject $request;
28
+    private ITimeFactory&MockObject $timeFactory;
29
+    private InvitationResponseServer&MockObject $responseServer;
30
+    private InvitationResponseController $controller;
31
+
32
+    protected function setUp(): void {
33
+        parent::setUp();
34
+
35
+        $this->dbConnection = $this->createMock(IDBConnection::class);
36
+        $this->request = $this->createMock(IRequest::class);
37
+        $this->timeFactory = $this->createMock(ITimeFactory::class);
38
+        $this->responseServer = $this->createMock(InvitationResponseServer::class);
39
+
40
+        $this->controller = new InvitationResponseController(
41
+            'appName',
42
+            $this->request,
43
+            $this->dbConnection,
44
+            $this->timeFactory,
45
+            $this->responseServer
46
+        );
47
+    }
48
+
49
+    public static function attendeeProvider(): array {
50
+        return [
51
+            'local attendee' => [false],
52
+            'external attendee' => [true]
53
+        ];
54
+    }
55
+
56
+    #[\PHPUnit\Framework\Attributes\DataProvider('attendeeProvider')]
57
+    public function testAccept(bool $isExternalAttendee): void {
58
+        $this->buildQueryExpects('TOKEN123', [
59
+            'id' => 0,
60
+            'uid' => 'this-is-the-events-uid',
61
+            'recurrenceid' => null,
62
+            'attendee' => 'mailto:[email protected]',
63
+            'organizer' => 'mailto:[email protected]',
64
+            'sequence' => null,
65
+            'token' => 'TOKEN123',
66
+            'expiration' => 420000,
67
+        ], 1337);
68
+
69
+        $expected = <<<EOF
70 70
 BEGIN:VCALENDAR
71 71
 VERSION:2.0
72 72
 PRODID:-//Nextcloud/Nextcloud CalDAV Server//EN
@@ -82,53 +82,53 @@  discard block
 block discarded – undo
82 82
 END:VCALENDAR
83 83
 
84 84
 EOF;
85
-		$expected = preg_replace('~\R~u', "\r\n", $expected);
86
-
87
-		$called = false;
88
-		$this->responseServer->expects($this->once())
89
-			->method('handleITipMessage')
90
-			->willReturnCallback(function (Message $iTipMessage) use (&$called, $isExternalAttendee, $expected): void {
91
-				$called = true;
92
-				$this->assertEquals('this-is-the-events-uid', $iTipMessage->uid);
93
-				$this->assertEquals('VEVENT', $iTipMessage->component);
94
-				$this->assertEquals('REPLY', $iTipMessage->method);
95
-				$this->assertEquals(null, $iTipMessage->sequence);
96
-				$this->assertEquals('mailto:[email protected]', $iTipMessage->sender);
97
-				if ($isExternalAttendee) {
98
-					$this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
99
-				} else {
100
-					$this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
101
-				}
102
-
103
-				$iTipMessage->scheduleStatus = '1.2;Message delivered locally';
104
-
105
-				$this->assertEquals($expected, $iTipMessage->message->serialize());
106
-			});
107
-		$this->responseServer->expects($this->once())
108
-			->method('isExternalAttendee')
109
-			->willReturn($isExternalAttendee);
110
-
111
-		$response = $this->controller->accept('TOKEN123');
112
-		$this->assertInstanceOf(TemplateResponse::class, $response);
113
-		$this->assertEquals('schedule-response-success', $response->getTemplateName());
114
-		$this->assertEquals([], $response->getParams());
115
-		$this->assertTrue($called);
116
-	}
117
-
118
-	#[\PHPUnit\Framework\Attributes\DataProvider('attendeeProvider')]
119
-	public function testAcceptSequence(bool $isExternalAttendee): void {
120
-		$this->buildQueryExpects('TOKEN123', [
121
-			'id' => 0,
122
-			'uid' => 'this-is-the-events-uid',
123
-			'recurrenceid' => null,
124
-			'attendee' => 'mailto:[email protected]',
125
-			'organizer' => 'mailto:[email protected]',
126
-			'sequence' => 1337,
127
-			'token' => 'TOKEN123',
128
-			'expiration' => 420000,
129
-		], 1337);
130
-
131
-		$expected = <<<EOF
85
+        $expected = preg_replace('~\R~u', "\r\n", $expected);
86
+
87
+        $called = false;
88
+        $this->responseServer->expects($this->once())
89
+            ->method('handleITipMessage')
90
+            ->willReturnCallback(function (Message $iTipMessage) use (&$called, $isExternalAttendee, $expected): void {
91
+                $called = true;
92
+                $this->assertEquals('this-is-the-events-uid', $iTipMessage->uid);
93
+                $this->assertEquals('VEVENT', $iTipMessage->component);
94
+                $this->assertEquals('REPLY', $iTipMessage->method);
95
+                $this->assertEquals(null, $iTipMessage->sequence);
96
+                $this->assertEquals('mailto:[email protected]', $iTipMessage->sender);
97
+                if ($isExternalAttendee) {
98
+                    $this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
99
+                } else {
100
+                    $this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
101
+                }
102
+
103
+                $iTipMessage->scheduleStatus = '1.2;Message delivered locally';
104
+
105
+                $this->assertEquals($expected, $iTipMessage->message->serialize());
106
+            });
107
+        $this->responseServer->expects($this->once())
108
+            ->method('isExternalAttendee')
109
+            ->willReturn($isExternalAttendee);
110
+
111
+        $response = $this->controller->accept('TOKEN123');
112
+        $this->assertInstanceOf(TemplateResponse::class, $response);
113
+        $this->assertEquals('schedule-response-success', $response->getTemplateName());
114
+        $this->assertEquals([], $response->getParams());
115
+        $this->assertTrue($called);
116
+    }
117
+
118
+    #[\PHPUnit\Framework\Attributes\DataProvider('attendeeProvider')]
119
+    public function testAcceptSequence(bool $isExternalAttendee): void {
120
+        $this->buildQueryExpects('TOKEN123', [
121
+            'id' => 0,
122
+            'uid' => 'this-is-the-events-uid',
123
+            'recurrenceid' => null,
124
+            'attendee' => 'mailto:[email protected]',
125
+            'organizer' => 'mailto:[email protected]',
126
+            'sequence' => 1337,
127
+            'token' => 'TOKEN123',
128
+            'expiration' => 420000,
129
+        ], 1337);
130
+
131
+        $expected = <<<EOF
132 132
 BEGIN:VCALENDAR
133 133
 VERSION:2.0
134 134
 PRODID:-//Nextcloud/Nextcloud CalDAV Server//EN
@@ -144,53 +144,53 @@  discard block
 block discarded – undo
144 144
 END:VCALENDAR
145 145
 
146 146
 EOF;
147
-		$expected = preg_replace('~\R~u', "\r\n", $expected);
148
-
149
-		$called = false;
150
-		$this->responseServer->expects($this->once())
151
-			->method('handleITipMessage')
152
-			->willReturnCallback(function (Message $iTipMessage) use (&$called, $isExternalAttendee, $expected): void {
153
-				$called = true;
154
-				$this->assertEquals('this-is-the-events-uid', $iTipMessage->uid);
155
-				$this->assertEquals('VEVENT', $iTipMessage->component);
156
-				$this->assertEquals('REPLY', $iTipMessage->method);
157
-				$this->assertEquals(1337, $iTipMessage->sequence);
158
-				$this->assertEquals('mailto:[email protected]', $iTipMessage->sender);
159
-				if ($isExternalAttendee) {
160
-					$this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
161
-				} else {
162
-					$this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
163
-				}
164
-
165
-				$iTipMessage->scheduleStatus = '1.2;Message delivered locally';
166
-
167
-				$this->assertEquals($expected, $iTipMessage->message->serialize());
168
-			});
169
-		$this->responseServer->expects($this->once())
170
-			->method('isExternalAttendee')
171
-			->willReturn($isExternalAttendee);
172
-
173
-		$response = $this->controller->accept('TOKEN123');
174
-		$this->assertInstanceOf(TemplateResponse::class, $response);
175
-		$this->assertEquals('schedule-response-success', $response->getTemplateName());
176
-		$this->assertEquals([], $response->getParams());
177
-		$this->assertTrue($called);
178
-	}
179
-
180
-	#[\PHPUnit\Framework\Attributes\DataProvider('attendeeProvider')]
181
-	public function testAcceptRecurrenceId(bool $isExternalAttendee): void {
182
-		$this->buildQueryExpects('TOKEN123', [
183
-			'id' => 0,
184
-			'uid' => 'this-is-the-events-uid',
185
-			'recurrenceid' => "RECURRENCE-ID;TZID=Europe/Berlin:20180726T150000\n",
186
-			'attendee' => 'mailto:[email protected]',
187
-			'organizer' => 'mailto:[email protected]',
188
-			'sequence' => null,
189
-			'token' => 'TOKEN123',
190
-			'expiration' => 420000,
191
-		], 1337);
192
-
193
-		$expected = <<<EOF
147
+        $expected = preg_replace('~\R~u', "\r\n", $expected);
148
+
149
+        $called = false;
150
+        $this->responseServer->expects($this->once())
151
+            ->method('handleITipMessage')
152
+            ->willReturnCallback(function (Message $iTipMessage) use (&$called, $isExternalAttendee, $expected): void {
153
+                $called = true;
154
+                $this->assertEquals('this-is-the-events-uid', $iTipMessage->uid);
155
+                $this->assertEquals('VEVENT', $iTipMessage->component);
156
+                $this->assertEquals('REPLY', $iTipMessage->method);
157
+                $this->assertEquals(1337, $iTipMessage->sequence);
158
+                $this->assertEquals('mailto:[email protected]', $iTipMessage->sender);
159
+                if ($isExternalAttendee) {
160
+                    $this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
161
+                } else {
162
+                    $this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
163
+                }
164
+
165
+                $iTipMessage->scheduleStatus = '1.2;Message delivered locally';
166
+
167
+                $this->assertEquals($expected, $iTipMessage->message->serialize());
168
+            });
169
+        $this->responseServer->expects($this->once())
170
+            ->method('isExternalAttendee')
171
+            ->willReturn($isExternalAttendee);
172
+
173
+        $response = $this->controller->accept('TOKEN123');
174
+        $this->assertInstanceOf(TemplateResponse::class, $response);
175
+        $this->assertEquals('schedule-response-success', $response->getTemplateName());
176
+        $this->assertEquals([], $response->getParams());
177
+        $this->assertTrue($called);
178
+    }
179
+
180
+    #[\PHPUnit\Framework\Attributes\DataProvider('attendeeProvider')]
181
+    public function testAcceptRecurrenceId(bool $isExternalAttendee): void {
182
+        $this->buildQueryExpects('TOKEN123', [
183
+            'id' => 0,
184
+            'uid' => 'this-is-the-events-uid',
185
+            'recurrenceid' => "RECURRENCE-ID;TZID=Europe/Berlin:20180726T150000\n",
186
+            'attendee' => 'mailto:[email protected]',
187
+            'organizer' => 'mailto:[email protected]',
188
+            'sequence' => null,
189
+            'token' => 'TOKEN123',
190
+            'expiration' => 420000,
191
+        ], 1337);
192
+
193
+        $expected = <<<EOF
194 194
 BEGIN:VCALENDAR
195 195
 VERSION:2.0
196 196
 PRODID:-//Nextcloud/Nextcloud CalDAV Server//EN
@@ -207,80 +207,80 @@  discard block
 block discarded – undo
207 207
 END:VCALENDAR
208 208
 
209 209
 EOF;
210
-		$expected = preg_replace('~\R~u', "\r\n", $expected);
211
-
212
-		$called = false;
213
-		$this->responseServer->expects($this->once())
214
-			->method('handleITipMessage')
215
-			->willReturnCallback(function (Message $iTipMessage) use (&$called, $isExternalAttendee, $expected): void {
216
-				$called = true;
217
-				$this->assertEquals('this-is-the-events-uid', $iTipMessage->uid);
218
-				$this->assertEquals('VEVENT', $iTipMessage->component);
219
-				$this->assertEquals('REPLY', $iTipMessage->method);
220
-				$this->assertEquals(0, $iTipMessage->sequence);
221
-				$this->assertEquals('mailto:[email protected]', $iTipMessage->sender);
222
-				if ($isExternalAttendee) {
223
-					$this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
224
-				} else {
225
-					$this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
226
-				}
227
-
228
-				$iTipMessage->scheduleStatus = '1.2;Message delivered locally';
229
-
230
-				$this->assertEquals($expected, $iTipMessage->message->serialize());
231
-			});
232
-		$this->responseServer->expects($this->once())
233
-			->method('isExternalAttendee')
234
-			->willReturn($isExternalAttendee);
235
-
236
-		$response = $this->controller->accept('TOKEN123');
237
-		$this->assertInstanceOf(TemplateResponse::class, $response);
238
-		$this->assertEquals('schedule-response-success', $response->getTemplateName());
239
-		$this->assertEquals([], $response->getParams());
240
-		$this->assertTrue($called);
241
-	}
242
-
243
-	public function testAcceptTokenNotFound(): void {
244
-		$this->buildQueryExpects('TOKEN123', null, 1337);
245
-
246
-		$response = $this->controller->accept('TOKEN123');
247
-		$this->assertInstanceOf(TemplateResponse::class, $response);
248
-		$this->assertEquals('schedule-response-error', $response->getTemplateName());
249
-		$this->assertEquals([], $response->getParams());
250
-	}
251
-
252
-	public function testAcceptExpiredToken(): void {
253
-		$this->buildQueryExpects('TOKEN123', [
254
-			'id' => 0,
255
-			'uid' => 'this-is-the-events-uid',
256
-			'recurrenceid' => null,
257
-			'attendee' => 'mailto:[email protected]',
258
-			'organizer' => 'mailto:[email protected]',
259
-			'sequence' => null,
260
-			'token' => 'TOKEN123',
261
-			'expiration' => 42,
262
-		], 1337);
263
-
264
-		$response = $this->controller->accept('TOKEN123');
265
-		$this->assertInstanceOf(TemplateResponse::class, $response);
266
-		$this->assertEquals('schedule-response-error', $response->getTemplateName());
267
-		$this->assertEquals([], $response->getParams());
268
-	}
269
-
270
-	#[\PHPUnit\Framework\Attributes\DataProvider('attendeeProvider')]
271
-	public function testDecline(bool $isExternalAttendee): void {
272
-		$this->buildQueryExpects('TOKEN123', [
273
-			'id' => 0,
274
-			'uid' => 'this-is-the-events-uid',
275
-			'recurrenceid' => null,
276
-			'attendee' => 'mailto:[email protected]',
277
-			'organizer' => 'mailto:[email protected]',
278
-			'sequence' => null,
279
-			'token' => 'TOKEN123',
280
-			'expiration' => 420000,
281
-		], 1337);
282
-
283
-		$expected = <<<EOF
210
+        $expected = preg_replace('~\R~u', "\r\n", $expected);
211
+
212
+        $called = false;
213
+        $this->responseServer->expects($this->once())
214
+            ->method('handleITipMessage')
215
+            ->willReturnCallback(function (Message $iTipMessage) use (&$called, $isExternalAttendee, $expected): void {
216
+                $called = true;
217
+                $this->assertEquals('this-is-the-events-uid', $iTipMessage->uid);
218
+                $this->assertEquals('VEVENT', $iTipMessage->component);
219
+                $this->assertEquals('REPLY', $iTipMessage->method);
220
+                $this->assertEquals(0, $iTipMessage->sequence);
221
+                $this->assertEquals('mailto:[email protected]', $iTipMessage->sender);
222
+                if ($isExternalAttendee) {
223
+                    $this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
224
+                } else {
225
+                    $this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
226
+                }
227
+
228
+                $iTipMessage->scheduleStatus = '1.2;Message delivered locally';
229
+
230
+                $this->assertEquals($expected, $iTipMessage->message->serialize());
231
+            });
232
+        $this->responseServer->expects($this->once())
233
+            ->method('isExternalAttendee')
234
+            ->willReturn($isExternalAttendee);
235
+
236
+        $response = $this->controller->accept('TOKEN123');
237
+        $this->assertInstanceOf(TemplateResponse::class, $response);
238
+        $this->assertEquals('schedule-response-success', $response->getTemplateName());
239
+        $this->assertEquals([], $response->getParams());
240
+        $this->assertTrue($called);
241
+    }
242
+
243
+    public function testAcceptTokenNotFound(): void {
244
+        $this->buildQueryExpects('TOKEN123', null, 1337);
245
+
246
+        $response = $this->controller->accept('TOKEN123');
247
+        $this->assertInstanceOf(TemplateResponse::class, $response);
248
+        $this->assertEquals('schedule-response-error', $response->getTemplateName());
249
+        $this->assertEquals([], $response->getParams());
250
+    }
251
+
252
+    public function testAcceptExpiredToken(): void {
253
+        $this->buildQueryExpects('TOKEN123', [
254
+            'id' => 0,
255
+            'uid' => 'this-is-the-events-uid',
256
+            'recurrenceid' => null,
257
+            'attendee' => 'mailto:[email protected]',
258
+            'organizer' => 'mailto:[email protected]',
259
+            'sequence' => null,
260
+            'token' => 'TOKEN123',
261
+            'expiration' => 42,
262
+        ], 1337);
263
+
264
+        $response = $this->controller->accept('TOKEN123');
265
+        $this->assertInstanceOf(TemplateResponse::class, $response);
266
+        $this->assertEquals('schedule-response-error', $response->getTemplateName());
267
+        $this->assertEquals([], $response->getParams());
268
+    }
269
+
270
+    #[\PHPUnit\Framework\Attributes\DataProvider('attendeeProvider')]
271
+    public function testDecline(bool $isExternalAttendee): void {
272
+        $this->buildQueryExpects('TOKEN123', [
273
+            'id' => 0,
274
+            'uid' => 'this-is-the-events-uid',
275
+            'recurrenceid' => null,
276
+            'attendee' => 'mailto:[email protected]',
277
+            'organizer' => 'mailto:[email protected]',
278
+            'sequence' => null,
279
+            'token' => 'TOKEN123',
280
+            'expiration' => 420000,
281
+        ], 1337);
282
+
283
+        $expected = <<<EOF
284 284
 BEGIN:VCALENDAR
285 285
 VERSION:2.0
286 286
 PRODID:-//Nextcloud/Nextcloud CalDAV Server//EN
@@ -296,65 +296,65 @@  discard block
 block discarded – undo
296 296
 END:VCALENDAR
297 297
 
298 298
 EOF;
299
-		$expected = preg_replace('~\R~u', "\r\n", $expected);
300
-
301
-		$called = false;
302
-		$this->responseServer->expects($this->once())
303
-			->method('handleITipMessage')
304
-			->willReturnCallback(function (Message $iTipMessage) use (&$called, $isExternalAttendee, $expected): void {
305
-				$called = true;
306
-				$this->assertEquals('this-is-the-events-uid', $iTipMessage->uid);
307
-				$this->assertEquals('VEVENT', $iTipMessage->component);
308
-				$this->assertEquals('REPLY', $iTipMessage->method);
309
-				$this->assertEquals(null, $iTipMessage->sequence);
310
-				$this->assertEquals('mailto:[email protected]', $iTipMessage->sender);
311
-				if ($isExternalAttendee) {
312
-					$this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
313
-				} else {
314
-					$this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
315
-				}
316
-
317
-				$iTipMessage->scheduleStatus = '1.2;Message delivered locally';
318
-
319
-				$this->assertEquals($expected, $iTipMessage->message->serialize());
320
-			});
321
-		$this->responseServer->expects($this->once())
322
-			->method('isExternalAttendee')
323
-			->willReturn($isExternalAttendee);
324
-
325
-		$response = $this->controller->decline('TOKEN123');
326
-		$this->assertInstanceOf(TemplateResponse::class, $response);
327
-		$this->assertEquals('schedule-response-success', $response->getTemplateName());
328
-		$this->assertEquals([], $response->getParams());
329
-		$this->assertTrue($called);
330
-	}
331
-
332
-	public function testOptions(): void {
333
-		$response = $this->controller->options('TOKEN123');
334
-		$this->assertInstanceOf(TemplateResponse::class, $response);
335
-		$this->assertEquals('schedule-response-options', $response->getTemplateName());
336
-		$this->assertEquals(['token' => 'TOKEN123'], $response->getParams());
337
-	}
338
-
339
-	#[\PHPUnit\Framework\Attributes\DataProvider('attendeeProvider')]
340
-	public function testProcessMoreOptionsResult(bool $isExternalAttendee): void {
341
-		$this->request->expects($this->once())
342
-			->method('getParam')
343
-			->with('partStat')
344
-			->willReturn('TENTATIVE');
345
-
346
-		$this->buildQueryExpects('TOKEN123', [
347
-			'id' => 0,
348
-			'uid' => 'this-is-the-events-uid',
349
-			'recurrenceid' => null,
350
-			'attendee' => 'mailto:[email protected]',
351
-			'organizer' => 'mailto:[email protected]',
352
-			'sequence' => null,
353
-			'token' => 'TOKEN123',
354
-			'expiration' => 420000,
355
-		], 1337);
356
-
357
-		$expected = <<<EOF
299
+        $expected = preg_replace('~\R~u', "\r\n", $expected);
300
+
301
+        $called = false;
302
+        $this->responseServer->expects($this->once())
303
+            ->method('handleITipMessage')
304
+            ->willReturnCallback(function (Message $iTipMessage) use (&$called, $isExternalAttendee, $expected): void {
305
+                $called = true;
306
+                $this->assertEquals('this-is-the-events-uid', $iTipMessage->uid);
307
+                $this->assertEquals('VEVENT', $iTipMessage->component);
308
+                $this->assertEquals('REPLY', $iTipMessage->method);
309
+                $this->assertEquals(null, $iTipMessage->sequence);
310
+                $this->assertEquals('mailto:[email protected]', $iTipMessage->sender);
311
+                if ($isExternalAttendee) {
312
+                    $this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
313
+                } else {
314
+                    $this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
315
+                }
316
+
317
+                $iTipMessage->scheduleStatus = '1.2;Message delivered locally';
318
+
319
+                $this->assertEquals($expected, $iTipMessage->message->serialize());
320
+            });
321
+        $this->responseServer->expects($this->once())
322
+            ->method('isExternalAttendee')
323
+            ->willReturn($isExternalAttendee);
324
+
325
+        $response = $this->controller->decline('TOKEN123');
326
+        $this->assertInstanceOf(TemplateResponse::class, $response);
327
+        $this->assertEquals('schedule-response-success', $response->getTemplateName());
328
+        $this->assertEquals([], $response->getParams());
329
+        $this->assertTrue($called);
330
+    }
331
+
332
+    public function testOptions(): void {
333
+        $response = $this->controller->options('TOKEN123');
334
+        $this->assertInstanceOf(TemplateResponse::class, $response);
335
+        $this->assertEquals('schedule-response-options', $response->getTemplateName());
336
+        $this->assertEquals(['token' => 'TOKEN123'], $response->getParams());
337
+    }
338
+
339
+    #[\PHPUnit\Framework\Attributes\DataProvider('attendeeProvider')]
340
+    public function testProcessMoreOptionsResult(bool $isExternalAttendee): void {
341
+        $this->request->expects($this->once())
342
+            ->method('getParam')
343
+            ->with('partStat')
344
+            ->willReturn('TENTATIVE');
345
+
346
+        $this->buildQueryExpects('TOKEN123', [
347
+            'id' => 0,
348
+            'uid' => 'this-is-the-events-uid',
349
+            'recurrenceid' => null,
350
+            'attendee' => 'mailto:[email protected]',
351
+            'organizer' => 'mailto:[email protected]',
352
+            'sequence' => null,
353
+            'token' => 'TOKEN123',
354
+            'expiration' => 420000,
355
+        ], 1337);
356
+
357
+        $expected = <<<EOF
358 358
 BEGIN:VCALENDAR
359 359
 VERSION:2.0
360 360
 PRODID:-//Nextcloud/Nextcloud CalDAV Server//EN
@@ -370,92 +370,92 @@  discard block
 block discarded – undo
370 370
 END:VCALENDAR
371 371
 
372 372
 EOF;
373
-		$expected = preg_replace('~\R~u', "\r\n", $expected);
374
-
375
-		$called = false;
376
-		$this->responseServer->expects($this->once())
377
-			->method('handleITipMessage')
378
-			->willReturnCallback(function (Message $iTipMessage) use (&$called, $isExternalAttendee, $expected): void {
379
-				$called = true;
380
-				$this->assertEquals('this-is-the-events-uid', $iTipMessage->uid);
381
-				$this->assertEquals('VEVENT', $iTipMessage->component);
382
-				$this->assertEquals('REPLY', $iTipMessage->method);
383
-				$this->assertEquals(null, $iTipMessage->sequence);
384
-				$this->assertEquals('mailto:[email protected]', $iTipMessage->sender);
385
-				if ($isExternalAttendee) {
386
-					$this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
387
-				} else {
388
-					$this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
389
-				}
390
-
391
-				$iTipMessage->scheduleStatus = '1.2;Message delivered locally';
392
-
393
-				$this->assertEquals($expected, $iTipMessage->message->serialize());
394
-			});
395
-		$this->responseServer->expects($this->once())
396
-			->method('isExternalAttendee')
397
-			->willReturn($isExternalAttendee);
398
-
399
-
400
-		$response = $this->controller->processMoreOptionsResult('TOKEN123');
401
-		$this->assertInstanceOf(TemplateResponse::class, $response);
402
-		$this->assertEquals('schedule-response-success', $response->getTemplateName());
403
-		$this->assertEquals([], $response->getParams());
404
-		$this->assertTrue($called);
405
-	}
406
-
407
-	private function buildQueryExpects(string $token, ?array $return, int $time): void {
408
-		$queryBuilder = $this->createMock(IQueryBuilder::class);
409
-		$stmt = $this->createMock(IResult::class);
410
-		$expr = $this->createMock(IExpressionBuilder::class);
411
-
412
-		$this->dbConnection->expects($this->once())
413
-			->method('getQueryBuilder')
414
-			->with()
415
-			->willReturn($queryBuilder);
416
-		$queryBuilder->method('expr')
417
-			->willReturn($expr);
418
-		$queryBuilder->method('createNamedParameter')
419
-			->willReturnMap([
420
-				[$token, \PDO::PARAM_STR, null, 'namedParameterToken']
421
-			]);
422
-
423
-		$stmt->expects($this->once())
424
-			->method('fetch')
425
-			->with(\PDO::FETCH_ASSOC)
426
-			->willReturn($return);
427
-		$stmt->expects($this->once())
428
-			->method('closeCursor');
429
-
430
-		$function = 'functionToken';
431
-		$expr->expects($this->once())
432
-			->method('eq')
433
-			->with('token', 'namedParameterToken')
434
-			->willReturn((string)$function);
435
-
436
-		$this->dbConnection->expects($this->once())
437
-			->method('getQueryBuilder')
438
-			->with()
439
-			->willReturn($queryBuilder);
440
-
441
-		$queryBuilder->expects($this->once())
442
-			->method('select')
443
-			->with('*')
444
-			->willReturn($queryBuilder);
445
-		$queryBuilder->expects($this->once())
446
-			->method('from')
447
-			->with('calendar_invitations')
448
-			->willReturn($queryBuilder);
449
-		$queryBuilder->expects($this->once())
450
-			->method('where')
451
-			->with($function)
452
-			->willReturn($queryBuilder);
453
-		$queryBuilder->expects($this->once())
454
-			->method('executeQuery')
455
-			->with()
456
-			->willReturn($stmt);
457
-
458
-		$this->timeFactory->method('getTime')
459
-			->willReturn($time);
460
-	}
373
+        $expected = preg_replace('~\R~u', "\r\n", $expected);
374
+
375
+        $called = false;
376
+        $this->responseServer->expects($this->once())
377
+            ->method('handleITipMessage')
378
+            ->willReturnCallback(function (Message $iTipMessage) use (&$called, $isExternalAttendee, $expected): void {
379
+                $called = true;
380
+                $this->assertEquals('this-is-the-events-uid', $iTipMessage->uid);
381
+                $this->assertEquals('VEVENT', $iTipMessage->component);
382
+                $this->assertEquals('REPLY', $iTipMessage->method);
383
+                $this->assertEquals(null, $iTipMessage->sequence);
384
+                $this->assertEquals('mailto:[email protected]', $iTipMessage->sender);
385
+                if ($isExternalAttendee) {
386
+                    $this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
387
+                } else {
388
+                    $this->assertEquals('mailto:[email protected]', $iTipMessage->recipient);
389
+                }
390
+
391
+                $iTipMessage->scheduleStatus = '1.2;Message delivered locally';
392
+
393
+                $this->assertEquals($expected, $iTipMessage->message->serialize());
394
+            });
395
+        $this->responseServer->expects($this->once())
396
+            ->method('isExternalAttendee')
397
+            ->willReturn($isExternalAttendee);
398
+
399
+
400
+        $response = $this->controller->processMoreOptionsResult('TOKEN123');
401
+        $this->assertInstanceOf(TemplateResponse::class, $response);
402
+        $this->assertEquals('schedule-response-success', $response->getTemplateName());
403
+        $this->assertEquals([], $response->getParams());
404
+        $this->assertTrue($called);
405
+    }
406
+
407
+    private function buildQueryExpects(string $token, ?array $return, int $time): void {
408
+        $queryBuilder = $this->createMock(IQueryBuilder::class);
409
+        $stmt = $this->createMock(IResult::class);
410
+        $expr = $this->createMock(IExpressionBuilder::class);
411
+
412
+        $this->dbConnection->expects($this->once())
413
+            ->method('getQueryBuilder')
414
+            ->with()
415
+            ->willReturn($queryBuilder);
416
+        $queryBuilder->method('expr')
417
+            ->willReturn($expr);
418
+        $queryBuilder->method('createNamedParameter')
419
+            ->willReturnMap([
420
+                [$token, \PDO::PARAM_STR, null, 'namedParameterToken']
421
+            ]);
422
+
423
+        $stmt->expects($this->once())
424
+            ->method('fetch')
425
+            ->with(\PDO::FETCH_ASSOC)
426
+            ->willReturn($return);
427
+        $stmt->expects($this->once())
428
+            ->method('closeCursor');
429
+
430
+        $function = 'functionToken';
431
+        $expr->expects($this->once())
432
+            ->method('eq')
433
+            ->with('token', 'namedParameterToken')
434
+            ->willReturn((string)$function);
435
+
436
+        $this->dbConnection->expects($this->once())
437
+            ->method('getQueryBuilder')
438
+            ->with()
439
+            ->willReturn($queryBuilder);
440
+
441
+        $queryBuilder->expects($this->once())
442
+            ->method('select')
443
+            ->with('*')
444
+            ->willReturn($queryBuilder);
445
+        $queryBuilder->expects($this->once())
446
+            ->method('from')
447
+            ->with('calendar_invitations')
448
+            ->willReturn($queryBuilder);
449
+        $queryBuilder->expects($this->once())
450
+            ->method('where')
451
+            ->with($function)
452
+            ->willReturn($queryBuilder);
453
+        $queryBuilder->expects($this->once())
454
+            ->method('executeQuery')
455
+            ->with()
456
+            ->willReturn($stmt);
457
+
458
+        $this->timeFactory->method('getTime')
459
+            ->willReturn($time);
460
+    }
461 461
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Settings/CalDAVSettingsTest.php 2 patches
Indentation   +60 added lines, -60 removed lines patch added patch discarded remove patch
@@ -17,72 +17,72 @@
 block discarded – undo
17 17
 use Test\TestCase;
18 18
 
19 19
 class CalDAVSettingsTest extends TestCase {
20
-	private IConfig&MockObject $config;
21
-	private IInitialState&MockObject $initialState;
22
-	private IURLGenerator&MockObject $urlGenerator;
23
-	private IAppManager&MockObject $appManager;
24
-	private CalDAVSettings $settings;
20
+    private IConfig&MockObject $config;
21
+    private IInitialState&MockObject $initialState;
22
+    private IURLGenerator&MockObject $urlGenerator;
23
+    private IAppManager&MockObject $appManager;
24
+    private CalDAVSettings $settings;
25 25
 
26
-	protected function setUp(): void {
27
-		parent::setUp();
26
+    protected function setUp(): void {
27
+        parent::setUp();
28 28
 
29
-		$this->config = $this->createMock(IConfig::class);
30
-		$this->initialState = $this->createMock(IInitialState::class);
31
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
32
-		$this->appManager = $this->createMock(IAppManager::class);
33
-		$this->settings = new CalDAVSettings($this->config, $this->initialState, $this->urlGenerator, $this->appManager);
34
-	}
29
+        $this->config = $this->createMock(IConfig::class);
30
+        $this->initialState = $this->createMock(IInitialState::class);
31
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
32
+        $this->appManager = $this->createMock(IAppManager::class);
33
+        $this->settings = new CalDAVSettings($this->config, $this->initialState, $this->urlGenerator, $this->appManager);
34
+    }
35 35
 
36
-	public function testGetForm(): void {
37
-		$this->config->method('getAppValue')
38
-			->willReturnMap([
39
-				['dav', 'sendInvitations', 'yes', 'yes'],
40
-				['dav', 'generateBirthdayCalendar', 'yes', 'no'],
41
-				['dav', 'sendEventReminders', 'yes', 'yes'],
42
-				['dav', 'sendEventRemindersToSharedUsers', 'yes', 'yes'],
43
-				['dav', 'sendEventRemindersPush', 'yes', 'yes'],
44
-			]);
45
-		$this->urlGenerator
46
-			->expects($this->once())
47
-			->method('linkToDocs')
48
-			->with('user-sync-calendars')
49
-			->willReturn('Some docs URL');
36
+    public function testGetForm(): void {
37
+        $this->config->method('getAppValue')
38
+            ->willReturnMap([
39
+                ['dav', 'sendInvitations', 'yes', 'yes'],
40
+                ['dav', 'generateBirthdayCalendar', 'yes', 'no'],
41
+                ['dav', 'sendEventReminders', 'yes', 'yes'],
42
+                ['dav', 'sendEventRemindersToSharedUsers', 'yes', 'yes'],
43
+                ['dav', 'sendEventRemindersPush', 'yes', 'yes'],
44
+            ]);
45
+        $this->urlGenerator
46
+            ->expects($this->once())
47
+            ->method('linkToDocs')
48
+            ->with('user-sync-calendars')
49
+            ->willReturn('Some docs URL');
50 50
 
51
-		$calls = [
52
-			['userSyncCalendarsDocUrl', 'Some docs URL'],
53
-			['sendInvitations', true],
54
-			['generateBirthdayCalendar', false],
55
-			['sendEventReminders', true],
56
-			['sendEventRemindersToSharedUsers', true],
57
-			['sendEventRemindersPush', true],
58
-		];
59
-		$this->initialState->method('provideInitialState')
60
-			->willReturnCallback(function () use (&$calls): void {
61
-				$expected = array_shift($calls);
62
-				$this->assertEquals($expected, func_get_args());
63
-			});
64
-		$result = $this->settings->getForm();
51
+        $calls = [
52
+            ['userSyncCalendarsDocUrl', 'Some docs URL'],
53
+            ['sendInvitations', true],
54
+            ['generateBirthdayCalendar', false],
55
+            ['sendEventReminders', true],
56
+            ['sendEventRemindersToSharedUsers', true],
57
+            ['sendEventRemindersPush', true],
58
+        ];
59
+        $this->initialState->method('provideInitialState')
60
+            ->willReturnCallback(function () use (&$calls): void {
61
+                $expected = array_shift($calls);
62
+                $this->assertEquals($expected, func_get_args());
63
+            });
64
+        $result = $this->settings->getForm();
65 65
 
66
-		$this->assertInstanceOf(TemplateResponse::class, $result);
67
-	}
66
+        $this->assertInstanceOf(TemplateResponse::class, $result);
67
+    }
68 68
 
69
-	public function testGetSection(): void {
70
-		$this->appManager->expects(self::once())
71
-			->method('isBackendRequired')
72
-			->with(IAppManager::BACKEND_CALDAV)
73
-			->willReturn(true);
74
-		$this->assertEquals('groupware', $this->settings->getSection());
75
-	}
69
+    public function testGetSection(): void {
70
+        $this->appManager->expects(self::once())
71
+            ->method('isBackendRequired')
72
+            ->with(IAppManager::BACKEND_CALDAV)
73
+            ->willReturn(true);
74
+        $this->assertEquals('groupware', $this->settings->getSection());
75
+    }
76 76
 
77
-	public function testGetSectionWithoutCaldavBackend(): void {
78
-		$this->appManager->expects(self::once())
79
-			->method('isBackendRequired')
80
-			->with(IAppManager::BACKEND_CALDAV)
81
-			->willReturn(false);
82
-		$this->assertEquals(null, $this->settings->getSection());
83
-	}
77
+    public function testGetSectionWithoutCaldavBackend(): void {
78
+        $this->appManager->expects(self::once())
79
+            ->method('isBackendRequired')
80
+            ->with(IAppManager::BACKEND_CALDAV)
81
+            ->willReturn(false);
82
+        $this->assertEquals(null, $this->settings->getSection());
83
+    }
84 84
 
85
-	public function testGetPriority(): void {
86
-		$this->assertEquals(10, $this->settings->getPriority());
87
-	}
85
+    public function testGetPriority(): void {
86
+        $this->assertEquals(10, $this->settings->getPriority());
87
+    }
88 88
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -57,7 +57,7 @@
 block discarded – undo
57 57
 			['sendEventRemindersPush', true],
58 58
 		];
59 59
 		$this->initialState->method('provideInitialState')
60
-			->willReturnCallback(function () use (&$calls): void {
60
+			->willReturnCallback(function() use (&$calls): void {
61 61
 				$expected = array_shift($calls);
62 62
 				$this->assertEquals($expected, func_get_args());
63 63
 			});
Please login to merge, or discard this patch.
apps/dav/tests/unit/Comments/CommentsNodeTest.php 1 patch
Indentation   +413 added lines, -413 removed lines patch added patch discarded remove patch
@@ -20,480 +20,480 @@
 block discarded – undo
20 20
 use Sabre\DAV\PropPatch;
21 21
 
22 22
 class CommentsNodeTest extends \Test\TestCase {
23
-	protected ICommentsManager&MockObject $commentsManager;
24
-	protected IComment&MockObject $comment;
25
-	protected IUserManager&MockObject $userManager;
26
-	protected LoggerInterface&MockObject $logger;
27
-	protected IUserSession&MockObject $userSession;
28
-	protected CommentNode $node;
23
+    protected ICommentsManager&MockObject $commentsManager;
24
+    protected IComment&MockObject $comment;
25
+    protected IUserManager&MockObject $userManager;
26
+    protected LoggerInterface&MockObject $logger;
27
+    protected IUserSession&MockObject $userSession;
28
+    protected CommentNode $node;
29 29
 
30
-	protected function setUp(): void {
31
-		parent::setUp();
30
+    protected function setUp(): void {
31
+        parent::setUp();
32 32
 
33
-		$this->commentsManager = $this->createMock(ICommentsManager::class);
34
-		$this->comment = $this->createMock(IComment::class);
35
-		$this->userManager = $this->createMock(IUserManager::class);
36
-		$this->userSession = $this->createMock(IUserSession::class);
37
-		$this->logger = $this->createMock(LoggerInterface::class);
33
+        $this->commentsManager = $this->createMock(ICommentsManager::class);
34
+        $this->comment = $this->createMock(IComment::class);
35
+        $this->userManager = $this->createMock(IUserManager::class);
36
+        $this->userSession = $this->createMock(IUserSession::class);
37
+        $this->logger = $this->createMock(LoggerInterface::class);
38 38
 
39
-		$this->node = new CommentNode(
40
-			$this->commentsManager,
41
-			$this->comment,
42
-			$this->userManager,
43
-			$this->userSession,
44
-			$this->logger
45
-		);
46
-	}
39
+        $this->node = new CommentNode(
40
+            $this->commentsManager,
41
+            $this->comment,
42
+            $this->userManager,
43
+            $this->userSession,
44
+            $this->logger
45
+        );
46
+    }
47 47
 
48
-	public function testDelete(): void {
49
-		$user = $this->createMock(IUser::class);
50
-		$user->expects($this->once())
51
-			->method('getUID')
52
-			->willReturn('alice');
48
+    public function testDelete(): void {
49
+        $user = $this->createMock(IUser::class);
50
+        $user->expects($this->once())
51
+            ->method('getUID')
52
+            ->willReturn('alice');
53 53
 
54
-		$this->userSession->expects($this->once())
55
-			->method('getUser')
56
-			->willReturn($user);
54
+        $this->userSession->expects($this->once())
55
+            ->method('getUser')
56
+            ->willReturn($user);
57 57
 
58
-		$this->comment->expects($this->once())
59
-			->method('getId')
60
-			->willReturn('19');
58
+        $this->comment->expects($this->once())
59
+            ->method('getId')
60
+            ->willReturn('19');
61 61
 
62
-		$this->comment->expects($this->any())
63
-			->method('getActorType')
64
-			->willReturn('users');
62
+        $this->comment->expects($this->any())
63
+            ->method('getActorType')
64
+            ->willReturn('users');
65 65
 
66
-		$this->comment->expects($this->any())
67
-			->method('getActorId')
68
-			->willReturn('alice');
66
+        $this->comment->expects($this->any())
67
+            ->method('getActorId')
68
+            ->willReturn('alice');
69 69
 
70
-		$this->commentsManager->expects($this->once())
71
-			->method('delete')
72
-			->with('19');
70
+        $this->commentsManager->expects($this->once())
71
+            ->method('delete')
72
+            ->with('19');
73 73
 
74
-		$this->node->delete();
75
-	}
74
+        $this->node->delete();
75
+    }
76 76
 
77 77
 
78
-	public function testDeleteForbidden(): void {
79
-		$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
78
+    public function testDeleteForbidden(): void {
79
+        $this->expectException(\Sabre\DAV\Exception\Forbidden::class);
80 80
 
81
-		$user = $this->createMock(IUser::class);
82
-		$user->expects($this->once())
83
-			->method('getUID')
84
-			->willReturn('mallory');
81
+        $user = $this->createMock(IUser::class);
82
+        $user->expects($this->once())
83
+            ->method('getUID')
84
+            ->willReturn('mallory');
85 85
 
86
-		$this->userSession->expects($this->once())
87
-			->method('getUser')
88
-			->willReturn($user);
86
+        $this->userSession->expects($this->once())
87
+            ->method('getUser')
88
+            ->willReturn($user);
89 89
 
90
-		$this->comment->expects($this->never())
91
-			->method('getId');
90
+        $this->comment->expects($this->never())
91
+            ->method('getId');
92 92
 
93
-		$this->comment->expects($this->any())
94
-			->method('getActorType')
95
-			->willReturn('users');
93
+        $this->comment->expects($this->any())
94
+            ->method('getActorType')
95
+            ->willReturn('users');
96 96
 
97
-		$this->comment->expects($this->any())
98
-			->method('getActorId')
99
-			->willReturn('alice');
97
+        $this->comment->expects($this->any())
98
+            ->method('getActorId')
99
+            ->willReturn('alice');
100 100
 
101
-		$this->commentsManager->expects($this->never())
102
-			->method('delete');
101
+        $this->commentsManager->expects($this->never())
102
+            ->method('delete');
103 103
 
104
-		$this->node->delete();
105
-	}
104
+        $this->node->delete();
105
+    }
106 106
 
107
-	public function testGetName(): void {
108
-		$id = '19';
109
-		$this->comment->expects($this->once())
110
-			->method('getId')
111
-			->willReturn($id);
107
+    public function testGetName(): void {
108
+        $id = '19';
109
+        $this->comment->expects($this->once())
110
+            ->method('getId')
111
+            ->willReturn($id);
112 112
 
113
-		$this->assertSame($this->node->getName(), $id);
114
-	}
113
+        $this->assertSame($this->node->getName(), $id);
114
+    }
115 115
 
116 116
 
117
-	public function testSetName(): void {
118
-		$this->expectException(\Sabre\DAV\Exception\MethodNotAllowed::class);
117
+    public function testSetName(): void {
118
+        $this->expectException(\Sabre\DAV\Exception\MethodNotAllowed::class);
119 119
 
120
-		$this->node->setName('666');
121
-	}
120
+        $this->node->setName('666');
121
+    }
122 122
 
123
-	public function testGetLastModified(): void {
124
-		$this->assertSame($this->node->getLastModified(), null);
125
-	}
123
+    public function testGetLastModified(): void {
124
+        $this->assertSame($this->node->getLastModified(), null);
125
+    }
126 126
 
127
-	public function testUpdateComment(): void {
128
-		$msg = 'Hello Earth';
127
+    public function testUpdateComment(): void {
128
+        $msg = 'Hello Earth';
129 129
 
130
-		$user = $this->createMock(IUser::class);
131
-		$user->expects($this->once())
132
-			->method('getUID')
133
-			->willReturn('alice');
130
+        $user = $this->createMock(IUser::class);
131
+        $user->expects($this->once())
132
+            ->method('getUID')
133
+            ->willReturn('alice');
134 134
 
135
-		$this->userSession->expects($this->once())
136
-			->method('getUser')
137
-			->willReturn($user);
135
+        $this->userSession->expects($this->once())
136
+            ->method('getUser')
137
+            ->willReturn($user);
138 138
 
139
-		$this->comment->expects($this->once())
140
-			->method('setMessage')
141
-			->with($msg);
139
+        $this->comment->expects($this->once())
140
+            ->method('setMessage')
141
+            ->with($msg);
142 142
 
143
-		$this->comment->expects($this->any())
144
-			->method('getActorType')
145
-			->willReturn('users');
143
+        $this->comment->expects($this->any())
144
+            ->method('getActorType')
145
+            ->willReturn('users');
146 146
 
147
-		$this->comment->expects($this->any())
148
-			->method('getActorId')
149
-			->willReturn('alice');
147
+        $this->comment->expects($this->any())
148
+            ->method('getActorId')
149
+            ->willReturn('alice');
150 150
 
151
-		$this->commentsManager->expects($this->once())
152
-			->method('save')
153
-			->with($this->comment);
151
+        $this->commentsManager->expects($this->once())
152
+            ->method('save')
153
+            ->with($this->comment);
154 154
 
155
-		$this->assertTrue($this->node->updateComment($msg));
156
-	}
155
+        $this->assertTrue($this->node->updateComment($msg));
156
+    }
157 157
 
158 158
 
159
-	public function testUpdateCommentLogException(): void {
160
-		$this->expectException(\Exception::class);
161
-		$this->expectExceptionMessage('buh!');
159
+    public function testUpdateCommentLogException(): void {
160
+        $this->expectException(\Exception::class);
161
+        $this->expectExceptionMessage('buh!');
162 162
 
163
-		$msg = null;
163
+        $msg = null;
164 164
 
165
-		$user = $this->createMock(IUser::class);
166
-		$user->expects($this->once())
167
-			->method('getUID')
168
-			->willReturn('alice');
165
+        $user = $this->createMock(IUser::class);
166
+        $user->expects($this->once())
167
+            ->method('getUID')
168
+            ->willReturn('alice');
169 169
 
170
-		$this->userSession->expects($this->once())
171
-			->method('getUser')
172
-			->willReturn($user);
170
+        $this->userSession->expects($this->once())
171
+            ->method('getUser')
172
+            ->willReturn($user);
173 173
 
174
-		$this->comment->expects($this->once())
175
-			->method('setMessage')
176
-			->with($msg)
177
-			->willThrowException(new \Exception('buh!'));
174
+        $this->comment->expects($this->once())
175
+            ->method('setMessage')
176
+            ->with($msg)
177
+            ->willThrowException(new \Exception('buh!'));
178 178
 
179
-		$this->comment->expects($this->any())
180
-			->method('getActorType')
181
-			->willReturn('users');
179
+        $this->comment->expects($this->any())
180
+            ->method('getActorType')
181
+            ->willReturn('users');
182 182
 
183
-		$this->comment->expects($this->any())
184
-			->method('getActorId')
185
-			->willReturn('alice');
183
+        $this->comment->expects($this->any())
184
+            ->method('getActorId')
185
+            ->willReturn('alice');
186 186
 
187
-		$this->commentsManager->expects($this->never())
188
-			->method('save');
187
+        $this->commentsManager->expects($this->never())
188
+            ->method('save');
189 189
 
190
-		$this->logger->expects($this->once())
191
-			->method('error');
190
+        $this->logger->expects($this->once())
191
+            ->method('error');
192 192
 
193
-		$this->node->updateComment($msg);
194
-	}
193
+        $this->node->updateComment($msg);
194
+    }
195 195
 
196 196
 
197
-	public function testUpdateCommentMessageTooLongException(): void {
198
-		$this->expectException(\Sabre\DAV\Exception\BadRequest::class);
199
-		$this->expectExceptionMessage('Message exceeds allowed character limit of');
197
+    public function testUpdateCommentMessageTooLongException(): void {
198
+        $this->expectException(\Sabre\DAV\Exception\BadRequest::class);
199
+        $this->expectExceptionMessage('Message exceeds allowed character limit of');
200 200
 
201
-		$user = $this->createMock(IUser::class);
202
-		$user->expects($this->once())
203
-			->method('getUID')
204
-			->willReturn('alice');
201
+        $user = $this->createMock(IUser::class);
202
+        $user->expects($this->once())
203
+            ->method('getUID')
204
+            ->willReturn('alice');
205 205
 
206
-		$this->userSession->expects($this->once())
207
-			->method('getUser')
208
-			->willReturn($user);
206
+        $this->userSession->expects($this->once())
207
+            ->method('getUser')
208
+            ->willReturn($user);
209 209
 
210
-		$this->comment->expects($this->once())
211
-			->method('setMessage')
212
-			->willThrowException(new MessageTooLongException());
210
+        $this->comment->expects($this->once())
211
+            ->method('setMessage')
212
+            ->willThrowException(new MessageTooLongException());
213 213
 
214
-		$this->comment->expects($this->any())
215
-			->method('getActorType')
216
-			->willReturn('users');
214
+        $this->comment->expects($this->any())
215
+            ->method('getActorType')
216
+            ->willReturn('users');
217 217
 
218
-		$this->comment->expects($this->any())
219
-			->method('getActorId')
220
-			->willReturn('alice');
218
+        $this->comment->expects($this->any())
219
+            ->method('getActorId')
220
+            ->willReturn('alice');
221 221
 
222
-		$this->commentsManager->expects($this->never())
223
-			->method('save');
222
+        $this->commentsManager->expects($this->never())
223
+            ->method('save');
224 224
 
225
-		$this->logger->expects($this->once())
226
-			->method('error');
225
+        $this->logger->expects($this->once())
226
+            ->method('error');
227 227
 
228
-		// imagine 'foo' has >1k characters. comment is mocked anyway.
229
-		$this->node->updateComment('foo');
230
-	}
228
+        // imagine 'foo' has >1k characters. comment is mocked anyway.
229
+        $this->node->updateComment('foo');
230
+    }
231 231
 
232 232
 
233
-	public function testUpdateForbiddenByUser(): void {
234
-		$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
233
+    public function testUpdateForbiddenByUser(): void {
234
+        $this->expectException(\Sabre\DAV\Exception\Forbidden::class);
235 235
 
236
-		$msg = 'HaXX0r';
236
+        $msg = 'HaXX0r';
237 237
 
238
-		$user = $this->createMock(IUser::class);
239
-		$user->expects($this->once())
240
-			->method('getUID')
241
-			->willReturn('mallory');
238
+        $user = $this->createMock(IUser::class);
239
+        $user->expects($this->once())
240
+            ->method('getUID')
241
+            ->willReturn('mallory');
242 242
 
243
-		$this->userSession->expects($this->once())
244
-			->method('getUser')
245
-			->willReturn($user);
243
+        $this->userSession->expects($this->once())
244
+            ->method('getUser')
245
+            ->willReturn($user);
246 246
 
247
-		$this->comment->expects($this->never())
248
-			->method('setMessage');
247
+        $this->comment->expects($this->never())
248
+            ->method('setMessage');
249 249
 
250
-		$this->comment->expects($this->any())
251
-			->method('getActorType')
252
-			->willReturn('users');
250
+        $this->comment->expects($this->any())
251
+            ->method('getActorType')
252
+            ->willReturn('users');
253 253
 
254
-		$this->comment->expects($this->any())
255
-			->method('getActorId')
256
-			->willReturn('alice');
254
+        $this->comment->expects($this->any())
255
+            ->method('getActorId')
256
+            ->willReturn('alice');
257 257
 
258
-		$this->commentsManager->expects($this->never())
259
-			->method('save');
260
-
261
-		$this->node->updateComment($msg);
262
-	}
263
-
264
-
265
-	public function testUpdateForbiddenByType(): void {
266
-		$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
267
-
268
-		$msg = 'HaXX0r';
269
-
270
-		$user = $this->createMock(IUser::class);
271
-		$user->expects($this->never())
272
-			->method('getUID');
273
-
274
-		$this->userSession->expects($this->once())
275
-			->method('getUser')
276
-			->willReturn($user);
277
-
278
-		$this->comment->expects($this->never())
279
-			->method('setMessage');
280
-
281
-		$this->comment->expects($this->any())
282
-			->method('getActorType')
283
-			->willReturn('bots');
284
-
285
-		$this->commentsManager->expects($this->never())
286
-			->method('save');
287
-
288
-		$this->node->updateComment($msg);
289
-	}
290
-
291
-
292
-	public function testUpdateForbiddenByNotLoggedIn(): void {
293
-		$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
294
-
295
-		$msg = 'HaXX0r';
296
-
297
-		$this->userSession->expects($this->once())
298
-			->method('getUser')
299
-			->willReturn(null);
300
-
301
-		$this->comment->expects($this->never())
302
-			->method('setMessage');
303
-
304
-		$this->comment->expects($this->any())
305
-			->method('getActorType')
306
-			->willReturn('users');
307
-
308
-		$this->commentsManager->expects($this->never())
309
-			->method('save');
310
-
311
-		$this->node->updateComment($msg);
312
-	}
313
-
314
-	public function testPropPatch(): void {
315
-		$propPatch = $this->createMock(PropPatch::class);
316
-		$propPatch->expects($this->once())
317
-			->method('handle')
318
-			->with('{http://owncloud.org/ns}message');
319
-
320
-		$this->node->propPatch($propPatch);
321
-	}
322
-
323
-	public function testGetProperties(): void {
324
-		$ns = '{http://owncloud.org/ns}';
325
-		$expected = [
326
-			$ns . 'id' => '123',
327
-			$ns . 'parentId' => '12',
328
-			$ns . 'topmostParentId' => '2',
329
-			$ns . 'childrenCount' => 3,
330
-			$ns . 'message' => 'such a nice file you have…',
331
-			$ns . 'mentions' => [
332
-				[ $ns . 'mention' => [
333
-					$ns . 'mentionType' => 'user',
334
-					$ns . 'mentionId' => 'alice',
335
-					$ns . 'mentionDisplayName' => 'Alice Al-Isson',
336
-				] ],
337
-				[ $ns . 'mention' => [
338
-					$ns . 'mentionType' => 'user',
339
-					$ns . 'mentionId' => 'bob',
340
-					$ns . 'mentionDisplayName' => 'Unknown user',
341
-				] ],
342
-			],
343
-			$ns . 'verb' => 'comment',
344
-			$ns . 'actorType' => 'users',
345
-			$ns . 'actorId' => 'alice',
346
-			$ns . 'actorDisplayName' => 'Alice of Wonderland',
347
-			$ns . 'creationDateTime' => new \DateTime('2016-01-10 18:48:00'),
348
-			$ns . 'latestChildDateTime' => new \DateTime('2016-01-12 18:48:00'),
349
-			$ns . 'objectType' => 'files',
350
-			$ns . 'objectId' => '1848',
351
-			$ns . 'referenceId' => 'ref',
352
-			$ns . 'isUnread' => null,
353
-			$ns . 'reactions' => [],
354
-			$ns . 'metaData' => [
355
-				'last_edited_at' => 1702553770,
356
-				'last_edited_by_id' => 'charly',
357
-				'last_edited_by_type' => 'user',
358
-			],
359
-			$ns . 'expireDate' => new \DateTime('2016-01-12 19:00:00'),
360
-		];
361
-
362
-		$this->commentsManager->expects($this->exactly(2))
363
-			->method('resolveDisplayName')
364
-			->willReturnMap([
365
-				['user', 'alice', 'Alice Al-Isson'],
366
-				['user', 'bob', 'Unknown user']
367
-			]);
368
-
369
-		$this->comment->expects($this->once())
370
-			->method('getId')
371
-			->willReturn($expected[$ns . 'id']);
372
-
373
-		$this->comment->expects($this->once())
374
-			->method('getParentId')
375
-			->willReturn($expected[$ns . 'parentId']);
376
-
377
-		$this->comment->expects($this->once())
378
-			->method('getTopmostParentId')
379
-			->willReturn($expected[$ns . 'topmostParentId']);
380
-
381
-		$this->comment->expects($this->once())
382
-			->method('getChildrenCount')
383
-			->willReturn($expected[$ns . 'childrenCount']);
384
-
385
-		$this->comment->expects($this->once())
386
-			->method('getMessage')
387
-			->willReturn($expected[$ns . 'message']);
388
-
389
-		$this->comment->expects($this->once())
390
-			->method('getMentions')
391
-			->willReturn([
392
-				['type' => 'user', 'id' => 'alice'],
393
-				['type' => 'user', 'id' => 'bob'],
394
-			]);
395
-
396
-		$this->comment->expects($this->once())
397
-			->method('getVerb')
398
-			->willReturn($expected[$ns . 'verb']);
399
-
400
-		$this->comment->expects($this->exactly(2))
401
-			->method('getActorType')
402
-			->willReturn($expected[$ns . 'actorType']);
403
-
404
-		$this->comment->expects($this->exactly(2))
405
-			->method('getActorId')
406
-			->willReturn($expected[$ns . 'actorId']);
407
-
408
-		$this->comment->expects($this->once())
409
-			->method('getCreationDateTime')
410
-			->willReturn($expected[$ns . 'creationDateTime']);
411
-
412
-		$this->comment->expects($this->once())
413
-			->method('getLatestChildDateTime')
414
-			->willReturn($expected[$ns . 'latestChildDateTime']);
415
-
416
-		$this->comment->expects($this->once())
417
-			->method('getObjectType')
418
-			->willReturn($expected[$ns . 'objectType']);
419
-
420
-		$this->comment->expects($this->once())
421
-			->method('getObjectId')
422
-			->willReturn($expected[$ns . 'objectId']);
423
-
424
-		$this->comment->expects($this->once())
425
-			->method('getReferenceId')
426
-			->willReturn($expected[$ns . 'referenceId']);
427
-
428
-		$this->comment->expects($this->once())
429
-			->method('getMetaData')
430
-			->willReturn($expected[$ns . 'metaData']);
431
-
432
-		$this->comment->expects($this->once())
433
-			->method('getExpireDate')
434
-			->willReturn($expected[$ns . 'expireDate']);
435
-
436
-		$user = $this->getMockBuilder(IUser::class)
437
-			->disableOriginalConstructor()
438
-			->getMock();
439
-		$user->expects($this->once())
440
-			->method('getDisplayName')
441
-			->willReturn($expected[$ns . 'actorDisplayName']);
442
-
443
-		$this->userManager->expects($this->once())
444
-			->method('get')
445
-			->with('alice')
446
-			->willReturn($user);
447
-
448
-		$properties = $this->node->getProperties(null);
449
-
450
-		foreach ($properties as $name => $value) {
451
-			$this->assertArrayHasKey($name, $expected, 'Key not found in the list of $expected');
452
-			$this->assertSame($expected[$name], $value);
453
-			unset($expected[$name]);
454
-		}
455
-		$this->assertTrue(empty($expected));
456
-	}
457
-
458
-	public static function readCommentProvider(): array {
459
-		$creationDT = new \DateTime('2016-01-19 18:48:00');
460
-		$diff = new \DateInterval('PT2H');
461
-		$readDT1 = clone $creationDT;
462
-		$readDT1->sub($diff);
463
-		$readDT2 = clone $creationDT;
464
-		$readDT2->add($diff);
465
-		return [
466
-			[$creationDT, $readDT1, 'true'],
467
-			[$creationDT, $readDT2, 'false'],
468
-			[$creationDT, null, 'true'],
469
-		];
470
-	}
471
-
472
-	#[\PHPUnit\Framework\Attributes\DataProvider('readCommentProvider')]
473
-	public function testGetPropertiesUnreadProperty(\DateTime $creationDT, ?\DateTime $readDT, string $expected): void {
474
-		$this->comment->expects($this->any())
475
-			->method('getCreationDateTime')
476
-			->willReturn($creationDT);
477
-
478
-		$this->comment->expects($this->any())
479
-			->method('getMentions')
480
-			->willReturn([]);
481
-
482
-		$this->commentsManager->expects($this->once())
483
-			->method('getReadMark')
484
-			->willReturn($readDT);
485
-
486
-		$this->userSession->expects($this->once())
487
-			->method('getUser')
488
-			->willReturn(
489
-				$this->getMockBuilder(IUser::class)
490
-					->disableOriginalConstructor()
491
-					->getMock()
492
-			);
493
-
494
-		$properties = $this->node->getProperties(null);
495
-
496
-		$this->assertTrue(array_key_exists(CommentNode::PROPERTY_NAME_UNREAD, $properties));
497
-		$this->assertSame($properties[CommentNode::PROPERTY_NAME_UNREAD], $expected);
498
-	}
258
+        $this->commentsManager->expects($this->never())
259
+            ->method('save');
260
+
261
+        $this->node->updateComment($msg);
262
+    }
263
+
264
+
265
+    public function testUpdateForbiddenByType(): void {
266
+        $this->expectException(\Sabre\DAV\Exception\Forbidden::class);
267
+
268
+        $msg = 'HaXX0r';
269
+
270
+        $user = $this->createMock(IUser::class);
271
+        $user->expects($this->never())
272
+            ->method('getUID');
273
+
274
+        $this->userSession->expects($this->once())
275
+            ->method('getUser')
276
+            ->willReturn($user);
277
+
278
+        $this->comment->expects($this->never())
279
+            ->method('setMessage');
280
+
281
+        $this->comment->expects($this->any())
282
+            ->method('getActorType')
283
+            ->willReturn('bots');
284
+
285
+        $this->commentsManager->expects($this->never())
286
+            ->method('save');
287
+
288
+        $this->node->updateComment($msg);
289
+    }
290
+
291
+
292
+    public function testUpdateForbiddenByNotLoggedIn(): void {
293
+        $this->expectException(\Sabre\DAV\Exception\Forbidden::class);
294
+
295
+        $msg = 'HaXX0r';
296
+
297
+        $this->userSession->expects($this->once())
298
+            ->method('getUser')
299
+            ->willReturn(null);
300
+
301
+        $this->comment->expects($this->never())
302
+            ->method('setMessage');
303
+
304
+        $this->comment->expects($this->any())
305
+            ->method('getActorType')
306
+            ->willReturn('users');
307
+
308
+        $this->commentsManager->expects($this->never())
309
+            ->method('save');
310
+
311
+        $this->node->updateComment($msg);
312
+    }
313
+
314
+    public function testPropPatch(): void {
315
+        $propPatch = $this->createMock(PropPatch::class);
316
+        $propPatch->expects($this->once())
317
+            ->method('handle')
318
+            ->with('{http://owncloud.org/ns}message');
319
+
320
+        $this->node->propPatch($propPatch);
321
+    }
322
+
323
+    public function testGetProperties(): void {
324
+        $ns = '{http://owncloud.org/ns}';
325
+        $expected = [
326
+            $ns . 'id' => '123',
327
+            $ns . 'parentId' => '12',
328
+            $ns . 'topmostParentId' => '2',
329
+            $ns . 'childrenCount' => 3,
330
+            $ns . 'message' => 'such a nice file you have…',
331
+            $ns . 'mentions' => [
332
+                [ $ns . 'mention' => [
333
+                    $ns . 'mentionType' => 'user',
334
+                    $ns . 'mentionId' => 'alice',
335
+                    $ns . 'mentionDisplayName' => 'Alice Al-Isson',
336
+                ] ],
337
+                [ $ns . 'mention' => [
338
+                    $ns . 'mentionType' => 'user',
339
+                    $ns . 'mentionId' => 'bob',
340
+                    $ns . 'mentionDisplayName' => 'Unknown user',
341
+                ] ],
342
+            ],
343
+            $ns . 'verb' => 'comment',
344
+            $ns . 'actorType' => 'users',
345
+            $ns . 'actorId' => 'alice',
346
+            $ns . 'actorDisplayName' => 'Alice of Wonderland',
347
+            $ns . 'creationDateTime' => new \DateTime('2016-01-10 18:48:00'),
348
+            $ns . 'latestChildDateTime' => new \DateTime('2016-01-12 18:48:00'),
349
+            $ns . 'objectType' => 'files',
350
+            $ns . 'objectId' => '1848',
351
+            $ns . 'referenceId' => 'ref',
352
+            $ns . 'isUnread' => null,
353
+            $ns . 'reactions' => [],
354
+            $ns . 'metaData' => [
355
+                'last_edited_at' => 1702553770,
356
+                'last_edited_by_id' => 'charly',
357
+                'last_edited_by_type' => 'user',
358
+            ],
359
+            $ns . 'expireDate' => new \DateTime('2016-01-12 19:00:00'),
360
+        ];
361
+
362
+        $this->commentsManager->expects($this->exactly(2))
363
+            ->method('resolveDisplayName')
364
+            ->willReturnMap([
365
+                ['user', 'alice', 'Alice Al-Isson'],
366
+                ['user', 'bob', 'Unknown user']
367
+            ]);
368
+
369
+        $this->comment->expects($this->once())
370
+            ->method('getId')
371
+            ->willReturn($expected[$ns . 'id']);
372
+
373
+        $this->comment->expects($this->once())
374
+            ->method('getParentId')
375
+            ->willReturn($expected[$ns . 'parentId']);
376
+
377
+        $this->comment->expects($this->once())
378
+            ->method('getTopmostParentId')
379
+            ->willReturn($expected[$ns . 'topmostParentId']);
380
+
381
+        $this->comment->expects($this->once())
382
+            ->method('getChildrenCount')
383
+            ->willReturn($expected[$ns . 'childrenCount']);
384
+
385
+        $this->comment->expects($this->once())
386
+            ->method('getMessage')
387
+            ->willReturn($expected[$ns . 'message']);
388
+
389
+        $this->comment->expects($this->once())
390
+            ->method('getMentions')
391
+            ->willReturn([
392
+                ['type' => 'user', 'id' => 'alice'],
393
+                ['type' => 'user', 'id' => 'bob'],
394
+            ]);
395
+
396
+        $this->comment->expects($this->once())
397
+            ->method('getVerb')
398
+            ->willReturn($expected[$ns . 'verb']);
399
+
400
+        $this->comment->expects($this->exactly(2))
401
+            ->method('getActorType')
402
+            ->willReturn($expected[$ns . 'actorType']);
403
+
404
+        $this->comment->expects($this->exactly(2))
405
+            ->method('getActorId')
406
+            ->willReturn($expected[$ns . 'actorId']);
407
+
408
+        $this->comment->expects($this->once())
409
+            ->method('getCreationDateTime')
410
+            ->willReturn($expected[$ns . 'creationDateTime']);
411
+
412
+        $this->comment->expects($this->once())
413
+            ->method('getLatestChildDateTime')
414
+            ->willReturn($expected[$ns . 'latestChildDateTime']);
415
+
416
+        $this->comment->expects($this->once())
417
+            ->method('getObjectType')
418
+            ->willReturn($expected[$ns . 'objectType']);
419
+
420
+        $this->comment->expects($this->once())
421
+            ->method('getObjectId')
422
+            ->willReturn($expected[$ns . 'objectId']);
423
+
424
+        $this->comment->expects($this->once())
425
+            ->method('getReferenceId')
426
+            ->willReturn($expected[$ns . 'referenceId']);
427
+
428
+        $this->comment->expects($this->once())
429
+            ->method('getMetaData')
430
+            ->willReturn($expected[$ns . 'metaData']);
431
+
432
+        $this->comment->expects($this->once())
433
+            ->method('getExpireDate')
434
+            ->willReturn($expected[$ns . 'expireDate']);
435
+
436
+        $user = $this->getMockBuilder(IUser::class)
437
+            ->disableOriginalConstructor()
438
+            ->getMock();
439
+        $user->expects($this->once())
440
+            ->method('getDisplayName')
441
+            ->willReturn($expected[$ns . 'actorDisplayName']);
442
+
443
+        $this->userManager->expects($this->once())
444
+            ->method('get')
445
+            ->with('alice')
446
+            ->willReturn($user);
447
+
448
+        $properties = $this->node->getProperties(null);
449
+
450
+        foreach ($properties as $name => $value) {
451
+            $this->assertArrayHasKey($name, $expected, 'Key not found in the list of $expected');
452
+            $this->assertSame($expected[$name], $value);
453
+            unset($expected[$name]);
454
+        }
455
+        $this->assertTrue(empty($expected));
456
+    }
457
+
458
+    public static function readCommentProvider(): array {
459
+        $creationDT = new \DateTime('2016-01-19 18:48:00');
460
+        $diff = new \DateInterval('PT2H');
461
+        $readDT1 = clone $creationDT;
462
+        $readDT1->sub($diff);
463
+        $readDT2 = clone $creationDT;
464
+        $readDT2->add($diff);
465
+        return [
466
+            [$creationDT, $readDT1, 'true'],
467
+            [$creationDT, $readDT2, 'false'],
468
+            [$creationDT, null, 'true'],
469
+        ];
470
+    }
471
+
472
+    #[\PHPUnit\Framework\Attributes\DataProvider('readCommentProvider')]
473
+    public function testGetPropertiesUnreadProperty(\DateTime $creationDT, ?\DateTime $readDT, string $expected): void {
474
+        $this->comment->expects($this->any())
475
+            ->method('getCreationDateTime')
476
+            ->willReturn($creationDT);
477
+
478
+        $this->comment->expects($this->any())
479
+            ->method('getMentions')
480
+            ->willReturn([]);
481
+
482
+        $this->commentsManager->expects($this->once())
483
+            ->method('getReadMark')
484
+            ->willReturn($readDT);
485
+
486
+        $this->userSession->expects($this->once())
487
+            ->method('getUser')
488
+            ->willReturn(
489
+                $this->getMockBuilder(IUser::class)
490
+                    ->disableOriginalConstructor()
491
+                    ->getMock()
492
+            );
493
+
494
+        $properties = $this->node->getProperties(null);
495
+
496
+        $this->assertTrue(array_key_exists(CommentNode::PROPERTY_NAME_UNREAD, $properties));
497
+        $this->assertSame($properties[CommentNode::PROPERTY_NAME_UNREAD], $expected);
498
+    }
499 499
 }
Please login to merge, or discard this patch.