Completed
Push — master ( 5d14f8...2337bd )
by Robin
27:19 queued 16s
created
apps/dav/tests/unit/Connector/Sabre/CommentsPropertiesPluginTest.php 1 patch
Indentation   +95 added lines, -95 removed lines patch added patch discarded remove patch
@@ -19,99 +19,99 @@
 block discarded – undo
19 19
 use Sabre\DAV\Server;
20 20
 
21 21
 class CommentsPropertiesPluginTest extends \Test\TestCase {
22
-	protected CommentPropertiesPluginImplementation $plugin;
23
-	protected ICommentsManager&MockObject $commentsManager;
24
-	protected IUserSession&MockObject $userSession;
25
-	protected Server&MockObject $server;
26
-
27
-	protected function setUp(): void {
28
-		parent::setUp();
29
-
30
-		$this->commentsManager = $this->createMock(ICommentsManager::class);
31
-		$this->userSession = $this->createMock(IUserSession::class);
32
-		$this->server = $this->createMock(Server::class);
33
-
34
-		$this->plugin = new CommentPropertiesPluginImplementation($this->commentsManager, $this->userSession);
35
-		$this->plugin->initialize($this->server);
36
-	}
37
-
38
-	public static function nodeProvider(): array {
39
-		return [
40
-			[File::class, true],
41
-			[Directory::class, true],
42
-			[\Sabre\DAV\INode::class, false]
43
-		];
44
-	}
45
-
46
-	#[\PHPUnit\Framework\Attributes\DataProvider('nodeProvider')]
47
-	public function testHandleGetProperties(string $class, bool $expectedSuccessful): void {
48
-		$propFind = $this->createMock(PropFind::class);
49
-
50
-		if ($expectedSuccessful) {
51
-			$propFind->expects($this->exactly(3))
52
-				->method('handle');
53
-		} else {
54
-			$propFind->expects($this->never())
55
-				->method('handle');
56
-		}
57
-
58
-		$node = $this->createMock($class);
59
-		$this->plugin->handleGetProperties($propFind, $node);
60
-	}
61
-
62
-	public static function baseUriProvider(): array {
63
-		return [
64
-			['owncloud/remote.php/webdav/', '4567', 'owncloud/remote.php/dav/comments/files/4567'],
65
-			['owncloud/remote.php/files/', '4567', 'owncloud/remote.php/dav/comments/files/4567'],
66
-			['owncloud/wicked.php/files/', '4567', null]
67
-		];
68
-	}
69
-
70
-	#[\PHPUnit\Framework\Attributes\DataProvider('baseUriProvider')]
71
-	public function testGetCommentsLink(string $baseUri, string $fid, ?string $expectedHref): void {
72
-		$node = $this->createMock(File::class);
73
-		$node->expects($this->any())
74
-			->method('getId')
75
-			->willReturn($fid);
76
-
77
-		$this->server->expects($this->once())
78
-			->method('getBaseUri')
79
-			->willReturn($baseUri);
80
-
81
-		$href = $this->plugin->getCommentsLink($node);
82
-		$this->assertSame($expectedHref, $href);
83
-	}
84
-
85
-	public static function userProvider(): array {
86
-		return [
87
-			[IUser::class],
88
-			[null]
89
-		];
90
-	}
91
-
92
-	#[\PHPUnit\Framework\Attributes\DataProvider('userProvider')]
93
-	public function testGetUnreadCount(?string $user): void {
94
-		$node = $this->createMock(File::class);
95
-		$node->expects($this->any())
96
-			->method('getId')
97
-			->willReturn('4567');
98
-
99
-		if ($user !== null) {
100
-			$user = $this->createMock($user);
101
-		}
102
-		$this->userSession->expects($this->once())
103
-			->method('getUser')
104
-			->willReturn($user);
105
-
106
-		$this->commentsManager->expects($this->any())
107
-			->method('getNumberOfCommentsForObject')
108
-			->willReturn(42);
109
-
110
-		$unread = $this->plugin->getUnreadCount($node);
111
-		if (is_null($user)) {
112
-			$this->assertNull($unread);
113
-		} else {
114
-			$this->assertSame($unread, 42);
115
-		}
116
-	}
22
+    protected CommentPropertiesPluginImplementation $plugin;
23
+    protected ICommentsManager&MockObject $commentsManager;
24
+    protected IUserSession&MockObject $userSession;
25
+    protected Server&MockObject $server;
26
+
27
+    protected function setUp(): void {
28
+        parent::setUp();
29
+
30
+        $this->commentsManager = $this->createMock(ICommentsManager::class);
31
+        $this->userSession = $this->createMock(IUserSession::class);
32
+        $this->server = $this->createMock(Server::class);
33
+
34
+        $this->plugin = new CommentPropertiesPluginImplementation($this->commentsManager, $this->userSession);
35
+        $this->plugin->initialize($this->server);
36
+    }
37
+
38
+    public static function nodeProvider(): array {
39
+        return [
40
+            [File::class, true],
41
+            [Directory::class, true],
42
+            [\Sabre\DAV\INode::class, false]
43
+        ];
44
+    }
45
+
46
+    #[\PHPUnit\Framework\Attributes\DataProvider('nodeProvider')]
47
+    public function testHandleGetProperties(string $class, bool $expectedSuccessful): void {
48
+        $propFind = $this->createMock(PropFind::class);
49
+
50
+        if ($expectedSuccessful) {
51
+            $propFind->expects($this->exactly(3))
52
+                ->method('handle');
53
+        } else {
54
+            $propFind->expects($this->never())
55
+                ->method('handle');
56
+        }
57
+
58
+        $node = $this->createMock($class);
59
+        $this->plugin->handleGetProperties($propFind, $node);
60
+    }
61
+
62
+    public static function baseUriProvider(): array {
63
+        return [
64
+            ['owncloud/remote.php/webdav/', '4567', 'owncloud/remote.php/dav/comments/files/4567'],
65
+            ['owncloud/remote.php/files/', '4567', 'owncloud/remote.php/dav/comments/files/4567'],
66
+            ['owncloud/wicked.php/files/', '4567', null]
67
+        ];
68
+    }
69
+
70
+    #[\PHPUnit\Framework\Attributes\DataProvider('baseUriProvider')]
71
+    public function testGetCommentsLink(string $baseUri, string $fid, ?string $expectedHref): void {
72
+        $node = $this->createMock(File::class);
73
+        $node->expects($this->any())
74
+            ->method('getId')
75
+            ->willReturn($fid);
76
+
77
+        $this->server->expects($this->once())
78
+            ->method('getBaseUri')
79
+            ->willReturn($baseUri);
80
+
81
+        $href = $this->plugin->getCommentsLink($node);
82
+        $this->assertSame($expectedHref, $href);
83
+    }
84
+
85
+    public static function userProvider(): array {
86
+        return [
87
+            [IUser::class],
88
+            [null]
89
+        ];
90
+    }
91
+
92
+    #[\PHPUnit\Framework\Attributes\DataProvider('userProvider')]
93
+    public function testGetUnreadCount(?string $user): void {
94
+        $node = $this->createMock(File::class);
95
+        $node->expects($this->any())
96
+            ->method('getId')
97
+            ->willReturn('4567');
98
+
99
+        if ($user !== null) {
100
+            $user = $this->createMock($user);
101
+        }
102
+        $this->userSession->expects($this->once())
103
+            ->method('getUser')
104
+            ->willReturn($user);
105
+
106
+        $this->commentsManager->expects($this->any())
107
+            ->method('getNumberOfCommentsForObject')
108
+            ->willReturn(42);
109
+
110
+        $unread = $this->plugin->getUnreadCount($node);
111
+        if (is_null($user)) {
112
+            $this->assertNull($unread);
113
+        } else {
114
+            $this->assertSame($unread, 42);
115
+        }
116
+    }
117 117
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Connector/Sabre/TagsPluginTest.php 2 patches
Indentation   +382 added lines, -382 removed lines patch added patch discarded remove patch
@@ -23,386 +23,386 @@
 block discarded – undo
23 23
 use Sabre\DAV\Tree;
24 24
 
25 25
 class TagsPluginTest extends \Test\TestCase {
26
-	public const TAGS_PROPERTYNAME = TagsPlugin::TAGS_PROPERTYNAME;
27
-	public const FAVORITE_PROPERTYNAME = TagsPlugin::FAVORITE_PROPERTYNAME;
28
-	public const TAG_FAVORITE = TagsPlugin::TAG_FAVORITE;
29
-
30
-	private \Sabre\DAV\Server $server;
31
-	private Tree&MockObject $tree;
32
-	private ITagManager&MockObject $tagManager;
33
-	private ITags&MockObject $tagger;
34
-	private IEventDispatcher&MockObject $eventDispatcher;
35
-	private IUserSession&MockObject $userSession;
36
-	private TagsPlugin $plugin;
37
-
38
-	protected function setUp(): void {
39
-		parent::setUp();
40
-
41
-		$this->server = new \Sabre\DAV\Server();
42
-		$this->tree = $this->createMock(Tree::class);
43
-		$this->tagger = $this->createMock(ITags::class);
44
-		$this->tagManager = $this->createMock(ITagManager::class);
45
-		$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
46
-		$user = $this->createMock(IUser::class);
47
-
48
-		$this->userSession = $this->createMock(IUserSession::class);
49
-		$this->userSession->expects($this->any())
50
-			->method('getUser')
51
-			->withAnyParameters()
52
-			->willReturn($user);
53
-		$this->tagManager->expects($this->any())
54
-			->method('load')
55
-			->with('files')
56
-			->willReturn($this->tagger);
57
-		$this->plugin = new TagsPlugin($this->tree, $this->tagManager, $this->eventDispatcher, $this->userSession);
58
-		$this->plugin->initialize($this->server);
59
-	}
60
-
61
-	#[\PHPUnit\Framework\Attributes\DataProvider('tagsGetPropertiesDataProvider')]
62
-	public function testGetProperties(array $tags, array $requestedProperties, array $expectedProperties): void {
63
-		$node = $this->createMock(Node::class);
64
-		$node->expects($this->any())
65
-			->method('getId')
66
-			->willReturn(123);
67
-
68
-		$expectedCallCount = 0;
69
-		if (count($requestedProperties) > 0) {
70
-			$expectedCallCount = 1;
71
-		}
72
-
73
-		$this->tagger->expects($this->exactly($expectedCallCount))
74
-			->method('getTagsForObjects')
75
-			->with($this->equalTo([123]))
76
-			->willReturn([123 => $tags]);
77
-
78
-		$propFind = new \Sabre\DAV\PropFind(
79
-			'/dummyPath',
80
-			$requestedProperties,
81
-			0
82
-		);
83
-
84
-		$this->plugin->handleGetProperties(
85
-			$propFind,
86
-			$node
87
-		);
88
-
89
-		$result = $propFind->getResultForMultiStatus();
90
-
91
-		$this->assertEmpty($result[404]);
92
-		unset($result[404]);
93
-		$this->assertEquals($expectedProperties, $result);
94
-	}
95
-
96
-	#[\PHPUnit\Framework\Attributes\DataProvider('tagsGetPropertiesDataProvider')]
97
-	public function testPreloadThenGetProperties(array $tags, array $requestedProperties, array $expectedProperties): void {
98
-		$node1 = $this->createMock(File::class);
99
-		$node1->expects($this->any())
100
-			->method('getId')
101
-			->willReturn(111);
102
-		$node2 = $this->createMock(File::class);
103
-		$node2->expects($this->any())
104
-			->method('getId')
105
-			->willReturn(222);
106
-
107
-		$expectedCallCount = 0;
108
-		if (count($requestedProperties) > 0) {
109
-			// this guarantees that getTagsForObjects
110
-			// is only called once and then the tags
111
-			// are cached
112
-			$expectedCallCount = 1;
113
-		}
114
-
115
-		$node = $this->createMock(Directory::class);
116
-		$node->expects($this->any())
117
-			->method('getId')
118
-			->willReturn(123);
119
-		$node->expects($this->exactly($expectedCallCount))
120
-			->method('getChildren')
121
-			->willReturn([$node1, $node2]);
122
-
123
-		$this->tagger->expects($this->exactly($expectedCallCount))
124
-			->method('getTagsForObjects')
125
-			->with($this->equalTo([123, 111, 222]))
126
-			->willReturn(
127
-				[
128
-					111 => $tags,
129
-					123 => $tags
130
-				]
131
-			);
132
-
133
-		// simulate sabre recursive PROPFIND traversal
134
-		$propFindRoot = new \Sabre\DAV\PropFind(
135
-			'/subdir',
136
-			$requestedProperties,
137
-			1
138
-		);
139
-		$propFind1 = new \Sabre\DAV\PropFind(
140
-			'/subdir/test.txt',
141
-			$requestedProperties,
142
-			0
143
-		);
144
-		$propFind2 = new \Sabre\DAV\PropFind(
145
-			'/subdir/test2.txt',
146
-			$requestedProperties,
147
-			0
148
-		);
149
-
150
-		$this->plugin->handleGetProperties(
151
-			$propFindRoot,
152
-			$node
153
-		);
154
-		$this->plugin->handleGetProperties(
155
-			$propFind1,
156
-			$node1
157
-		);
158
-		$this->plugin->handleGetProperties(
159
-			$propFind2,
160
-			$node2
161
-		);
162
-
163
-		$result = $propFind1->getResultForMultiStatus();
164
-
165
-		$this->assertEmpty($result[404]);
166
-		unset($result[404]);
167
-		$this->assertEquals($expectedProperties, $result);
168
-	}
169
-
170
-	public static function tagsGetPropertiesDataProvider(): array {
171
-		return [
172
-			// request both, receive both
173
-			[
174
-				['tag1', 'tag2', self::TAG_FAVORITE],
175
-				[self::TAGS_PROPERTYNAME, self::FAVORITE_PROPERTYNAME],
176
-				[
177
-					200 => [
178
-						self::TAGS_PROPERTYNAME => new TagList(['tag1', 'tag2']),
179
-						self::FAVORITE_PROPERTYNAME => true,
180
-					]
181
-				]
182
-			],
183
-			// request tags alone
184
-			[
185
-				['tag1', 'tag2', self::TAG_FAVORITE],
186
-				[self::TAGS_PROPERTYNAME],
187
-				[
188
-					200 => [
189
-						self::TAGS_PROPERTYNAME => new TagList(['tag1', 'tag2']),
190
-					]
191
-				]
192
-			],
193
-			// request fav alone
194
-			[
195
-				['tag1', 'tag2', self::TAG_FAVORITE],
196
-				[self::FAVORITE_PROPERTYNAME],
197
-				[
198
-					200 => [
199
-						self::FAVORITE_PROPERTYNAME => true,
200
-					]
201
-				]
202
-			],
203
-			// request none
204
-			[
205
-				['tag1', 'tag2', self::TAG_FAVORITE],
206
-				[],
207
-				[
208
-					200 => []
209
-				],
210
-			],
211
-			// request both with none set, receive both
212
-			[
213
-				[],
214
-				[self::TAGS_PROPERTYNAME, self::FAVORITE_PROPERTYNAME],
215
-				[
216
-					200 => [
217
-						self::TAGS_PROPERTYNAME => new TagList([]),
218
-						self::FAVORITE_PROPERTYNAME => false,
219
-					]
220
-				]
221
-			],
222
-		];
223
-	}
224
-
225
-	public function testGetPropertiesSkipChunks(): void {
226
-		$sabreNode = $this->createMock(UploadFile::class);
227
-
228
-		$propFind = new \Sabre\DAV\PropFind(
229
-			'/dummyPath',
230
-			[self::TAGS_PROPERTYNAME, self::TAG_FAVORITE],
231
-			0
232
-		);
233
-
234
-		$this->plugin->handleGetProperties(
235
-			$propFind,
236
-			$sabreNode
237
-		);
238
-
239
-		$result = $propFind->getResultForMultiStatus();
240
-		$this->assertCount(2, $result[404]);
241
-	}
242
-
243
-	public function testUpdateTags(): void {
244
-		// this test will replace the existing tags "tagremove" with "tag1" and "tag2"
245
-		// and keep "tagkeep"
246
-		$node = $this->createMock(Node::class);
247
-		$node->expects($this->any())
248
-			->method('getId')
249
-			->willReturn(123);
250
-
251
-		$this->tree->expects($this->any())
252
-			->method('getNodeForPath')
253
-			->with('/dummypath')
254
-			->willReturn($node);
255
-
256
-		$this->tagger->expects($this->once())
257
-			->method('getTagsForObjects')
258
-			->with($this->equalTo([123]))
259
-			->willReturn([123 => ['tagkeep', 'tagremove', self::TAG_FAVORITE]]);
260
-
261
-		// then tag as tag1 and tag2
262
-		$calls = [
263
-			[123, 'tag1'],
264
-			[123, 'tag2'],
265
-		];
266
-		$this->tagger->expects($this->exactly(count($calls)))
267
-			->method('tagAs')
268
-			->willReturnCallback(function () use (&$calls): void {
269
-				$expected = array_shift($calls);
270
-				$this->assertEquals($expected, func_get_args());
271
-			});
272
-
273
-		// it will untag tag3
274
-		$this->tagger->expects($this->once())
275
-			->method('unTag')
276
-			->with(123, 'tagremove');
277
-
278
-		// properties to set
279
-		$propPatch = new \Sabre\DAV\PropPatch([
280
-			self::TAGS_PROPERTYNAME => new TagList(['tag1', 'tag2', 'tagkeep'])
281
-		]);
282
-
283
-		$this->plugin->handleUpdateProperties(
284
-			'/dummypath',
285
-			$propPatch
286
-		);
287
-
288
-		$propPatch->commit();
289
-
290
-		// all requested properties removed, as they were processed already
291
-		$this->assertEmpty($propPatch->getRemainingMutations());
292
-
293
-		$result = $propPatch->getResult();
294
-		$this->assertEquals(200, $result[self::TAGS_PROPERTYNAME]);
295
-		$this->assertArrayNotHasKey(self::FAVORITE_PROPERTYNAME, $result);
296
-	}
297
-
298
-	public function testUpdateTagsFromScratch(): void {
299
-		$node = $this->createMock(Node::class);
300
-		$node->expects($this->any())
301
-			->method('getId')
302
-			->willReturn(123);
303
-
304
-		$this->tree->expects($this->any())
305
-			->method('getNodeForPath')
306
-			->with('/dummypath')
307
-			->willReturn($node);
308
-
309
-		$this->tagger->expects($this->once())
310
-			->method('getTagsForObjects')
311
-			->with($this->equalTo([123]))
312
-			->willReturn([]);
313
-
314
-		// then tag as tag1 and tag2
315
-		$calls = [
316
-			[123, 'tag1'],
317
-			[123, 'tag2'],
318
-		];
319
-		$this->tagger->expects($this->exactly(count($calls)))
320
-			->method('tagAs')
321
-			->willReturnCallback(function () use (&$calls): void {
322
-				$expected = array_shift($calls);
323
-				$this->assertEquals($expected, func_get_args());
324
-			});
325
-
326
-		// properties to set
327
-		$propPatch = new \Sabre\DAV\PropPatch([
328
-			self::TAGS_PROPERTYNAME => new TagList(['tag1', 'tag2'])
329
-		]);
330
-
331
-		$this->plugin->handleUpdateProperties(
332
-			'/dummypath',
333
-			$propPatch
334
-		);
335
-
336
-		$propPatch->commit();
337
-
338
-		// all requested properties removed, as they were processed already
339
-		$this->assertEmpty($propPatch->getRemainingMutations());
340
-
341
-		$result = $propPatch->getResult();
342
-		$this->assertEquals(200, $result[self::TAGS_PROPERTYNAME]);
343
-		$this->assertArrayNotHasKey(self::FAVORITE_PROPERTYNAME, $result);
344
-	}
345
-
346
-	public function testUpdateFav(): void {
347
-		// this test will replace the existing tags "tagremove" with "tag1" and "tag2"
348
-		// and keep "tagkeep"
349
-		$node = $this->createMock(Node::class);
350
-		$node->expects($this->any())
351
-			->method('getId')
352
-			->willReturn(123);
353
-
354
-		$this->tree->expects($this->any())
355
-			->method('getNodeForPath')
356
-			->with('/dummypath')
357
-			->willReturn($node);
358
-
359
-		// set favorite tag
360
-		$this->tagger->expects($this->once())
361
-			->method('tagAs')
362
-			->with(123, self::TAG_FAVORITE);
363
-
364
-		// properties to set
365
-		$propPatch = new \Sabre\DAV\PropPatch([
366
-			self::FAVORITE_PROPERTYNAME => true
367
-		]);
368
-
369
-		$this->plugin->handleUpdateProperties(
370
-			'/dummypath',
371
-			$propPatch
372
-		);
373
-
374
-		$propPatch->commit();
375
-
376
-		// all requested properties removed, as they were processed already
377
-		$this->assertEmpty($propPatch->getRemainingMutations());
378
-
379
-		$result = $propPatch->getResult();
380
-		$this->assertArrayNotHasKey(self::TAGS_PROPERTYNAME, $result);
381
-		$this->assertEquals(200, $result[self::FAVORITE_PROPERTYNAME]);
382
-
383
-		// unfavorite now
384
-		// set favorite tag
385
-		$this->tagger->expects($this->once())
386
-			->method('unTag')
387
-			->with(123, self::TAG_FAVORITE);
388
-
389
-		// properties to set
390
-		$propPatch = new \Sabre\DAV\PropPatch([
391
-			self::FAVORITE_PROPERTYNAME => false
392
-		]);
393
-
394
-		$this->plugin->handleUpdateProperties(
395
-			'/dummypath',
396
-			$propPatch
397
-		);
398
-
399
-		$propPatch->commit();
400
-
401
-		// all requested properties removed, as they were processed already
402
-		$this->assertEmpty($propPatch->getRemainingMutations());
403
-
404
-		$result = $propPatch->getResult();
405
-		$this->assertArrayNotHasKey(self::TAGS_PROPERTYNAME, $result);
406
-		$this->assertEquals(200, $result[self::FAVORITE_PROPERTYNAME]);
407
-	}
26
+    public const TAGS_PROPERTYNAME = TagsPlugin::TAGS_PROPERTYNAME;
27
+    public const FAVORITE_PROPERTYNAME = TagsPlugin::FAVORITE_PROPERTYNAME;
28
+    public const TAG_FAVORITE = TagsPlugin::TAG_FAVORITE;
29
+
30
+    private \Sabre\DAV\Server $server;
31
+    private Tree&MockObject $tree;
32
+    private ITagManager&MockObject $tagManager;
33
+    private ITags&MockObject $tagger;
34
+    private IEventDispatcher&MockObject $eventDispatcher;
35
+    private IUserSession&MockObject $userSession;
36
+    private TagsPlugin $plugin;
37
+
38
+    protected function setUp(): void {
39
+        parent::setUp();
40
+
41
+        $this->server = new \Sabre\DAV\Server();
42
+        $this->tree = $this->createMock(Tree::class);
43
+        $this->tagger = $this->createMock(ITags::class);
44
+        $this->tagManager = $this->createMock(ITagManager::class);
45
+        $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
46
+        $user = $this->createMock(IUser::class);
47
+
48
+        $this->userSession = $this->createMock(IUserSession::class);
49
+        $this->userSession->expects($this->any())
50
+            ->method('getUser')
51
+            ->withAnyParameters()
52
+            ->willReturn($user);
53
+        $this->tagManager->expects($this->any())
54
+            ->method('load')
55
+            ->with('files')
56
+            ->willReturn($this->tagger);
57
+        $this->plugin = new TagsPlugin($this->tree, $this->tagManager, $this->eventDispatcher, $this->userSession);
58
+        $this->plugin->initialize($this->server);
59
+    }
60
+
61
+    #[\PHPUnit\Framework\Attributes\DataProvider('tagsGetPropertiesDataProvider')]
62
+    public function testGetProperties(array $tags, array $requestedProperties, array $expectedProperties): void {
63
+        $node = $this->createMock(Node::class);
64
+        $node->expects($this->any())
65
+            ->method('getId')
66
+            ->willReturn(123);
67
+
68
+        $expectedCallCount = 0;
69
+        if (count($requestedProperties) > 0) {
70
+            $expectedCallCount = 1;
71
+        }
72
+
73
+        $this->tagger->expects($this->exactly($expectedCallCount))
74
+            ->method('getTagsForObjects')
75
+            ->with($this->equalTo([123]))
76
+            ->willReturn([123 => $tags]);
77
+
78
+        $propFind = new \Sabre\DAV\PropFind(
79
+            '/dummyPath',
80
+            $requestedProperties,
81
+            0
82
+        );
83
+
84
+        $this->plugin->handleGetProperties(
85
+            $propFind,
86
+            $node
87
+        );
88
+
89
+        $result = $propFind->getResultForMultiStatus();
90
+
91
+        $this->assertEmpty($result[404]);
92
+        unset($result[404]);
93
+        $this->assertEquals($expectedProperties, $result);
94
+    }
95
+
96
+    #[\PHPUnit\Framework\Attributes\DataProvider('tagsGetPropertiesDataProvider')]
97
+    public function testPreloadThenGetProperties(array $tags, array $requestedProperties, array $expectedProperties): void {
98
+        $node1 = $this->createMock(File::class);
99
+        $node1->expects($this->any())
100
+            ->method('getId')
101
+            ->willReturn(111);
102
+        $node2 = $this->createMock(File::class);
103
+        $node2->expects($this->any())
104
+            ->method('getId')
105
+            ->willReturn(222);
106
+
107
+        $expectedCallCount = 0;
108
+        if (count($requestedProperties) > 0) {
109
+            // this guarantees that getTagsForObjects
110
+            // is only called once and then the tags
111
+            // are cached
112
+            $expectedCallCount = 1;
113
+        }
114
+
115
+        $node = $this->createMock(Directory::class);
116
+        $node->expects($this->any())
117
+            ->method('getId')
118
+            ->willReturn(123);
119
+        $node->expects($this->exactly($expectedCallCount))
120
+            ->method('getChildren')
121
+            ->willReturn([$node1, $node2]);
122
+
123
+        $this->tagger->expects($this->exactly($expectedCallCount))
124
+            ->method('getTagsForObjects')
125
+            ->with($this->equalTo([123, 111, 222]))
126
+            ->willReturn(
127
+                [
128
+                    111 => $tags,
129
+                    123 => $tags
130
+                ]
131
+            );
132
+
133
+        // simulate sabre recursive PROPFIND traversal
134
+        $propFindRoot = new \Sabre\DAV\PropFind(
135
+            '/subdir',
136
+            $requestedProperties,
137
+            1
138
+        );
139
+        $propFind1 = new \Sabre\DAV\PropFind(
140
+            '/subdir/test.txt',
141
+            $requestedProperties,
142
+            0
143
+        );
144
+        $propFind2 = new \Sabre\DAV\PropFind(
145
+            '/subdir/test2.txt',
146
+            $requestedProperties,
147
+            0
148
+        );
149
+
150
+        $this->plugin->handleGetProperties(
151
+            $propFindRoot,
152
+            $node
153
+        );
154
+        $this->plugin->handleGetProperties(
155
+            $propFind1,
156
+            $node1
157
+        );
158
+        $this->plugin->handleGetProperties(
159
+            $propFind2,
160
+            $node2
161
+        );
162
+
163
+        $result = $propFind1->getResultForMultiStatus();
164
+
165
+        $this->assertEmpty($result[404]);
166
+        unset($result[404]);
167
+        $this->assertEquals($expectedProperties, $result);
168
+    }
169
+
170
+    public static function tagsGetPropertiesDataProvider(): array {
171
+        return [
172
+            // request both, receive both
173
+            [
174
+                ['tag1', 'tag2', self::TAG_FAVORITE],
175
+                [self::TAGS_PROPERTYNAME, self::FAVORITE_PROPERTYNAME],
176
+                [
177
+                    200 => [
178
+                        self::TAGS_PROPERTYNAME => new TagList(['tag1', 'tag2']),
179
+                        self::FAVORITE_PROPERTYNAME => true,
180
+                    ]
181
+                ]
182
+            ],
183
+            // request tags alone
184
+            [
185
+                ['tag1', 'tag2', self::TAG_FAVORITE],
186
+                [self::TAGS_PROPERTYNAME],
187
+                [
188
+                    200 => [
189
+                        self::TAGS_PROPERTYNAME => new TagList(['tag1', 'tag2']),
190
+                    ]
191
+                ]
192
+            ],
193
+            // request fav alone
194
+            [
195
+                ['tag1', 'tag2', self::TAG_FAVORITE],
196
+                [self::FAVORITE_PROPERTYNAME],
197
+                [
198
+                    200 => [
199
+                        self::FAVORITE_PROPERTYNAME => true,
200
+                    ]
201
+                ]
202
+            ],
203
+            // request none
204
+            [
205
+                ['tag1', 'tag2', self::TAG_FAVORITE],
206
+                [],
207
+                [
208
+                    200 => []
209
+                ],
210
+            ],
211
+            // request both with none set, receive both
212
+            [
213
+                [],
214
+                [self::TAGS_PROPERTYNAME, self::FAVORITE_PROPERTYNAME],
215
+                [
216
+                    200 => [
217
+                        self::TAGS_PROPERTYNAME => new TagList([]),
218
+                        self::FAVORITE_PROPERTYNAME => false,
219
+                    ]
220
+                ]
221
+            ],
222
+        ];
223
+    }
224
+
225
+    public function testGetPropertiesSkipChunks(): void {
226
+        $sabreNode = $this->createMock(UploadFile::class);
227
+
228
+        $propFind = new \Sabre\DAV\PropFind(
229
+            '/dummyPath',
230
+            [self::TAGS_PROPERTYNAME, self::TAG_FAVORITE],
231
+            0
232
+        );
233
+
234
+        $this->plugin->handleGetProperties(
235
+            $propFind,
236
+            $sabreNode
237
+        );
238
+
239
+        $result = $propFind->getResultForMultiStatus();
240
+        $this->assertCount(2, $result[404]);
241
+    }
242
+
243
+    public function testUpdateTags(): void {
244
+        // this test will replace the existing tags "tagremove" with "tag1" and "tag2"
245
+        // and keep "tagkeep"
246
+        $node = $this->createMock(Node::class);
247
+        $node->expects($this->any())
248
+            ->method('getId')
249
+            ->willReturn(123);
250
+
251
+        $this->tree->expects($this->any())
252
+            ->method('getNodeForPath')
253
+            ->with('/dummypath')
254
+            ->willReturn($node);
255
+
256
+        $this->tagger->expects($this->once())
257
+            ->method('getTagsForObjects')
258
+            ->with($this->equalTo([123]))
259
+            ->willReturn([123 => ['tagkeep', 'tagremove', self::TAG_FAVORITE]]);
260
+
261
+        // then tag as tag1 and tag2
262
+        $calls = [
263
+            [123, 'tag1'],
264
+            [123, 'tag2'],
265
+        ];
266
+        $this->tagger->expects($this->exactly(count($calls)))
267
+            ->method('tagAs')
268
+            ->willReturnCallback(function () use (&$calls): void {
269
+                $expected = array_shift($calls);
270
+                $this->assertEquals($expected, func_get_args());
271
+            });
272
+
273
+        // it will untag tag3
274
+        $this->tagger->expects($this->once())
275
+            ->method('unTag')
276
+            ->with(123, 'tagremove');
277
+
278
+        // properties to set
279
+        $propPatch = new \Sabre\DAV\PropPatch([
280
+            self::TAGS_PROPERTYNAME => new TagList(['tag1', 'tag2', 'tagkeep'])
281
+        ]);
282
+
283
+        $this->plugin->handleUpdateProperties(
284
+            '/dummypath',
285
+            $propPatch
286
+        );
287
+
288
+        $propPatch->commit();
289
+
290
+        // all requested properties removed, as they were processed already
291
+        $this->assertEmpty($propPatch->getRemainingMutations());
292
+
293
+        $result = $propPatch->getResult();
294
+        $this->assertEquals(200, $result[self::TAGS_PROPERTYNAME]);
295
+        $this->assertArrayNotHasKey(self::FAVORITE_PROPERTYNAME, $result);
296
+    }
297
+
298
+    public function testUpdateTagsFromScratch(): void {
299
+        $node = $this->createMock(Node::class);
300
+        $node->expects($this->any())
301
+            ->method('getId')
302
+            ->willReturn(123);
303
+
304
+        $this->tree->expects($this->any())
305
+            ->method('getNodeForPath')
306
+            ->with('/dummypath')
307
+            ->willReturn($node);
308
+
309
+        $this->tagger->expects($this->once())
310
+            ->method('getTagsForObjects')
311
+            ->with($this->equalTo([123]))
312
+            ->willReturn([]);
313
+
314
+        // then tag as tag1 and tag2
315
+        $calls = [
316
+            [123, 'tag1'],
317
+            [123, 'tag2'],
318
+        ];
319
+        $this->tagger->expects($this->exactly(count($calls)))
320
+            ->method('tagAs')
321
+            ->willReturnCallback(function () use (&$calls): void {
322
+                $expected = array_shift($calls);
323
+                $this->assertEquals($expected, func_get_args());
324
+            });
325
+
326
+        // properties to set
327
+        $propPatch = new \Sabre\DAV\PropPatch([
328
+            self::TAGS_PROPERTYNAME => new TagList(['tag1', 'tag2'])
329
+        ]);
330
+
331
+        $this->plugin->handleUpdateProperties(
332
+            '/dummypath',
333
+            $propPatch
334
+        );
335
+
336
+        $propPatch->commit();
337
+
338
+        // all requested properties removed, as they were processed already
339
+        $this->assertEmpty($propPatch->getRemainingMutations());
340
+
341
+        $result = $propPatch->getResult();
342
+        $this->assertEquals(200, $result[self::TAGS_PROPERTYNAME]);
343
+        $this->assertArrayNotHasKey(self::FAVORITE_PROPERTYNAME, $result);
344
+    }
345
+
346
+    public function testUpdateFav(): void {
347
+        // this test will replace the existing tags "tagremove" with "tag1" and "tag2"
348
+        // and keep "tagkeep"
349
+        $node = $this->createMock(Node::class);
350
+        $node->expects($this->any())
351
+            ->method('getId')
352
+            ->willReturn(123);
353
+
354
+        $this->tree->expects($this->any())
355
+            ->method('getNodeForPath')
356
+            ->with('/dummypath')
357
+            ->willReturn($node);
358
+
359
+        // set favorite tag
360
+        $this->tagger->expects($this->once())
361
+            ->method('tagAs')
362
+            ->with(123, self::TAG_FAVORITE);
363
+
364
+        // properties to set
365
+        $propPatch = new \Sabre\DAV\PropPatch([
366
+            self::FAVORITE_PROPERTYNAME => true
367
+        ]);
368
+
369
+        $this->plugin->handleUpdateProperties(
370
+            '/dummypath',
371
+            $propPatch
372
+        );
373
+
374
+        $propPatch->commit();
375
+
376
+        // all requested properties removed, as they were processed already
377
+        $this->assertEmpty($propPatch->getRemainingMutations());
378
+
379
+        $result = $propPatch->getResult();
380
+        $this->assertArrayNotHasKey(self::TAGS_PROPERTYNAME, $result);
381
+        $this->assertEquals(200, $result[self::FAVORITE_PROPERTYNAME]);
382
+
383
+        // unfavorite now
384
+        // set favorite tag
385
+        $this->tagger->expects($this->once())
386
+            ->method('unTag')
387
+            ->with(123, self::TAG_FAVORITE);
388
+
389
+        // properties to set
390
+        $propPatch = new \Sabre\DAV\PropPatch([
391
+            self::FAVORITE_PROPERTYNAME => false
392
+        ]);
393
+
394
+        $this->plugin->handleUpdateProperties(
395
+            '/dummypath',
396
+            $propPatch
397
+        );
398
+
399
+        $propPatch->commit();
400
+
401
+        // all requested properties removed, as they were processed already
402
+        $this->assertEmpty($propPatch->getRemainingMutations());
403
+
404
+        $result = $propPatch->getResult();
405
+        $this->assertArrayNotHasKey(self::TAGS_PROPERTYNAME, $result);
406
+        $this->assertEquals(200, $result[self::FAVORITE_PROPERTYNAME]);
407
+    }
408 408
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -265,7 +265,7 @@  discard block
 block discarded – undo
265 265
 		];
266 266
 		$this->tagger->expects($this->exactly(count($calls)))
267 267
 			->method('tagAs')
268
-			->willReturnCallback(function () use (&$calls): void {
268
+			->willReturnCallback(function() use (&$calls): void {
269 269
 				$expected = array_shift($calls);
270 270
 				$this->assertEquals($expected, func_get_args());
271 271
 			});
@@ -318,7 +318,7 @@  discard block
 block discarded – undo
318 318
 		];
319 319
 		$this->tagger->expects($this->exactly(count($calls)))
320 320
 			->method('tagAs')
321
-			->willReturnCallback(function () use (&$calls): void {
321
+			->willReturnCallback(function() use (&$calls): void {
322 322
 				$expected = array_shift($calls);
323 323
 				$this->assertEquals($expected, func_get_args());
324 324
 			});
Please login to merge, or discard this patch.
apps/dav/tests/unit/Connector/Sabre/ObjectTreeTest.php 1 patch
Indentation   +212 added lines, -212 removed lines patch added patch discarded remove patch
@@ -28,216 +28,216 @@
 block discarded – undo
28 28
  * @package OCA\DAV\Tests\Unit\Connector\Sabre
29 29
  */
30 30
 class ObjectTreeTest extends \Test\TestCase {
31
-	public static function copyDataProvider(): array {
32
-		return [
33
-			// copy into same dir
34
-			['a', 'b', ''],
35
-			// copy into same dir
36
-			['a/a', 'a/b', 'a'],
37
-			// copy into another dir
38
-			['a', 'sub/a', 'sub'],
39
-		];
40
-	}
41
-
42
-	#[\PHPUnit\Framework\Attributes\DataProvider('copyDataProvider')]
43
-	public function testCopy(string $sourcePath, string $targetPath, string $targetParent): void {
44
-		$view = $this->createMock(View::class);
45
-		$view->expects($this->once())
46
-			->method('verifyPath')
47
-			->with($targetParent);
48
-		$view->expects($this->once())
49
-			->method('file_exists')
50
-			->with($targetPath)
51
-			->willReturn(false);
52
-		$view->expects($this->once())
53
-			->method('copy')
54
-			->with($sourcePath, $targetPath)
55
-			->willReturn(true);
56
-
57
-		$info = $this->createMock(FileInfo::class);
58
-		$info->expects($this->once())
59
-			->method('isCreatable')
60
-			->willReturn(true);
61
-
62
-		$view->expects($this->once())
63
-			->method('getFileInfo')
64
-			->with($targetParent === '' ? '.' : $targetParent)
65
-			->willReturn($info);
66
-
67
-		$rootDir = new Directory($view, $info);
68
-		$objectTree = $this->getMockBuilder(ObjectTree::class)
69
-			->onlyMethods(['nodeExists', 'getNodeForPath'])
70
-			->setConstructorArgs([$rootDir, $view])
71
-			->getMock();
72
-
73
-		$objectTree->expects($this->once())
74
-			->method('getNodeForPath')
75
-			->with($this->identicalTo($sourcePath))
76
-			->willReturn(false);
77
-
78
-		/** @var ObjectTree $objectTree */
79
-		$mountManager = Filesystem::getMountManager();
80
-		$objectTree->init($rootDir, $view, $mountManager);
81
-		$objectTree->copy($sourcePath, $targetPath);
82
-	}
83
-
84
-	#[\PHPUnit\Framework\Attributes\DataProvider('copyDataProvider')]
85
-	public function testCopyFailNotCreatable($sourcePath, $targetPath, $targetParent): void {
86
-		$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
87
-
88
-		$view = $this->createMock(View::class);
89
-		$view->expects($this->never())
90
-			->method('verifyPath');
91
-		$view->expects($this->once())
92
-			->method('file_exists')
93
-			->with($targetPath)
94
-			->willReturn(false);
95
-		$view->expects($this->never())
96
-			->method('copy');
97
-
98
-		$info = $this->createMock(FileInfo::class);
99
-		$info->expects($this->once())
100
-			->method('isCreatable')
101
-			->willReturn(false);
102
-
103
-		$view->expects($this->once())
104
-			->method('getFileInfo')
105
-			->with($targetParent === '' ? '.' : $targetParent)
106
-			->willReturn($info);
107
-
108
-		$rootDir = new Directory($view, $info);
109
-		$objectTree = $this->getMockBuilder(ObjectTree::class)
110
-			->onlyMethods(['nodeExists', 'getNodeForPath'])
111
-			->setConstructorArgs([$rootDir, $view])
112
-			->getMock();
113
-
114
-		$objectTree->expects($this->never())
115
-			->method('getNodeForPath');
116
-
117
-		/** @var ObjectTree $objectTree */
118
-		$mountManager = Filesystem::getMountManager();
119
-		$objectTree->init($rootDir, $view, $mountManager);
120
-		$objectTree->copy($sourcePath, $targetPath);
121
-	}
122
-
123
-	#[\PHPUnit\Framework\Attributes\DataProvider('nodeForPathProvider')]
124
-	public function testGetNodeForPath(
125
-		string $inputFileName,
126
-		string $fileInfoQueryPath,
127
-		string $outputFileName,
128
-		string $type,
129
-	): void {
130
-		$rootNode = $this->createMock(Directory::class);
131
-		$mountManager = $this->createMock(Manager::class);
132
-		$view = $this->createMock(View::class);
133
-		$fileInfo = $this->createMock(FileInfo::class);
134
-		$fileInfo->method('getType')
135
-			->willReturn($type);
136
-		$fileInfo->method('getName')
137
-			->willReturn($outputFileName);
138
-		$fileInfo->method('getStorage')
139
-			->willReturn($this->createMock(Common::class));
140
-
141
-		$view->method('getFileInfo')
142
-			->with($fileInfoQueryPath)
143
-			->willReturn($fileInfo);
144
-
145
-		$tree = new ObjectTree();
146
-		$tree->init($rootNode, $view, $mountManager);
147
-
148
-		$node = $tree->getNodeForPath($inputFileName);
149
-
150
-		$this->assertNotNull($node);
151
-		$this->assertEquals($outputFileName, $node->getName());
152
-
153
-		if ($type === 'file') {
154
-			$this->assertInstanceOf(File::class, $node);
155
-		} else {
156
-			$this->assertInstanceOf(Directory::class, $node);
157
-		}
158
-	}
159
-
160
-	public static function nodeForPathProvider(): array {
161
-		return [
162
-			// regular file
163
-			[
164
-				'regularfile.txt',
165
-				'regularfile.txt',
166
-				'regularfile.txt',
167
-				'file',
168
-			],
169
-			// regular directory
170
-			[
171
-				'regulardir',
172
-				'regulardir',
173
-				'regulardir',
174
-				'dir',
175
-			],
176
-			// regular file in subdir
177
-			[
178
-				'subdir/regularfile.txt',
179
-				'subdir/regularfile.txt',
180
-				'regularfile.txt',
181
-				'file',
182
-			],
183
-			// regular directory in subdir
184
-			[
185
-				'subdir/regulardir',
186
-				'subdir/regulardir',
187
-				'regulardir',
188
-				'dir',
189
-			],
190
-		];
191
-	}
192
-
193
-
194
-	public function testGetNodeForPathInvalidPath(): void {
195
-		$this->expectException(InvalidPath::class);
196
-
197
-		$path = '/foo\bar';
198
-
199
-
200
-		$storage = new Temporary([]);
201
-
202
-		$view = $this->getMockBuilder(View::class)
203
-			->onlyMethods(['resolvePath'])
204
-			->getMock();
205
-		$view->expects($this->once())
206
-			->method('resolvePath')
207
-			->willReturnCallback(function ($path) use ($storage) {
208
-				return [$storage, ltrim($path, '/')];
209
-			});
210
-
211
-		$rootNode = $this->createMock(Directory::class);
212
-		$mountManager = $this->createMock(IMountManager::class);
213
-
214
-		$tree = new ObjectTree();
215
-		$tree->init($rootNode, $view, $mountManager);
216
-
217
-		$tree->getNodeForPath($path);
218
-	}
219
-
220
-	public function testGetNodeForPathRoot(): void {
221
-		$path = '/';
222
-
223
-
224
-		$storage = new Temporary([]);
225
-
226
-		$view = $this->getMockBuilder(View::class)
227
-			->onlyMethods(['resolvePath'])
228
-			->getMock();
229
-		$view->expects($this->any())
230
-			->method('resolvePath')
231
-			->willReturnCallback(function ($path) use ($storage) {
232
-				return [$storage, ltrim($path, '/')];
233
-			});
234
-
235
-		$rootNode = $this->createMock(Directory::class);
236
-		$mountManager = $this->createMock(IMountManager::class);
237
-
238
-		$tree = new ObjectTree();
239
-		$tree->init($rootNode, $view, $mountManager);
240
-
241
-		$this->assertInstanceOf('\Sabre\DAV\INode', $tree->getNodeForPath($path));
242
-	}
31
+    public static function copyDataProvider(): array {
32
+        return [
33
+            // copy into same dir
34
+            ['a', 'b', ''],
35
+            // copy into same dir
36
+            ['a/a', 'a/b', 'a'],
37
+            // copy into another dir
38
+            ['a', 'sub/a', 'sub'],
39
+        ];
40
+    }
41
+
42
+    #[\PHPUnit\Framework\Attributes\DataProvider('copyDataProvider')]
43
+    public function testCopy(string $sourcePath, string $targetPath, string $targetParent): void {
44
+        $view = $this->createMock(View::class);
45
+        $view->expects($this->once())
46
+            ->method('verifyPath')
47
+            ->with($targetParent);
48
+        $view->expects($this->once())
49
+            ->method('file_exists')
50
+            ->with($targetPath)
51
+            ->willReturn(false);
52
+        $view->expects($this->once())
53
+            ->method('copy')
54
+            ->with($sourcePath, $targetPath)
55
+            ->willReturn(true);
56
+
57
+        $info = $this->createMock(FileInfo::class);
58
+        $info->expects($this->once())
59
+            ->method('isCreatable')
60
+            ->willReturn(true);
61
+
62
+        $view->expects($this->once())
63
+            ->method('getFileInfo')
64
+            ->with($targetParent === '' ? '.' : $targetParent)
65
+            ->willReturn($info);
66
+
67
+        $rootDir = new Directory($view, $info);
68
+        $objectTree = $this->getMockBuilder(ObjectTree::class)
69
+            ->onlyMethods(['nodeExists', 'getNodeForPath'])
70
+            ->setConstructorArgs([$rootDir, $view])
71
+            ->getMock();
72
+
73
+        $objectTree->expects($this->once())
74
+            ->method('getNodeForPath')
75
+            ->with($this->identicalTo($sourcePath))
76
+            ->willReturn(false);
77
+
78
+        /** @var ObjectTree $objectTree */
79
+        $mountManager = Filesystem::getMountManager();
80
+        $objectTree->init($rootDir, $view, $mountManager);
81
+        $objectTree->copy($sourcePath, $targetPath);
82
+    }
83
+
84
+    #[\PHPUnit\Framework\Attributes\DataProvider('copyDataProvider')]
85
+    public function testCopyFailNotCreatable($sourcePath, $targetPath, $targetParent): void {
86
+        $this->expectException(\Sabre\DAV\Exception\Forbidden::class);
87
+
88
+        $view = $this->createMock(View::class);
89
+        $view->expects($this->never())
90
+            ->method('verifyPath');
91
+        $view->expects($this->once())
92
+            ->method('file_exists')
93
+            ->with($targetPath)
94
+            ->willReturn(false);
95
+        $view->expects($this->never())
96
+            ->method('copy');
97
+
98
+        $info = $this->createMock(FileInfo::class);
99
+        $info->expects($this->once())
100
+            ->method('isCreatable')
101
+            ->willReturn(false);
102
+
103
+        $view->expects($this->once())
104
+            ->method('getFileInfo')
105
+            ->with($targetParent === '' ? '.' : $targetParent)
106
+            ->willReturn($info);
107
+
108
+        $rootDir = new Directory($view, $info);
109
+        $objectTree = $this->getMockBuilder(ObjectTree::class)
110
+            ->onlyMethods(['nodeExists', 'getNodeForPath'])
111
+            ->setConstructorArgs([$rootDir, $view])
112
+            ->getMock();
113
+
114
+        $objectTree->expects($this->never())
115
+            ->method('getNodeForPath');
116
+
117
+        /** @var ObjectTree $objectTree */
118
+        $mountManager = Filesystem::getMountManager();
119
+        $objectTree->init($rootDir, $view, $mountManager);
120
+        $objectTree->copy($sourcePath, $targetPath);
121
+    }
122
+
123
+    #[\PHPUnit\Framework\Attributes\DataProvider('nodeForPathProvider')]
124
+    public function testGetNodeForPath(
125
+        string $inputFileName,
126
+        string $fileInfoQueryPath,
127
+        string $outputFileName,
128
+        string $type,
129
+    ): void {
130
+        $rootNode = $this->createMock(Directory::class);
131
+        $mountManager = $this->createMock(Manager::class);
132
+        $view = $this->createMock(View::class);
133
+        $fileInfo = $this->createMock(FileInfo::class);
134
+        $fileInfo->method('getType')
135
+            ->willReturn($type);
136
+        $fileInfo->method('getName')
137
+            ->willReturn($outputFileName);
138
+        $fileInfo->method('getStorage')
139
+            ->willReturn($this->createMock(Common::class));
140
+
141
+        $view->method('getFileInfo')
142
+            ->with($fileInfoQueryPath)
143
+            ->willReturn($fileInfo);
144
+
145
+        $tree = new ObjectTree();
146
+        $tree->init($rootNode, $view, $mountManager);
147
+
148
+        $node = $tree->getNodeForPath($inputFileName);
149
+
150
+        $this->assertNotNull($node);
151
+        $this->assertEquals($outputFileName, $node->getName());
152
+
153
+        if ($type === 'file') {
154
+            $this->assertInstanceOf(File::class, $node);
155
+        } else {
156
+            $this->assertInstanceOf(Directory::class, $node);
157
+        }
158
+    }
159
+
160
+    public static function nodeForPathProvider(): array {
161
+        return [
162
+            // regular file
163
+            [
164
+                'regularfile.txt',
165
+                'regularfile.txt',
166
+                'regularfile.txt',
167
+                'file',
168
+            ],
169
+            // regular directory
170
+            [
171
+                'regulardir',
172
+                'regulardir',
173
+                'regulardir',
174
+                'dir',
175
+            ],
176
+            // regular file in subdir
177
+            [
178
+                'subdir/regularfile.txt',
179
+                'subdir/regularfile.txt',
180
+                'regularfile.txt',
181
+                'file',
182
+            ],
183
+            // regular directory in subdir
184
+            [
185
+                'subdir/regulardir',
186
+                'subdir/regulardir',
187
+                'regulardir',
188
+                'dir',
189
+            ],
190
+        ];
191
+    }
192
+
193
+
194
+    public function testGetNodeForPathInvalidPath(): void {
195
+        $this->expectException(InvalidPath::class);
196
+
197
+        $path = '/foo\bar';
198
+
199
+
200
+        $storage = new Temporary([]);
201
+
202
+        $view = $this->getMockBuilder(View::class)
203
+            ->onlyMethods(['resolvePath'])
204
+            ->getMock();
205
+        $view->expects($this->once())
206
+            ->method('resolvePath')
207
+            ->willReturnCallback(function ($path) use ($storage) {
208
+                return [$storage, ltrim($path, '/')];
209
+            });
210
+
211
+        $rootNode = $this->createMock(Directory::class);
212
+        $mountManager = $this->createMock(IMountManager::class);
213
+
214
+        $tree = new ObjectTree();
215
+        $tree->init($rootNode, $view, $mountManager);
216
+
217
+        $tree->getNodeForPath($path);
218
+    }
219
+
220
+    public function testGetNodeForPathRoot(): void {
221
+        $path = '/';
222
+
223
+
224
+        $storage = new Temporary([]);
225
+
226
+        $view = $this->getMockBuilder(View::class)
227
+            ->onlyMethods(['resolvePath'])
228
+            ->getMock();
229
+        $view->expects($this->any())
230
+            ->method('resolvePath')
231
+            ->willReturnCallback(function ($path) use ($storage) {
232
+                return [$storage, ltrim($path, '/')];
233
+            });
234
+
235
+        $rootNode = $this->createMock(Directory::class);
236
+        $mountManager = $this->createMock(IMountManager::class);
237
+
238
+        $tree = new ObjectTree();
239
+        $tree->init($rootNode, $view, $mountManager);
240
+
241
+        $this->assertInstanceOf('\Sabre\DAV\INode', $tree->getNodeForPath($path));
242
+    }
243 243
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Connector/Sabre/SharesPluginTest.php 1 patch
Indentation   +256 added lines, -256 removed lines patch added patch discarded remove patch
@@ -22,260 +22,260 @@
 block discarded – undo
22 22
 use Sabre\DAV\Tree;
23 23
 
24 24
 class SharesPluginTest extends \Test\TestCase {
25
-	public const SHARETYPES_PROPERTYNAME = SharesPlugin::SHARETYPES_PROPERTYNAME;
26
-
27
-	private \Sabre\DAV\Server $server;
28
-	private \Sabre\DAV\Tree&MockObject $tree;
29
-	private \OCP\Share\IManager&MockObject $shareManager;
30
-	private Folder&MockObject $userFolder;
31
-	private SharesPlugin $plugin;
32
-
33
-	protected function setUp(): void {
34
-		parent::setUp();
35
-		$this->server = new \Sabre\DAV\Server();
36
-		$this->tree = $this->createMock(Tree::class);
37
-		$this->shareManager = $this->createMock(IManager::class);
38
-		$user = $this->createMock(IUser::class);
39
-		$user->expects($this->once())
40
-			->method('getUID')
41
-			->willReturn('user1');
42
-		$userSession = $this->createMock(IUserSession::class);
43
-		$userSession->expects($this->once())
44
-			->method('getUser')
45
-			->willReturn($user);
46
-		$this->userFolder = $this->createMock(Folder::class);
47
-
48
-		$this->plugin = new SharesPlugin(
49
-			$this->tree,
50
-			$userSession,
51
-			$this->userFolder,
52
-			$this->shareManager
53
-		);
54
-		$this->plugin->initialize($this->server);
55
-	}
56
-
57
-	#[\PHPUnit\Framework\Attributes\DataProvider('sharesGetPropertiesDataProvider')]
58
-	public function testGetProperties(array $shareTypes): void {
59
-		$sabreNode = $this->createMock(Node::class);
60
-		$sabreNode->expects($this->any())
61
-			->method('getId')
62
-			->willReturn(123);
63
-		$sabreNode->expects($this->any())
64
-			->method('getPath')
65
-			->willReturn('/subdir');
66
-
67
-		// node API nodes
68
-		$node = $this->createMock(Folder::class);
69
-
70
-		$sabreNode->method('getNode')
71
-			->willReturn($node);
72
-
73
-		$this->shareManager->expects($this->any())
74
-			->method('getSharesBy')
75
-			->with(
76
-				$this->equalTo('user1'),
77
-				$this->anything(),
78
-				$this->equalTo($node),
79
-				$this->equalTo(false),
80
-				$this->equalTo(-1)
81
-			)
82
-			->willReturnCallback(function ($userId, $requestedShareType, $node, $flag, $limit) use ($shareTypes) {
83
-				if (in_array($requestedShareType, $shareTypes)) {
84
-					$share = $this->createMock(IShare::class);
85
-					$share->method('getShareType')
86
-						->willReturn($requestedShareType);
87
-					return [$share];
88
-				}
89
-				return [];
90
-			});
91
-
92
-		$this->shareManager->expects($this->any())
93
-			->method('getSharedWith')
94
-			->with(
95
-				$this->equalTo('user1'),
96
-				$this->anything(),
97
-				$this->equalTo($node),
98
-				$this->equalTo(-1)
99
-			)
100
-			->willReturn([]);
101
-
102
-		$propFind = new \Sabre\DAV\PropFind(
103
-			'/dummyPath',
104
-			[self::SHARETYPES_PROPERTYNAME],
105
-			0
106
-		);
107
-
108
-		$this->plugin->handleGetProperties(
109
-			$propFind,
110
-			$sabreNode
111
-		);
112
-
113
-		$result = $propFind->getResultForMultiStatus();
114
-
115
-		$this->assertEmpty($result[404]);
116
-		unset($result[404]);
117
-		$this->assertEquals($shareTypes, $result[200][self::SHARETYPES_PROPERTYNAME]->getShareTypes());
118
-	}
119
-
120
-	#[\PHPUnit\Framework\Attributes\DataProvider('sharesGetPropertiesDataProvider')]
121
-	public function testPreloadThenGetProperties(array $shareTypes): void {
122
-		$sabreNode1 = $this->createMock(File::class);
123
-		$sabreNode1->method('getId')
124
-			->willReturn(111);
125
-		$sabreNode2 = $this->createMock(File::class);
126
-		$sabreNode2->method('getId')
127
-			->willReturn(222);
128
-		$sabreNode2->method('getPath')
129
-			->willReturn('/subdir/foo');
130
-
131
-		$sabreNode = $this->createMock(Directory::class);
132
-		$sabreNode->method('getId')
133
-			->willReturn(123);
134
-		// never, because we use getDirectoryListing from the Node API instead
135
-		$sabreNode->expects($this->never())
136
-			->method('getChildren');
137
-		$sabreNode->expects($this->any())
138
-			->method('getPath')
139
-			->willReturn('/subdir');
140
-
141
-		// node API nodes
142
-		$node = $this->createMock(Folder::class);
143
-		$node->method('getId')
144
-			->willReturn(123);
145
-		$node1 = $this->createMock(\OC\Files\Node\File::class);
146
-		$node1->method('getId')
147
-			->willReturn(111);
148
-		$node2 = $this->createMock(\OC\Files\Node\File::class);
149
-		$node2->method('getId')
150
-			->willReturn(222);
151
-
152
-		$sabreNode->method('getNode')
153
-			->willReturn($node);
154
-		$sabreNode1->method('getNode')
155
-			->willReturn($node1);
156
-		$sabreNode2->method('getNode')
157
-			->willReturn($node2);
158
-
159
-		$dummyShares = array_map(function ($type) {
160
-			$share = $this->createMock(IShare::class);
161
-			$share->expects($this->any())
162
-				->method('getShareType')
163
-				->willReturn($type);
164
-			return $share;
165
-		}, $shareTypes);
166
-
167
-		$this->shareManager->expects($this->any())
168
-			->method('getSharesBy')
169
-			->with(
170
-				$this->equalTo('user1'),
171
-				$this->anything(),
172
-				$this->anything(),
173
-				$this->equalTo(false),
174
-				$this->equalTo(-1)
175
-			)
176
-			->willReturnCallback(function ($userId, $requestedShareType, $node, $flag, $limit) use ($shareTypes, $dummyShares) {
177
-				if ($node->getId() === 111 && in_array($requestedShareType, $shareTypes)) {
178
-					foreach ($dummyShares as $dummyShare) {
179
-						if ($dummyShare->getShareType() === $requestedShareType) {
180
-							return [$dummyShare];
181
-						}
182
-					}
183
-				}
184
-
185
-				return [];
186
-			});
187
-
188
-		$this->shareManager->expects($this->any())
189
-			->method('getSharedWith')
190
-			->with(
191
-				$this->equalTo('user1'),
192
-				$this->anything(),
193
-				$this->equalTo($node),
194
-				$this->equalTo(-1)
195
-			)
196
-			->willReturn([]);
197
-
198
-		$this->shareManager->expects($this->any())
199
-			->method('getSharesInFolder')
200
-			->with(
201
-				$this->equalTo('user1'),
202
-				$this->anything(),
203
-				$this->equalTo(true)
204
-			)
205
-			->willReturnCallback(function ($userId, $node, $flag) use ($shareTypes, $dummyShares) {
206
-				return [111 => $dummyShares];
207
-			});
208
-
209
-		// simulate sabre recursive PROPFIND traversal
210
-		$propFindRoot = new \Sabre\DAV\PropFind(
211
-			'/subdir',
212
-			[self::SHARETYPES_PROPERTYNAME],
213
-			1
214
-		);
215
-		$propFind1 = new \Sabre\DAV\PropFind(
216
-			'/subdir/test.txt',
217
-			[self::SHARETYPES_PROPERTYNAME],
218
-			0
219
-		);
220
-		$propFind2 = new \Sabre\DAV\PropFind(
221
-			'/subdir/test2.txt',
222
-			[self::SHARETYPES_PROPERTYNAME],
223
-			0
224
-		);
225
-
226
-		$this->plugin->handleGetProperties(
227
-			$propFindRoot,
228
-			$sabreNode
229
-		);
230
-		$this->plugin->handleGetProperties(
231
-			$propFind1,
232
-			$sabreNode1
233
-		);
234
-		$this->plugin->handleGetProperties(
235
-			$propFind2,
236
-			$sabreNode2
237
-		);
238
-
239
-		$result = $propFind1->getResultForMultiStatus();
240
-
241
-		$this->assertEmpty($result[404]);
242
-		unset($result[404]);
243
-		$this->assertEquals($shareTypes, $result[200][self::SHARETYPES_PROPERTYNAME]->getShareTypes());
244
-	}
245
-
246
-	public static function sharesGetPropertiesDataProvider(): array {
247
-		return [
248
-			[[]],
249
-			[[IShare::TYPE_USER]],
250
-			[[IShare::TYPE_GROUP]],
251
-			[[IShare::TYPE_LINK]],
252
-			[[IShare::TYPE_REMOTE]],
253
-			[[IShare::TYPE_ROOM]],
254
-			[[IShare::TYPE_DECK]],
255
-			[[IShare::TYPE_SCIENCEMESH]],
256
-			[[IShare::TYPE_USER, IShare::TYPE_GROUP]],
257
-			[[IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK]],
258
-			[[IShare::TYPE_USER, IShare::TYPE_LINK]],
259
-			[[IShare::TYPE_GROUP, IShare::TYPE_LINK]],
260
-			[[IShare::TYPE_USER, IShare::TYPE_REMOTE]],
261
-		];
262
-	}
263
-
264
-	public function testGetPropertiesSkipChunks(): void {
265
-		$sabreNode = $this->createMock(UploadFile::class);
266
-
267
-		$propFind = new \Sabre\DAV\PropFind(
268
-			'/dummyPath',
269
-			[self::SHARETYPES_PROPERTYNAME],
270
-			0
271
-		);
272
-
273
-		$this->plugin->handleGetProperties(
274
-			$propFind,
275
-			$sabreNode
276
-		);
277
-
278
-		$result = $propFind->getResultForMultiStatus();
279
-		$this->assertCount(1, $result[404]);
280
-	}
25
+    public const SHARETYPES_PROPERTYNAME = SharesPlugin::SHARETYPES_PROPERTYNAME;
26
+
27
+    private \Sabre\DAV\Server $server;
28
+    private \Sabre\DAV\Tree&MockObject $tree;
29
+    private \OCP\Share\IManager&MockObject $shareManager;
30
+    private Folder&MockObject $userFolder;
31
+    private SharesPlugin $plugin;
32
+
33
+    protected function setUp(): void {
34
+        parent::setUp();
35
+        $this->server = new \Sabre\DAV\Server();
36
+        $this->tree = $this->createMock(Tree::class);
37
+        $this->shareManager = $this->createMock(IManager::class);
38
+        $user = $this->createMock(IUser::class);
39
+        $user->expects($this->once())
40
+            ->method('getUID')
41
+            ->willReturn('user1');
42
+        $userSession = $this->createMock(IUserSession::class);
43
+        $userSession->expects($this->once())
44
+            ->method('getUser')
45
+            ->willReturn($user);
46
+        $this->userFolder = $this->createMock(Folder::class);
47
+
48
+        $this->plugin = new SharesPlugin(
49
+            $this->tree,
50
+            $userSession,
51
+            $this->userFolder,
52
+            $this->shareManager
53
+        );
54
+        $this->plugin->initialize($this->server);
55
+    }
56
+
57
+    #[\PHPUnit\Framework\Attributes\DataProvider('sharesGetPropertiesDataProvider')]
58
+    public function testGetProperties(array $shareTypes): void {
59
+        $sabreNode = $this->createMock(Node::class);
60
+        $sabreNode->expects($this->any())
61
+            ->method('getId')
62
+            ->willReturn(123);
63
+        $sabreNode->expects($this->any())
64
+            ->method('getPath')
65
+            ->willReturn('/subdir');
66
+
67
+        // node API nodes
68
+        $node = $this->createMock(Folder::class);
69
+
70
+        $sabreNode->method('getNode')
71
+            ->willReturn($node);
72
+
73
+        $this->shareManager->expects($this->any())
74
+            ->method('getSharesBy')
75
+            ->with(
76
+                $this->equalTo('user1'),
77
+                $this->anything(),
78
+                $this->equalTo($node),
79
+                $this->equalTo(false),
80
+                $this->equalTo(-1)
81
+            )
82
+            ->willReturnCallback(function ($userId, $requestedShareType, $node, $flag, $limit) use ($shareTypes) {
83
+                if (in_array($requestedShareType, $shareTypes)) {
84
+                    $share = $this->createMock(IShare::class);
85
+                    $share->method('getShareType')
86
+                        ->willReturn($requestedShareType);
87
+                    return [$share];
88
+                }
89
+                return [];
90
+            });
91
+
92
+        $this->shareManager->expects($this->any())
93
+            ->method('getSharedWith')
94
+            ->with(
95
+                $this->equalTo('user1'),
96
+                $this->anything(),
97
+                $this->equalTo($node),
98
+                $this->equalTo(-1)
99
+            )
100
+            ->willReturn([]);
101
+
102
+        $propFind = new \Sabre\DAV\PropFind(
103
+            '/dummyPath',
104
+            [self::SHARETYPES_PROPERTYNAME],
105
+            0
106
+        );
107
+
108
+        $this->plugin->handleGetProperties(
109
+            $propFind,
110
+            $sabreNode
111
+        );
112
+
113
+        $result = $propFind->getResultForMultiStatus();
114
+
115
+        $this->assertEmpty($result[404]);
116
+        unset($result[404]);
117
+        $this->assertEquals($shareTypes, $result[200][self::SHARETYPES_PROPERTYNAME]->getShareTypes());
118
+    }
119
+
120
+    #[\PHPUnit\Framework\Attributes\DataProvider('sharesGetPropertiesDataProvider')]
121
+    public function testPreloadThenGetProperties(array $shareTypes): void {
122
+        $sabreNode1 = $this->createMock(File::class);
123
+        $sabreNode1->method('getId')
124
+            ->willReturn(111);
125
+        $sabreNode2 = $this->createMock(File::class);
126
+        $sabreNode2->method('getId')
127
+            ->willReturn(222);
128
+        $sabreNode2->method('getPath')
129
+            ->willReturn('/subdir/foo');
130
+
131
+        $sabreNode = $this->createMock(Directory::class);
132
+        $sabreNode->method('getId')
133
+            ->willReturn(123);
134
+        // never, because we use getDirectoryListing from the Node API instead
135
+        $sabreNode->expects($this->never())
136
+            ->method('getChildren');
137
+        $sabreNode->expects($this->any())
138
+            ->method('getPath')
139
+            ->willReturn('/subdir');
140
+
141
+        // node API nodes
142
+        $node = $this->createMock(Folder::class);
143
+        $node->method('getId')
144
+            ->willReturn(123);
145
+        $node1 = $this->createMock(\OC\Files\Node\File::class);
146
+        $node1->method('getId')
147
+            ->willReturn(111);
148
+        $node2 = $this->createMock(\OC\Files\Node\File::class);
149
+        $node2->method('getId')
150
+            ->willReturn(222);
151
+
152
+        $sabreNode->method('getNode')
153
+            ->willReturn($node);
154
+        $sabreNode1->method('getNode')
155
+            ->willReturn($node1);
156
+        $sabreNode2->method('getNode')
157
+            ->willReturn($node2);
158
+
159
+        $dummyShares = array_map(function ($type) {
160
+            $share = $this->createMock(IShare::class);
161
+            $share->expects($this->any())
162
+                ->method('getShareType')
163
+                ->willReturn($type);
164
+            return $share;
165
+        }, $shareTypes);
166
+
167
+        $this->shareManager->expects($this->any())
168
+            ->method('getSharesBy')
169
+            ->with(
170
+                $this->equalTo('user1'),
171
+                $this->anything(),
172
+                $this->anything(),
173
+                $this->equalTo(false),
174
+                $this->equalTo(-1)
175
+            )
176
+            ->willReturnCallback(function ($userId, $requestedShareType, $node, $flag, $limit) use ($shareTypes, $dummyShares) {
177
+                if ($node->getId() === 111 && in_array($requestedShareType, $shareTypes)) {
178
+                    foreach ($dummyShares as $dummyShare) {
179
+                        if ($dummyShare->getShareType() === $requestedShareType) {
180
+                            return [$dummyShare];
181
+                        }
182
+                    }
183
+                }
184
+
185
+                return [];
186
+            });
187
+
188
+        $this->shareManager->expects($this->any())
189
+            ->method('getSharedWith')
190
+            ->with(
191
+                $this->equalTo('user1'),
192
+                $this->anything(),
193
+                $this->equalTo($node),
194
+                $this->equalTo(-1)
195
+            )
196
+            ->willReturn([]);
197
+
198
+        $this->shareManager->expects($this->any())
199
+            ->method('getSharesInFolder')
200
+            ->with(
201
+                $this->equalTo('user1'),
202
+                $this->anything(),
203
+                $this->equalTo(true)
204
+            )
205
+            ->willReturnCallback(function ($userId, $node, $flag) use ($shareTypes, $dummyShares) {
206
+                return [111 => $dummyShares];
207
+            });
208
+
209
+        // simulate sabre recursive PROPFIND traversal
210
+        $propFindRoot = new \Sabre\DAV\PropFind(
211
+            '/subdir',
212
+            [self::SHARETYPES_PROPERTYNAME],
213
+            1
214
+        );
215
+        $propFind1 = new \Sabre\DAV\PropFind(
216
+            '/subdir/test.txt',
217
+            [self::SHARETYPES_PROPERTYNAME],
218
+            0
219
+        );
220
+        $propFind2 = new \Sabre\DAV\PropFind(
221
+            '/subdir/test2.txt',
222
+            [self::SHARETYPES_PROPERTYNAME],
223
+            0
224
+        );
225
+
226
+        $this->plugin->handleGetProperties(
227
+            $propFindRoot,
228
+            $sabreNode
229
+        );
230
+        $this->plugin->handleGetProperties(
231
+            $propFind1,
232
+            $sabreNode1
233
+        );
234
+        $this->plugin->handleGetProperties(
235
+            $propFind2,
236
+            $sabreNode2
237
+        );
238
+
239
+        $result = $propFind1->getResultForMultiStatus();
240
+
241
+        $this->assertEmpty($result[404]);
242
+        unset($result[404]);
243
+        $this->assertEquals($shareTypes, $result[200][self::SHARETYPES_PROPERTYNAME]->getShareTypes());
244
+    }
245
+
246
+    public static function sharesGetPropertiesDataProvider(): array {
247
+        return [
248
+            [[]],
249
+            [[IShare::TYPE_USER]],
250
+            [[IShare::TYPE_GROUP]],
251
+            [[IShare::TYPE_LINK]],
252
+            [[IShare::TYPE_REMOTE]],
253
+            [[IShare::TYPE_ROOM]],
254
+            [[IShare::TYPE_DECK]],
255
+            [[IShare::TYPE_SCIENCEMESH]],
256
+            [[IShare::TYPE_USER, IShare::TYPE_GROUP]],
257
+            [[IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK]],
258
+            [[IShare::TYPE_USER, IShare::TYPE_LINK]],
259
+            [[IShare::TYPE_GROUP, IShare::TYPE_LINK]],
260
+            [[IShare::TYPE_USER, IShare::TYPE_REMOTE]],
261
+        ];
262
+    }
263
+
264
+    public function testGetPropertiesSkipChunks(): void {
265
+        $sabreNode = $this->createMock(UploadFile::class);
266
+
267
+        $propFind = new \Sabre\DAV\PropFind(
268
+            '/dummyPath',
269
+            [self::SHARETYPES_PROPERTYNAME],
270
+            0
271
+        );
272
+
273
+        $this->plugin->handleGetProperties(
274
+            $propFind,
275
+            $sabreNode
276
+        );
277
+
278
+        $result = $propFind->getResultForMultiStatus();
279
+        $this->assertCount(1, $result[404]);
280
+    }
281 281
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Connector/Sabre/FakeLockerPluginTest.php 2 patches
Indentation   +134 added lines, -134 removed lines patch added patch discarded remove patch
@@ -23,138 +23,138 @@
 block discarded – undo
23 23
  * @package OCA\DAV\Tests\unit\Connector\Sabre
24 24
  */
25 25
 class FakeLockerPluginTest extends TestCase {
26
-	private FakeLockerPlugin $fakeLockerPlugin;
27
-
28
-	protected function setUp(): void {
29
-		parent::setUp();
30
-		$this->fakeLockerPlugin = new FakeLockerPlugin();
31
-	}
32
-
33
-	public function testInitialize(): void {
34
-		/** @var Server $server */
35
-		$server = $this->createMock(Server::class);
36
-		$calls = [
37
-			['method:LOCK', [$this->fakeLockerPlugin, 'fakeLockProvider'], 1],
38
-			['method:UNLOCK', [$this->fakeLockerPlugin, 'fakeUnlockProvider'], 1],
39
-			['propFind', [$this->fakeLockerPlugin, 'propFind'], 100],
40
-			['validateTokens', [$this->fakeLockerPlugin, 'validateTokens'], 100],
41
-		];
42
-		$server->expects($this->exactly(count($calls)))
43
-			->method('on')
44
-			->willReturnCallback(function () use (&$calls): void {
45
-				$expected = array_shift($calls);
46
-				$this->assertEquals($expected, func_get_args());
47
-			});
48
-
49
-		$this->fakeLockerPlugin->initialize($server);
50
-	}
51
-
52
-	public function testGetHTTPMethods(): void {
53
-		$expected = [
54
-			'LOCK',
55
-			'UNLOCK',
56
-		];
57
-		$this->assertSame($expected, $this->fakeLockerPlugin->getHTTPMethods('Test'));
58
-	}
59
-
60
-	public function testGetFeatures(): void {
61
-		$expected = [
62
-			2,
63
-		];
64
-		$this->assertSame($expected, $this->fakeLockerPlugin->getFeatures());
65
-	}
66
-
67
-	public function testPropFind(): void {
68
-		$propFind = $this->createMock(PropFind::class);
69
-		$node = $this->createMock(INode::class);
70
-
71
-		$calls = [
72
-			'{DAV:}supportedlock',
73
-			'{DAV:}lockdiscovery',
74
-		];
75
-		$propFind->expects($this->exactly(count($calls)))
76
-			->method('handle')
77
-			->willReturnCallback(function ($propertyName) use (&$calls): void {
78
-				$expected = array_shift($calls);
79
-				$this->assertEquals($expected, $propertyName);
80
-			});
81
-
82
-		$this->fakeLockerPlugin->propFind($propFind, $node);
83
-	}
84
-
85
-	public static function tokenDataProvider(): array {
86
-		return [
87
-			[
88
-				[
89
-					[
90
-						'tokens' => [
91
-							[
92
-								'token' => 'aToken',
93
-								'validToken' => false,
94
-							],
95
-							[],
96
-							[
97
-								'token' => 'opaquelocktoken:asdf',
98
-								'validToken' => false,
99
-							]
100
-						],
101
-					]
102
-				],
103
-				[
104
-					[
105
-						'tokens' => [
106
-							[
107
-								'token' => 'aToken',
108
-								'validToken' => false,
109
-							],
110
-							[],
111
-							[
112
-								'token' => 'opaquelocktoken:asdf',
113
-								'validToken' => true,
114
-							]
115
-						],
116
-					]
117
-				],
118
-			]
119
-		];
120
-	}
121
-
122
-	#[\PHPUnit\Framework\Attributes\DataProvider('tokenDataProvider')]
123
-	public function testValidateTokens(array $input, array $expected): void {
124
-		$request = $this->createMock(RequestInterface::class);
125
-		$this->fakeLockerPlugin->validateTokens($request, $input);
126
-		$this->assertSame($expected, $input);
127
-	}
128
-
129
-	public function testFakeLockProvider(): void {
130
-		$request = $this->createMock(RequestInterface::class);
131
-		$response = new Response();
132
-		$server = $this->getMockBuilder(Server::class)
133
-			->getMock();
134
-		$this->fakeLockerPlugin->initialize($server);
135
-
136
-		$request->expects($this->exactly(2))
137
-			->method('getPath')
138
-			->willReturn('MyPath');
139
-
140
-		$this->assertSame(false, $this->fakeLockerPlugin->fakeLockProvider($request, $response));
141
-
142
-		$expectedXml = '<?xml version="1.0" encoding="utf-8"?><d:prop xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"><d:lockdiscovery><d:activelock><d:lockscope><d:exclusive/></d:lockscope><d:locktype><d:write/></d:locktype><d:lockroot><d:href>MyPath</d:href></d:lockroot><d:depth>infinity</d:depth><d:timeout>Second-1800</d:timeout><d:locktoken><d:href>opaquelocktoken:fe4f7f2437b151fbcb4e9f5c8118c6b1</d:href></d:locktoken></d:activelock></d:lockdiscovery></d:prop>';
143
-
144
-		$this->assertXmlStringEqualsXmlString($expectedXml, $response->getBody());
145
-	}
146
-
147
-	public function testFakeUnlockProvider(): void {
148
-		$request = $this->createMock(RequestInterface::class);
149
-		$response = $this->createMock(ResponseInterface::class);
150
-
151
-		$response->expects($this->once())
152
-			->method('setStatus')
153
-			->with('204');
154
-		$response->expects($this->once())
155
-			->method('setHeader')
156
-			->with('Content-Length', '0');
157
-
158
-		$this->assertSame(false, $this->fakeLockerPlugin->fakeUnlockProvider($request, $response));
159
-	}
26
+    private FakeLockerPlugin $fakeLockerPlugin;
27
+
28
+    protected function setUp(): void {
29
+        parent::setUp();
30
+        $this->fakeLockerPlugin = new FakeLockerPlugin();
31
+    }
32
+
33
+    public function testInitialize(): void {
34
+        /** @var Server $server */
35
+        $server = $this->createMock(Server::class);
36
+        $calls = [
37
+            ['method:LOCK', [$this->fakeLockerPlugin, 'fakeLockProvider'], 1],
38
+            ['method:UNLOCK', [$this->fakeLockerPlugin, 'fakeUnlockProvider'], 1],
39
+            ['propFind', [$this->fakeLockerPlugin, 'propFind'], 100],
40
+            ['validateTokens', [$this->fakeLockerPlugin, 'validateTokens'], 100],
41
+        ];
42
+        $server->expects($this->exactly(count($calls)))
43
+            ->method('on')
44
+            ->willReturnCallback(function () use (&$calls): void {
45
+                $expected = array_shift($calls);
46
+                $this->assertEquals($expected, func_get_args());
47
+            });
48
+
49
+        $this->fakeLockerPlugin->initialize($server);
50
+    }
51
+
52
+    public function testGetHTTPMethods(): void {
53
+        $expected = [
54
+            'LOCK',
55
+            'UNLOCK',
56
+        ];
57
+        $this->assertSame($expected, $this->fakeLockerPlugin->getHTTPMethods('Test'));
58
+    }
59
+
60
+    public function testGetFeatures(): void {
61
+        $expected = [
62
+            2,
63
+        ];
64
+        $this->assertSame($expected, $this->fakeLockerPlugin->getFeatures());
65
+    }
66
+
67
+    public function testPropFind(): void {
68
+        $propFind = $this->createMock(PropFind::class);
69
+        $node = $this->createMock(INode::class);
70
+
71
+        $calls = [
72
+            '{DAV:}supportedlock',
73
+            '{DAV:}lockdiscovery',
74
+        ];
75
+        $propFind->expects($this->exactly(count($calls)))
76
+            ->method('handle')
77
+            ->willReturnCallback(function ($propertyName) use (&$calls): void {
78
+                $expected = array_shift($calls);
79
+                $this->assertEquals($expected, $propertyName);
80
+            });
81
+
82
+        $this->fakeLockerPlugin->propFind($propFind, $node);
83
+    }
84
+
85
+    public static function tokenDataProvider(): array {
86
+        return [
87
+            [
88
+                [
89
+                    [
90
+                        'tokens' => [
91
+                            [
92
+                                'token' => 'aToken',
93
+                                'validToken' => false,
94
+                            ],
95
+                            [],
96
+                            [
97
+                                'token' => 'opaquelocktoken:asdf',
98
+                                'validToken' => false,
99
+                            ]
100
+                        ],
101
+                    ]
102
+                ],
103
+                [
104
+                    [
105
+                        'tokens' => [
106
+                            [
107
+                                'token' => 'aToken',
108
+                                'validToken' => false,
109
+                            ],
110
+                            [],
111
+                            [
112
+                                'token' => 'opaquelocktoken:asdf',
113
+                                'validToken' => true,
114
+                            ]
115
+                        ],
116
+                    ]
117
+                ],
118
+            ]
119
+        ];
120
+    }
121
+
122
+    #[\PHPUnit\Framework\Attributes\DataProvider('tokenDataProvider')]
123
+    public function testValidateTokens(array $input, array $expected): void {
124
+        $request = $this->createMock(RequestInterface::class);
125
+        $this->fakeLockerPlugin->validateTokens($request, $input);
126
+        $this->assertSame($expected, $input);
127
+    }
128
+
129
+    public function testFakeLockProvider(): void {
130
+        $request = $this->createMock(RequestInterface::class);
131
+        $response = new Response();
132
+        $server = $this->getMockBuilder(Server::class)
133
+            ->getMock();
134
+        $this->fakeLockerPlugin->initialize($server);
135
+
136
+        $request->expects($this->exactly(2))
137
+            ->method('getPath')
138
+            ->willReturn('MyPath');
139
+
140
+        $this->assertSame(false, $this->fakeLockerPlugin->fakeLockProvider($request, $response));
141
+
142
+        $expectedXml = '<?xml version="1.0" encoding="utf-8"?><d:prop xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"><d:lockdiscovery><d:activelock><d:lockscope><d:exclusive/></d:lockscope><d:locktype><d:write/></d:locktype><d:lockroot><d:href>MyPath</d:href></d:lockroot><d:depth>infinity</d:depth><d:timeout>Second-1800</d:timeout><d:locktoken><d:href>opaquelocktoken:fe4f7f2437b151fbcb4e9f5c8118c6b1</d:href></d:locktoken></d:activelock></d:lockdiscovery></d:prop>';
143
+
144
+        $this->assertXmlStringEqualsXmlString($expectedXml, $response->getBody());
145
+    }
146
+
147
+    public function testFakeUnlockProvider(): void {
148
+        $request = $this->createMock(RequestInterface::class);
149
+        $response = $this->createMock(ResponseInterface::class);
150
+
151
+        $response->expects($this->once())
152
+            ->method('setStatus')
153
+            ->with('204');
154
+        $response->expects($this->once())
155
+            ->method('setHeader')
156
+            ->with('Content-Length', '0');
157
+
158
+        $this->assertSame(false, $this->fakeLockerPlugin->fakeUnlockProvider($request, $response));
159
+    }
160 160
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -41,7 +41,7 @@  discard block
 block discarded – undo
41 41
 		];
42 42
 		$server->expects($this->exactly(count($calls)))
43 43
 			->method('on')
44
-			->willReturnCallback(function () use (&$calls): void {
44
+			->willReturnCallback(function() use (&$calls): void {
45 45
 				$expected = array_shift($calls);
46 46
 				$this->assertEquals($expected, func_get_args());
47 47
 			});
@@ -74,7 +74,7 @@  discard block
 block discarded – undo
74 74
 		];
75 75
 		$propFind->expects($this->exactly(count($calls)))
76 76
 			->method('handle')
77
-			->willReturnCallback(function ($propertyName) use (&$calls): void {
77
+			->willReturnCallback(function($propertyName) use (&$calls): void {
78 78
 				$expected = array_shift($calls);
79 79
 				$this->assertEquals($expected, $propertyName);
80 80
 			});
Please login to merge, or discard this patch.
apps/dav/tests/unit/Connector/Sabre/DirectoryTest.php 1 patch
Indentation   +414 added lines, -414 removed lines patch added patch discarded remove patch
@@ -26,32 +26,32 @@  discard block
 block discarded – undo
26 26
 use Test\Traits\UserTrait;
27 27
 
28 28
 class TestViewDirectory extends View {
29
-	public function __construct(
30
-		private $updatables,
31
-		private $deletables,
32
-		private $canRename = true,
33
-	) {
34
-	}
35
-
36
-	public function isUpdatable($path) {
37
-		return $this->updatables[$path];
38
-	}
39
-
40
-	public function isCreatable($path) {
41
-		return $this->updatables[$path];
42
-	}
43
-
44
-	public function isDeletable($path) {
45
-		return $this->deletables[$path];
46
-	}
47
-
48
-	public function rename($source, $target, array $options = []) {
49
-		return $this->canRename;
50
-	}
51
-
52
-	public function getRelativePath($path): ?string {
53
-		return $path;
54
-	}
29
+    public function __construct(
30
+        private $updatables,
31
+        private $deletables,
32
+        private $canRename = true,
33
+    ) {
34
+    }
35
+
36
+    public function isUpdatable($path) {
37
+        return $this->updatables[$path];
38
+    }
39
+
40
+    public function isCreatable($path) {
41
+        return $this->updatables[$path];
42
+    }
43
+
44
+    public function isDeletable($path) {
45
+        return $this->deletables[$path];
46
+    }
47
+
48
+    public function rename($source, $target, array $options = []) {
49
+        return $this->canRename;
50
+    }
51
+
52
+    public function getRelativePath($path): ?string {
53
+        return $path;
54
+    }
55 55
 }
56 56
 
57 57
 
@@ -59,410 +59,410 @@  discard block
 block discarded – undo
59 59
  * @group DB
60 60
  */
61 61
 class DirectoryTest extends \Test\TestCase {
62
-	use UserTrait;
62
+    use UserTrait;
63 63
 
64
-	private View&MockObject $view;
65
-	private FileInfo&MockObject $info;
64
+    private View&MockObject $view;
65
+    private FileInfo&MockObject $info;
66 66
 
67
-	protected function setUp(): void {
68
-		parent::setUp();
69
-
70
-		$this->view = $this->createMock(View::class);
71
-		$this->info = $this->createMock(FileInfo::class);
72
-		$this->info->method('isReadable')
73
-			->willReturn(true);
74
-		$this->info->method('getType')
75
-			->willReturn(Node::TYPE_FOLDER);
76
-		$this->info->method('getName')
77
-			->willReturn('folder');
78
-		$this->info->method('getPath')
79
-			->willReturn('/admin/files/folder');
80
-		$this->info->method('getPermissions')
81
-			->willReturn(Constants::PERMISSION_READ);
82
-	}
83
-
84
-	private function getDir(string $path = '/'): Directory {
85
-		$this->view->expects($this->once())
86
-			->method('getRelativePath')
87
-			->willReturn($path);
88
-
89
-		$this->info->expects($this->once())
90
-			->method('getPath')
91
-			->willReturn($path);
92
-
93
-		return new Directory($this->view, $this->info);
94
-	}
95
-
96
-
97
-	public function testDeleteRootFolderFails(): void {
98
-		$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
99
-
100
-		$this->info->expects($this->any())
101
-			->method('isDeletable')
102
-			->willReturn(true);
103
-		$this->view->expects($this->never())
104
-			->method('rmdir');
105
-		$dir = $this->getDir();
106
-		$dir->delete();
107
-	}
108
-
109
-
110
-	public function testDeleteForbidden(): void {
111
-		$this->expectException(Forbidden::class);
112
-
113
-		// deletion allowed
114
-		$this->info->expects($this->once())
115
-			->method('isDeletable')
116
-			->willReturn(true);
117
-
118
-		// but fails
119
-		$this->view->expects($this->once())
120
-			->method('rmdir')
121
-			->with('sub')
122
-			->willThrowException(new ForbiddenException('', true));
123
-
124
-		$dir = $this->getDir('sub');
125
-		$dir->delete();
126
-	}
127
-
128
-
129
-	public function testDeleteFolderWhenAllowed(): void {
130
-		// deletion allowed
131
-		$this->info->expects($this->once())
132
-			->method('isDeletable')
133
-			->willReturn(true);
134
-
135
-		// but fails
136
-		$this->view->expects($this->once())
137
-			->method('rmdir')
138
-			->with('sub')
139
-			->willReturn(true);
140
-
141
-		$dir = $this->getDir('sub');
142
-		$dir->delete();
143
-	}
144
-
145
-
146
-	public function testDeleteFolderFailsWhenNotAllowed(): void {
147
-		$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
67
+    protected function setUp(): void {
68
+        parent::setUp();
69
+
70
+        $this->view = $this->createMock(View::class);
71
+        $this->info = $this->createMock(FileInfo::class);
72
+        $this->info->method('isReadable')
73
+            ->willReturn(true);
74
+        $this->info->method('getType')
75
+            ->willReturn(Node::TYPE_FOLDER);
76
+        $this->info->method('getName')
77
+            ->willReturn('folder');
78
+        $this->info->method('getPath')
79
+            ->willReturn('/admin/files/folder');
80
+        $this->info->method('getPermissions')
81
+            ->willReturn(Constants::PERMISSION_READ);
82
+    }
83
+
84
+    private function getDir(string $path = '/'): Directory {
85
+        $this->view->expects($this->once())
86
+            ->method('getRelativePath')
87
+            ->willReturn($path);
88
+
89
+        $this->info->expects($this->once())
90
+            ->method('getPath')
91
+            ->willReturn($path);
92
+
93
+        return new Directory($this->view, $this->info);
94
+    }
95
+
96
+
97
+    public function testDeleteRootFolderFails(): void {
98
+        $this->expectException(\Sabre\DAV\Exception\Forbidden::class);
99
+
100
+        $this->info->expects($this->any())
101
+            ->method('isDeletable')
102
+            ->willReturn(true);
103
+        $this->view->expects($this->never())
104
+            ->method('rmdir');
105
+        $dir = $this->getDir();
106
+        $dir->delete();
107
+    }
108
+
109
+
110
+    public function testDeleteForbidden(): void {
111
+        $this->expectException(Forbidden::class);
112
+
113
+        // deletion allowed
114
+        $this->info->expects($this->once())
115
+            ->method('isDeletable')
116
+            ->willReturn(true);
117
+
118
+        // but fails
119
+        $this->view->expects($this->once())
120
+            ->method('rmdir')
121
+            ->with('sub')
122
+            ->willThrowException(new ForbiddenException('', true));
123
+
124
+        $dir = $this->getDir('sub');
125
+        $dir->delete();
126
+    }
127
+
128
+
129
+    public function testDeleteFolderWhenAllowed(): void {
130
+        // deletion allowed
131
+        $this->info->expects($this->once())
132
+            ->method('isDeletable')
133
+            ->willReturn(true);
134
+
135
+        // but fails
136
+        $this->view->expects($this->once())
137
+            ->method('rmdir')
138
+            ->with('sub')
139
+            ->willReturn(true);
140
+
141
+        $dir = $this->getDir('sub');
142
+        $dir->delete();
143
+    }
144
+
145
+
146
+    public function testDeleteFolderFailsWhenNotAllowed(): void {
147
+        $this->expectException(\Sabre\DAV\Exception\Forbidden::class);
148 148
 
149
-		$this->info->expects($this->once())
150
-			->method('isDeletable')
151
-			->willReturn(false);
149
+        $this->info->expects($this->once())
150
+            ->method('isDeletable')
151
+            ->willReturn(false);
152 152
 
153
-		$dir = $this->getDir('sub');
154
-		$dir->delete();
155
-	}
153
+        $dir = $this->getDir('sub');
154
+        $dir->delete();
155
+    }
156 156
 
157 157
 
158
-	public function testDeleteFolderThrowsWhenDeletionFailed(): void {
159
-		$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
158
+    public function testDeleteFolderThrowsWhenDeletionFailed(): void {
159
+        $this->expectException(\Sabre\DAV\Exception\Forbidden::class);
160 160
 
161
-		// deletion allowed
162
-		$this->info->expects($this->once())
163
-			->method('isDeletable')
164
-			->willReturn(true);
165
-
166
-		// but fails
167
-		$this->view->expects($this->once())
168
-			->method('rmdir')
169
-			->with('sub')
170
-			->willReturn(false);
171
-
172
-		$dir = $this->getDir('sub');
173
-		$dir->delete();
174
-	}
175
-
176
-	public function testGetChildren(): void {
177
-		$info1 = $this->createMock(FileInfo::class);
178
-		$info2 = $this->createMock(FileInfo::class);
179
-		$info1->method('getName')
180
-			->willReturn('first');
181
-		$info1->method('getPath')
182
-			->willReturn('folder/first');
183
-		$info1->method('getEtag')
184
-			->willReturn('abc');
185
-		$info2->method('getName')
186
-			->willReturn('second');
187
-		$info2->method('getPath')
188
-			->willReturn('folder/second');
189
-		$info2->method('getEtag')
190
-			->willReturn('def');
161
+        // deletion allowed
162
+        $this->info->expects($this->once())
163
+            ->method('isDeletable')
164
+            ->willReturn(true);
165
+
166
+        // but fails
167
+        $this->view->expects($this->once())
168
+            ->method('rmdir')
169
+            ->with('sub')
170
+            ->willReturn(false);
171
+
172
+        $dir = $this->getDir('sub');
173
+        $dir->delete();
174
+    }
175
+
176
+    public function testGetChildren(): void {
177
+        $info1 = $this->createMock(FileInfo::class);
178
+        $info2 = $this->createMock(FileInfo::class);
179
+        $info1->method('getName')
180
+            ->willReturn('first');
181
+        $info1->method('getPath')
182
+            ->willReturn('folder/first');
183
+        $info1->method('getEtag')
184
+            ->willReturn('abc');
185
+        $info2->method('getName')
186
+            ->willReturn('second');
187
+        $info2->method('getPath')
188
+            ->willReturn('folder/second');
189
+        $info2->method('getEtag')
190
+            ->willReturn('def');
191 191
 
192
-		$this->view->expects($this->once())
193
-			->method('getDirectoryContent')
194
-			->willReturn([$info1, $info2]);
192
+        $this->view->expects($this->once())
193
+            ->method('getDirectoryContent')
194
+            ->willReturn([$info1, $info2]);
195 195
 
196
-		$this->view->expects($this->any())
197
-			->method('getRelativePath')
198
-			->willReturnCallback(function ($path) {
199
-				return str_replace('/admin/files/', '', $path);
200
-			});
201
-
202
-		$this->view->expects($this->any())
203
-			->method('getAbsolutePath')
204
-			->willReturnCallback(function ($path) {
205
-				return Filesystem::normalizePath('/admin/files' . $path);
206
-			});
196
+        $this->view->expects($this->any())
197
+            ->method('getRelativePath')
198
+            ->willReturnCallback(function ($path) {
199
+                return str_replace('/admin/files/', '', $path);
200
+            });
201
+
202
+        $this->view->expects($this->any())
203
+            ->method('getAbsolutePath')
204
+            ->willReturnCallback(function ($path) {
205
+                return Filesystem::normalizePath('/admin/files' . $path);
206
+            });
207 207
 
208
-		$this->overwriteService(View::class, $this->view);
209
-
210
-		$dir = new Directory($this->view, $this->info);
211
-		$nodes = $dir->getChildren();
212
-
213
-		$this->assertCount(2, $nodes);
214
-
215
-		// calling a second time just returns the cached values,
216
-		// does not call getDirectoryContents again
217
-		$dir->getChildren();
218
-	}
208
+        $this->overwriteService(View::class, $this->view);
209
+
210
+        $dir = new Directory($this->view, $this->info);
211
+        $nodes = $dir->getChildren();
212
+
213
+        $this->assertCount(2, $nodes);
214
+
215
+        // calling a second time just returns the cached values,
216
+        // does not call getDirectoryContents again
217
+        $dir->getChildren();
218
+    }
219 219
 
220 220
 
221
-	public function testGetChildrenNoPermission(): void {
222
-		$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
221
+    public function testGetChildrenNoPermission(): void {
222
+        $this->expectException(\Sabre\DAV\Exception\Forbidden::class);
223 223
 
224
-		$info = $this->createMock(FileInfo::class);
225
-		$info->expects($this->any())
226
-			->method('isReadable')
227
-			->willReturn(false);
228
-
229
-		$dir = new Directory($this->view, $info);
230
-		$dir->getChildren();
231
-	}
232
-
233
-
234
-	public function testGetChildNoPermission(): void {
235
-		$this->expectException(\Sabre\DAV\Exception\NotFound::class);
236
-
237
-		$this->info->expects($this->any())
238
-			->method('isReadable')
239
-			->willReturn(false);
240
-
241
-		$dir = new Directory($this->view, $this->info);
242
-		$dir->getChild('test');
243
-	}
244
-
245
-
246
-	public function testGetChildThrowStorageNotAvailableException(): void {
247
-		$this->expectException(\Sabre\DAV\Exception\ServiceUnavailable::class);
248
-
249
-		$this->view->expects($this->once())
250
-			->method('getFileInfo')
251
-			->willThrowException(new StorageNotAvailableException());
252
-
253
-		$dir = new Directory($this->view, $this->info);
254
-		$dir->getChild('.');
255
-	}
256
-
257
-
258
-	public function testGetChildThrowInvalidPath(): void {
259
-		$this->expectException(InvalidPath::class);
260
-
261
-		$this->view->expects($this->once())
262
-			->method('verifyPath')
263
-			->willThrowException(new InvalidPathException());
264
-		$this->view->expects($this->never())
265
-			->method('getFileInfo');
266
-
267
-		$dir = new Directory($this->view, $this->info);
268
-		$dir->getChild('.');
269
-	}
270
-
271
-	public function testGetQuotaInfoUnlimited(): void {
272
-		$this->createUser('user', 'password');
273
-		self::loginAsUser('user');
274
-		$mountPoint = $this->createMock(IMountPoint::class);
275
-		$storage = $this->createMock(Quota::class);
276
-		$mountPoint->method('getStorage')
277
-			->willReturn($storage);
278
-
279
-		$storage->expects($this->any())
280
-			->method('instanceOfStorage')
281
-			->willReturnMap([
282
-				['\OCA\Files_Sharing\SharedStorage', false],
283
-				['\OC\Files\Storage\Wrapper\Quota', false],
284
-				[Storage::class, false],
285
-			]);
286
-
287
-		$storage->expects($this->once())
288
-			->method('getOwner')
289
-			->willReturn('user');
224
+        $info = $this->createMock(FileInfo::class);
225
+        $info->expects($this->any())
226
+            ->method('isReadable')
227
+            ->willReturn(false);
228
+
229
+        $dir = new Directory($this->view, $info);
230
+        $dir->getChildren();
231
+    }
232
+
233
+
234
+    public function testGetChildNoPermission(): void {
235
+        $this->expectException(\Sabre\DAV\Exception\NotFound::class);
236
+
237
+        $this->info->expects($this->any())
238
+            ->method('isReadable')
239
+            ->willReturn(false);
240
+
241
+        $dir = new Directory($this->view, $this->info);
242
+        $dir->getChild('test');
243
+    }
244
+
245
+
246
+    public function testGetChildThrowStorageNotAvailableException(): void {
247
+        $this->expectException(\Sabre\DAV\Exception\ServiceUnavailable::class);
248
+
249
+        $this->view->expects($this->once())
250
+            ->method('getFileInfo')
251
+            ->willThrowException(new StorageNotAvailableException());
252
+
253
+        $dir = new Directory($this->view, $this->info);
254
+        $dir->getChild('.');
255
+    }
256
+
257
+
258
+    public function testGetChildThrowInvalidPath(): void {
259
+        $this->expectException(InvalidPath::class);
260
+
261
+        $this->view->expects($this->once())
262
+            ->method('verifyPath')
263
+            ->willThrowException(new InvalidPathException());
264
+        $this->view->expects($this->never())
265
+            ->method('getFileInfo');
266
+
267
+        $dir = new Directory($this->view, $this->info);
268
+        $dir->getChild('.');
269
+    }
270
+
271
+    public function testGetQuotaInfoUnlimited(): void {
272
+        $this->createUser('user', 'password');
273
+        self::loginAsUser('user');
274
+        $mountPoint = $this->createMock(IMountPoint::class);
275
+        $storage = $this->createMock(Quota::class);
276
+        $mountPoint->method('getStorage')
277
+            ->willReturn($storage);
278
+
279
+        $storage->expects($this->any())
280
+            ->method('instanceOfStorage')
281
+            ->willReturnMap([
282
+                ['\OCA\Files_Sharing\SharedStorage', false],
283
+                ['\OC\Files\Storage\Wrapper\Quota', false],
284
+                [Storage::class, false],
285
+            ]);
286
+
287
+        $storage->expects($this->once())
288
+            ->method('getOwner')
289
+            ->willReturn('user');
290 290
 
291
-		$storage->expects($this->never())
292
-			->method('getQuota');
291
+        $storage->expects($this->never())
292
+            ->method('getQuota');
293 293
 
294
-		$storage->expects($this->once())
295
-			->method('free_space')
296
-			->willReturn(800);
294
+        $storage->expects($this->once())
295
+            ->method('free_space')
296
+            ->willReturn(800);
297 297
 
298
-		$this->info->expects($this->any())
299
-			->method('getPath')
300
-			->willReturn('/admin/files/foo');
298
+        $this->info->expects($this->any())
299
+            ->method('getPath')
300
+            ->willReturn('/admin/files/foo');
301 301
 
302
-		$this->info->expects($this->once())
303
-			->method('getSize')
304
-			->willReturn(200);
302
+        $this->info->expects($this->once())
303
+            ->method('getSize')
304
+            ->willReturn(200);
305 305
 
306
-		$this->info->expects($this->once())
307
-			->method('getMountPoint')
308
-			->willReturn($mountPoint);
309
-
310
-		$this->view->expects($this->any())
311
-			->method('getRelativePath')
312
-			->willReturn('/foo');
313
-
314
-		$this->info->expects($this->once())
315
-			->method('getInternalPath')
316
-			->willReturn('/foo');
317
-
318
-		$mountPoint->method('getMountPoint')
319
-			->willReturn('/user/files/mymountpoint');
320
-
321
-		$dir = new Directory($this->view, $this->info);
322
-		$this->assertEquals([200, -3], $dir->getQuotaInfo()); //200 used, unlimited
323
-	}
324
-
325
-	public function testGetQuotaInfoSpecific(): void {
326
-		$this->createUser('user', 'password');
327
-		self::loginAsUser('user');
328
-		$mountPoint = $this->createMock(IMountPoint::class);
329
-		$storage = $this->createMock(Quota::class);
330
-		$mountPoint->method('getStorage')
331
-			->willReturn($storage);
332
-
333
-		$storage->expects($this->any())
334
-			->method('instanceOfStorage')
335
-			->willReturnMap([
336
-				['\OCA\Files_Sharing\SharedStorage', false],
337
-				['\OC\Files\Storage\Wrapper\Quota', true],
338
-				[Storage::class, false],
339
-			]);
340
-
341
-		$storage->expects($this->once())
342
-			->method('getOwner')
343
-			->willReturn('user');
344
-
345
-		$storage->expects($this->once())
346
-			->method('getQuota')
347
-			->willReturn(1000);
348
-
349
-		$storage->expects($this->once())
350
-			->method('free_space')
351
-			->willReturn(800);
352
-
353
-		$this->info->expects($this->once())
354
-			->method('getSize')
355
-			->willReturn(200);
356
-
357
-		$this->info->expects($this->once())
358
-			->method('getMountPoint')
359
-			->willReturn($mountPoint);
360
-
361
-		$this->info->expects($this->once())
362
-			->method('getInternalPath')
363
-			->willReturn('/foo');
364
-
365
-		$mountPoint->method('getMountPoint')
366
-			->willReturn('/user/files/mymountpoint');
367
-
368
-		$this->view->expects($this->any())
369
-			->method('getRelativePath')
370
-			->willReturn('/foo');
371
-
372
-		$dir = new Directory($this->view, $this->info);
373
-		$this->assertEquals([200, 800], $dir->getQuotaInfo()); //200 used, 800 free
374
-	}
375
-
376
-	#[\PHPUnit\Framework\Attributes\DataProvider('moveFailedProvider')]
377
-	public function testMoveFailed(string $source, string $destination, array $updatables, array $deletables): void {
378
-		$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
379
-
380
-		$this->moveTest($source, $destination, $updatables, $deletables);
381
-	}
382
-
383
-	#[\PHPUnit\Framework\Attributes\DataProvider('moveSuccessProvider')]
384
-	public function testMoveSuccess(string $source, string $destination, array $updatables, array $deletables): void {
385
-		$this->moveTest($source, $destination, $updatables, $deletables);
386
-		$this->addToAssertionCount(1);
387
-	}
388
-
389
-	#[\PHPUnit\Framework\Attributes\DataProvider('moveFailedInvalidCharsProvider')]
390
-	public function testMoveFailedInvalidChars(string $source, string $destination, array $updatables, array $deletables): void {
391
-		$this->expectException(InvalidPath::class);
392
-
393
-		$this->moveTest($source, $destination, $updatables, $deletables);
394
-	}
395
-
396
-	public static function moveFailedInvalidCharsProvider(): array {
397
-		return [
398
-			['a/valid', "a/i\nvalid", ['a' => true, 'a/valid' => true, 'a/c*' => false], []],
399
-		];
400
-	}
401
-
402
-	public static function moveFailedProvider(): array {
403
-		return [
404
-			['a/b', 'a/c', ['a' => false, 'a/b' => false, 'a/c' => false], []],
405
-			['a/b', 'b/b', ['a' => false, 'a/b' => false, 'b' => false, 'b/b' => false], []],
406
-			['a/b', 'b/b', ['a' => false, 'a/b' => true, 'b' => false, 'b/b' => false], []],
407
-			['a/b', 'b/b', ['a' => true, 'a/b' => true, 'b' => false, 'b/b' => false], []],
408
-			['a/b', 'b/b', ['a' => true, 'a/b' => true, 'b' => true, 'b/b' => false], ['a/b' => false]],
409
-			['a/b', 'a/c', ['a' => false, 'a/b' => true, 'a/c' => false], []],
410
-		];
411
-	}
412
-
413
-	public static function moveSuccessProvider(): array {
414
-		return [
415
-			['a/b', 'b/b', ['a' => true, 'a/b' => true, 'b' => true, 'b/b' => false], ['a/b' => true]],
416
-			// older files with special chars can still be renamed to valid names
417
-			['a/b*', 'b/b', ['a' => true, 'a/b*' => true, 'b' => true, 'b/b' => false], ['a/b*' => true]],
418
-		];
419
-	}
420
-
421
-	private function moveTest(string $source, string $destination, array $updatables, array $deletables): void {
422
-		$view = new TestViewDirectory($updatables, $deletables);
423
-
424
-		$sourceInfo = new FileInfo($source, null, null, [
425
-			'type' => FileInfo::TYPE_FOLDER,
426
-		], null);
427
-		$targetInfo = new FileInfo(dirname($destination), null, null, [
428
-			'type' => FileInfo::TYPE_FOLDER,
429
-		], null);
430
-
431
-		$sourceNode = new Directory($view, $sourceInfo);
432
-		$targetNode = $this->getMockBuilder(Directory::class)
433
-			->onlyMethods(['childExists'])
434
-			->setConstructorArgs([$view, $targetInfo])
435
-			->getMock();
436
-		$targetNode->expects($this->any())->method('childExists')
437
-			->with(basename($destination))
438
-			->willReturn(false);
439
-		$this->assertTrue($targetNode->moveInto(basename($destination), $source, $sourceNode));
440
-	}
441
-
442
-
443
-	public function testFailingMove(): void {
444
-		$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
445
-		$this->expectExceptionMessage('Could not copy directory b, target exists');
446
-
447
-		$source = 'a/b';
448
-		$destination = 'c/b';
449
-		$updatables = ['a' => true, 'a/b' => true, 'b' => true, 'c/b' => false];
450
-		$deletables = ['a/b' => true];
451
-
452
-		$view = new TestViewDirectory($updatables, $deletables);
453
-
454
-		$sourceInfo = new FileInfo($source, null, null, ['type' => FileInfo::TYPE_FOLDER], null);
455
-		$targetInfo = new FileInfo(dirname($destination), null, null, ['type' => FileInfo::TYPE_FOLDER], null);
456
-
457
-		$sourceNode = new Directory($view, $sourceInfo);
458
-		$targetNode = $this->getMockBuilder(Directory::class)
459
-			->onlyMethods(['childExists'])
460
-			->setConstructorArgs([$view, $targetInfo])
461
-			->getMock();
462
-		$targetNode->expects($this->once())->method('childExists')
463
-			->with(basename($destination))
464
-			->willReturn(true);
465
-
466
-		$targetNode->moveInto(basename($destination), $source, $sourceNode);
467
-	}
306
+        $this->info->expects($this->once())
307
+            ->method('getMountPoint')
308
+            ->willReturn($mountPoint);
309
+
310
+        $this->view->expects($this->any())
311
+            ->method('getRelativePath')
312
+            ->willReturn('/foo');
313
+
314
+        $this->info->expects($this->once())
315
+            ->method('getInternalPath')
316
+            ->willReturn('/foo');
317
+
318
+        $mountPoint->method('getMountPoint')
319
+            ->willReturn('/user/files/mymountpoint');
320
+
321
+        $dir = new Directory($this->view, $this->info);
322
+        $this->assertEquals([200, -3], $dir->getQuotaInfo()); //200 used, unlimited
323
+    }
324
+
325
+    public function testGetQuotaInfoSpecific(): void {
326
+        $this->createUser('user', 'password');
327
+        self::loginAsUser('user');
328
+        $mountPoint = $this->createMock(IMountPoint::class);
329
+        $storage = $this->createMock(Quota::class);
330
+        $mountPoint->method('getStorage')
331
+            ->willReturn($storage);
332
+
333
+        $storage->expects($this->any())
334
+            ->method('instanceOfStorage')
335
+            ->willReturnMap([
336
+                ['\OCA\Files_Sharing\SharedStorage', false],
337
+                ['\OC\Files\Storage\Wrapper\Quota', true],
338
+                [Storage::class, false],
339
+            ]);
340
+
341
+        $storage->expects($this->once())
342
+            ->method('getOwner')
343
+            ->willReturn('user');
344
+
345
+        $storage->expects($this->once())
346
+            ->method('getQuota')
347
+            ->willReturn(1000);
348
+
349
+        $storage->expects($this->once())
350
+            ->method('free_space')
351
+            ->willReturn(800);
352
+
353
+        $this->info->expects($this->once())
354
+            ->method('getSize')
355
+            ->willReturn(200);
356
+
357
+        $this->info->expects($this->once())
358
+            ->method('getMountPoint')
359
+            ->willReturn($mountPoint);
360
+
361
+        $this->info->expects($this->once())
362
+            ->method('getInternalPath')
363
+            ->willReturn('/foo');
364
+
365
+        $mountPoint->method('getMountPoint')
366
+            ->willReturn('/user/files/mymountpoint');
367
+
368
+        $this->view->expects($this->any())
369
+            ->method('getRelativePath')
370
+            ->willReturn('/foo');
371
+
372
+        $dir = new Directory($this->view, $this->info);
373
+        $this->assertEquals([200, 800], $dir->getQuotaInfo()); //200 used, 800 free
374
+    }
375
+
376
+    #[\PHPUnit\Framework\Attributes\DataProvider('moveFailedProvider')]
377
+    public function testMoveFailed(string $source, string $destination, array $updatables, array $deletables): void {
378
+        $this->expectException(\Sabre\DAV\Exception\Forbidden::class);
379
+
380
+        $this->moveTest($source, $destination, $updatables, $deletables);
381
+    }
382
+
383
+    #[\PHPUnit\Framework\Attributes\DataProvider('moveSuccessProvider')]
384
+    public function testMoveSuccess(string $source, string $destination, array $updatables, array $deletables): void {
385
+        $this->moveTest($source, $destination, $updatables, $deletables);
386
+        $this->addToAssertionCount(1);
387
+    }
388
+
389
+    #[\PHPUnit\Framework\Attributes\DataProvider('moveFailedInvalidCharsProvider')]
390
+    public function testMoveFailedInvalidChars(string $source, string $destination, array $updatables, array $deletables): void {
391
+        $this->expectException(InvalidPath::class);
392
+
393
+        $this->moveTest($source, $destination, $updatables, $deletables);
394
+    }
395
+
396
+    public static function moveFailedInvalidCharsProvider(): array {
397
+        return [
398
+            ['a/valid', "a/i\nvalid", ['a' => true, 'a/valid' => true, 'a/c*' => false], []],
399
+        ];
400
+    }
401
+
402
+    public static function moveFailedProvider(): array {
403
+        return [
404
+            ['a/b', 'a/c', ['a' => false, 'a/b' => false, 'a/c' => false], []],
405
+            ['a/b', 'b/b', ['a' => false, 'a/b' => false, 'b' => false, 'b/b' => false], []],
406
+            ['a/b', 'b/b', ['a' => false, 'a/b' => true, 'b' => false, 'b/b' => false], []],
407
+            ['a/b', 'b/b', ['a' => true, 'a/b' => true, 'b' => false, 'b/b' => false], []],
408
+            ['a/b', 'b/b', ['a' => true, 'a/b' => true, 'b' => true, 'b/b' => false], ['a/b' => false]],
409
+            ['a/b', 'a/c', ['a' => false, 'a/b' => true, 'a/c' => false], []],
410
+        ];
411
+    }
412
+
413
+    public static function moveSuccessProvider(): array {
414
+        return [
415
+            ['a/b', 'b/b', ['a' => true, 'a/b' => true, 'b' => true, 'b/b' => false], ['a/b' => true]],
416
+            // older files with special chars can still be renamed to valid names
417
+            ['a/b*', 'b/b', ['a' => true, 'a/b*' => true, 'b' => true, 'b/b' => false], ['a/b*' => true]],
418
+        ];
419
+    }
420
+
421
+    private function moveTest(string $source, string $destination, array $updatables, array $deletables): void {
422
+        $view = new TestViewDirectory($updatables, $deletables);
423
+
424
+        $sourceInfo = new FileInfo($source, null, null, [
425
+            'type' => FileInfo::TYPE_FOLDER,
426
+        ], null);
427
+        $targetInfo = new FileInfo(dirname($destination), null, null, [
428
+            'type' => FileInfo::TYPE_FOLDER,
429
+        ], null);
430
+
431
+        $sourceNode = new Directory($view, $sourceInfo);
432
+        $targetNode = $this->getMockBuilder(Directory::class)
433
+            ->onlyMethods(['childExists'])
434
+            ->setConstructorArgs([$view, $targetInfo])
435
+            ->getMock();
436
+        $targetNode->expects($this->any())->method('childExists')
437
+            ->with(basename($destination))
438
+            ->willReturn(false);
439
+        $this->assertTrue($targetNode->moveInto(basename($destination), $source, $sourceNode));
440
+    }
441
+
442
+
443
+    public function testFailingMove(): void {
444
+        $this->expectException(\Sabre\DAV\Exception\Forbidden::class);
445
+        $this->expectExceptionMessage('Could not copy directory b, target exists');
446
+
447
+        $source = 'a/b';
448
+        $destination = 'c/b';
449
+        $updatables = ['a' => true, 'a/b' => true, 'b' => true, 'c/b' => false];
450
+        $deletables = ['a/b' => true];
451
+
452
+        $view = new TestViewDirectory($updatables, $deletables);
453
+
454
+        $sourceInfo = new FileInfo($source, null, null, ['type' => FileInfo::TYPE_FOLDER], null);
455
+        $targetInfo = new FileInfo(dirname($destination), null, null, ['type' => FileInfo::TYPE_FOLDER], null);
456
+
457
+        $sourceNode = new Directory($view, $sourceInfo);
458
+        $targetNode = $this->getMockBuilder(Directory::class)
459
+            ->onlyMethods(['childExists'])
460
+            ->setConstructorArgs([$view, $targetInfo])
461
+            ->getMock();
462
+        $targetNode->expects($this->once())->method('childExists')
463
+            ->with(basename($destination))
464
+            ->willReturn(true);
465
+
466
+        $targetNode->moveInto(basename($destination), $source, $sourceNode);
467
+    }
468 468
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php 2 patches
Indentation   +677 added lines, -677 removed lines patch added patch discarded remove patch
@@ -40,681 +40,681 @@
 block discarded – undo
40 40
  */
41 41
 class FilesPluginTest extends TestCase {
42 42
 
43
-	private Tree&MockObject $tree;
44
-	private Server&MockObject $server;
45
-	private IConfig&MockObject $config;
46
-	private IRequest&MockObject $request;
47
-	private IPreview&MockObject $previewManager;
48
-	private IUserSession&MockObject $userSession;
49
-	private IFilenameValidator&MockObject $filenameValidator;
50
-	private IAccountManager&MockObject $accountManager;
51
-	private FilesPlugin $plugin;
52
-
53
-	protected function setUp(): void {
54
-		parent::setUp();
55
-		$this->server = $this->createMock(Server::class);
56
-		$this->tree = $this->createMock(Tree::class);
57
-		$this->config = $this->createMock(IConfig::class);
58
-		$this->config->expects($this->any())->method('getSystemValue')
59
-			->with($this->equalTo('data-fingerprint'), $this->equalTo(''))
60
-			->willReturn('my_fingerprint');
61
-		$this->request = $this->createMock(IRequest::class);
62
-		$this->previewManager = $this->createMock(IPreview::class);
63
-		$this->userSession = $this->createMock(IUserSession::class);
64
-		$this->filenameValidator = $this->createMock(IFilenameValidator::class);
65
-		$this->accountManager = $this->createMock(IAccountManager::class);
66
-
67
-		$this->plugin = new FilesPlugin(
68
-			$this->tree,
69
-			$this->config,
70
-			$this->request,
71
-			$this->previewManager,
72
-			$this->userSession,
73
-			$this->filenameValidator,
74
-			$this->accountManager,
75
-		);
76
-
77
-		$response = $this->createMock(ResponseInterface::class);
78
-		$this->server->httpResponse = $response;
79
-		$this->server->xml = new Service();
80
-
81
-		$this->plugin->initialize($this->server);
82
-	}
83
-
84
-	private function createTestNode(string $class, string $path = '/dummypath'): MockObject {
85
-		$node = $this->createMock($class);
86
-
87
-		$node->expects($this->any())
88
-			->method('getId')
89
-			->willReturn(123);
90
-
91
-		$this->tree->expects($this->any())
92
-			->method('getNodeForPath')
93
-			->with($path)
94
-			->willReturn($node);
95
-
96
-		$node->expects($this->any())
97
-			->method('getFileId')
98
-			->willReturn('00000123instanceid');
99
-		$node->expects($this->any())
100
-			->method('getInternalFileId')
101
-			->willReturn('123');
102
-		$node->expects($this->any())
103
-			->method('getEtag')
104
-			->willReturn('"abc"');
105
-		$node->expects($this->any())
106
-			->method('getDavPermissions')
107
-			->willReturn('DWCKMSR');
108
-
109
-		$fileInfo = $this->createMock(FileInfo::class);
110
-		$fileInfo->expects($this->any())
111
-			->method('isReadable')
112
-			->willReturn(true);
113
-		$fileInfo->expects($this->any())
114
-			->method('getCreationTime')
115
-			->willReturn(123456789);
116
-
117
-		$node->expects($this->any())
118
-			->method('getFileInfo')
119
-			->willReturn($fileInfo);
120
-
121
-		return $node;
122
-	}
123
-
124
-	public function testGetPropertiesForFile(): void {
125
-		/** @var File&MockObject $node */
126
-		$node = $this->createTestNode(File::class);
127
-
128
-		$propFind = new PropFind(
129
-			'/dummyPath',
130
-			[
131
-				FilesPlugin::GETETAG_PROPERTYNAME,
132
-				FilesPlugin::FILEID_PROPERTYNAME,
133
-				FilesPlugin::INTERNAL_FILEID_PROPERTYNAME,
134
-				FilesPlugin::SIZE_PROPERTYNAME,
135
-				FilesPlugin::PERMISSIONS_PROPERTYNAME,
136
-				FilesPlugin::DOWNLOADURL_PROPERTYNAME,
137
-				FilesPlugin::OWNER_ID_PROPERTYNAME,
138
-				FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME,
139
-				FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME,
140
-				FilesPlugin::CREATIONDATE_PROPERTYNAME,
141
-			],
142
-			0
143
-		);
144
-
145
-		$user = $this->createMock(User::class);
146
-		$user
147
-			->expects($this->once())
148
-			->method('getUID')
149
-			->willReturn('foo');
150
-		$user
151
-			->expects($this->once())
152
-			->method('getDisplayName')
153
-			->willReturn('M. Foo');
154
-
155
-		$owner = $this->createMock(Account::class);
156
-		$this->accountManager->expects($this->once())
157
-			->method('getAccount')
158
-			->with($user)
159
-			->willReturn($owner);
160
-
161
-		$node->expects($this->once())
162
-			->method('getDirectDownload')
163
-			->willReturn(['url' => 'http://example.com/']);
164
-		$node->expects($this->exactly(2))
165
-			->method('getOwner')
166
-			->willReturn($user);
167
-
168
-		$displayNameProp = $this->createMock(AccountProperty::class);
169
-		$owner
170
-			->expects($this->once())
171
-			->method('getProperty')
172
-			->with(IAccountManager::PROPERTY_DISPLAYNAME)
173
-			->willReturn($displayNameProp);
174
-		$displayNameProp
175
-			->expects($this->once())
176
-			->method('getScope')
177
-			->willReturn(IAccountManager::SCOPE_PUBLISHED);
178
-
179
-		$this->plugin->handleGetProperties(
180
-			$propFind,
181
-			$node
182
-		);
183
-
184
-		$this->assertEquals('"abc"', $propFind->get(FilesPlugin::GETETAG_PROPERTYNAME));
185
-		$this->assertEquals('00000123instanceid', $propFind->get(FilesPlugin::FILEID_PROPERTYNAME));
186
-		$this->assertEquals('123', $propFind->get(FilesPlugin::INTERNAL_FILEID_PROPERTYNAME));
187
-		$this->assertEquals('1973-11-29T21:33:09+00:00', $propFind->get(FilesPlugin::CREATIONDATE_PROPERTYNAME));
188
-		$this->assertEquals(0, $propFind->get(FilesPlugin::SIZE_PROPERTYNAME));
189
-		$this->assertEquals('DWCKMSR', $propFind->get(FilesPlugin::PERMISSIONS_PROPERTYNAME));
190
-		$this->assertEquals('http://example.com/', $propFind->get(FilesPlugin::DOWNLOADURL_PROPERTYNAME));
191
-		$this->assertEquals('foo', $propFind->get(FilesPlugin::OWNER_ID_PROPERTYNAME));
192
-		$this->assertEquals('M. Foo', $propFind->get(FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME));
193
-		$this->assertEquals('my_fingerprint', $propFind->get(FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME));
194
-		$this->assertEquals([], $propFind->get404Properties());
195
-	}
196
-
197
-	public function testGetDisplayNamePropertyWhenNotPublished(): void {
198
-		$node = $this->createTestNode(File::class);
199
-		$propFind = new PropFind(
200
-			'/dummyPath',
201
-			[
202
-				FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME,
203
-			],
204
-			0
205
-		);
206
-
207
-		$this->userSession->expects($this->once())
208
-			->method('getUser')
209
-			->willReturn(null);
210
-
211
-		$user = $this->createMock(User::class);
212
-
213
-		$user->expects($this->never())
214
-			->method('getDisplayName');
215
-
216
-		$owner = $this->createMock(Account::class);
217
-		$this->accountManager->expects($this->once())
218
-			->method('getAccount')
219
-			->with($user)
220
-			->willReturn($owner);
221
-
222
-		$node->expects($this->once())
223
-			->method('getOwner')
224
-			->willReturn($user);
225
-
226
-		$displayNameProp = $this->createMock(AccountProperty::class);
227
-		$owner
228
-			->expects($this->once())
229
-			->method('getProperty')
230
-			->with(IAccountManager::PROPERTY_DISPLAYNAME)
231
-			->willReturn($displayNameProp);
232
-		$displayNameProp
233
-			->expects($this->once())
234
-			->method('getScope')
235
-			->willReturn(IAccountManager::SCOPE_PRIVATE);
236
-
237
-		$this->plugin->handleGetProperties(
238
-			$propFind,
239
-			$node
240
-		);
241
-
242
-		$this->assertEquals(null, $propFind->get(FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME));
243
-	}
244
-
245
-	public function testGetDisplayNamePropertyWhenNotPublishedButLoggedIn(): void {
246
-		$node = $this->createTestNode(File::class);
247
-
248
-		$propFind = new PropFind(
249
-			'/dummyPath',
250
-			[
251
-				FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME,
252
-			],
253
-			0
254
-		);
255
-
256
-		$user = $this->createMock(User::class);
257
-
258
-		$node->expects($this->once())
259
-			->method('getOwner')
260
-			->willReturn($user);
261
-
262
-		$loggedInUser = $this->createMock(User::class);
263
-		$this->userSession->expects($this->once())
264
-			->method('getUser')
265
-			->willReturn($loggedInUser);
266
-
267
-		$user
268
-			->expects($this->once())
269
-			->method('getDisplayName')
270
-			->willReturn('M. Foo');
271
-
272
-		$this->accountManager->expects($this->never())
273
-			->method('getAccount');
274
-
275
-		$this->plugin->handleGetProperties(
276
-			$propFind,
277
-			$node
278
-		);
279
-
280
-		$this->assertEquals('M. Foo', $propFind->get(FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME));
281
-	}
282
-
283
-	public function testGetPropertiesStorageNotAvailable(): void {
284
-		/** @var File&MockObject $node */
285
-		$node = $this->createTestNode(File::class);
286
-
287
-		$propFind = new PropFind(
288
-			'/dummyPath',
289
-			[
290
-				FilesPlugin::DOWNLOADURL_PROPERTYNAME,
291
-			],
292
-			0
293
-		);
294
-
295
-		$node->expects($this->once())
296
-			->method('getDirectDownload')
297
-			->willThrowException(new StorageNotAvailableException());
298
-
299
-		$this->plugin->handleGetProperties(
300
-			$propFind,
301
-			$node
302
-		);
303
-
304
-		$this->assertEquals(null, $propFind->get(FilesPlugin::DOWNLOADURL_PROPERTYNAME));
305
-	}
306
-
307
-	public function testGetPublicPermissions(): void {
308
-		/** @var IRequest&MockObject */
309
-		$request = $this->createMock(IRequest::class);
310
-		$this->plugin = new FilesPlugin(
311
-			$this->tree,
312
-			$this->config,
313
-			$request,
314
-			$this->previewManager,
315
-			$this->userSession,
316
-			$this->filenameValidator,
317
-			$this->accountManager,
318
-			true,
319
-		);
320
-		$this->plugin->initialize($this->server);
321
-
322
-		$propFind = new PropFind(
323
-			'/dummyPath',
324
-			[
325
-				FilesPlugin::PERMISSIONS_PROPERTYNAME,
326
-			],
327
-			0
328
-		);
329
-
330
-		/** @var File&MockObject $node */
331
-		$node = $this->createTestNode(File::class);
332
-		$node->expects($this->any())
333
-			->method('getDavPermissions')
334
-			->willReturn('DWCKMSR');
335
-
336
-		$this->plugin->handleGetProperties(
337
-			$propFind,
338
-			$node
339
-		);
340
-
341
-		$this->assertEquals('DWCKR', $propFind->get(FilesPlugin::PERMISSIONS_PROPERTYNAME));
342
-	}
343
-
344
-	public function testGetPropertiesForDirectory(): void {
345
-		/** @var Directory&MockObject $node */
346
-		$node = $this->createTestNode(Directory::class);
347
-
348
-		$propFind = new PropFind(
349
-			'/dummyPath',
350
-			[
351
-				FilesPlugin::GETETAG_PROPERTYNAME,
352
-				FilesPlugin::FILEID_PROPERTYNAME,
353
-				FilesPlugin::SIZE_PROPERTYNAME,
354
-				FilesPlugin::PERMISSIONS_PROPERTYNAME,
355
-				FilesPlugin::DOWNLOADURL_PROPERTYNAME,
356
-				FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME,
357
-			],
358
-			0
359
-		);
360
-
361
-		$node->expects($this->once())
362
-			->method('getSize')
363
-			->willReturn(1025);
364
-
365
-		$this->plugin->handleGetProperties(
366
-			$propFind,
367
-			$node
368
-		);
369
-
370
-		$this->assertEquals('"abc"', $propFind->get(FilesPlugin::GETETAG_PROPERTYNAME));
371
-		$this->assertEquals('00000123instanceid', $propFind->get(FilesPlugin::FILEID_PROPERTYNAME));
372
-		$this->assertEquals(1025, $propFind->get(FilesPlugin::SIZE_PROPERTYNAME));
373
-		$this->assertEquals('DWCKMSR', $propFind->get(FilesPlugin::PERMISSIONS_PROPERTYNAME));
374
-		$this->assertEquals(null, $propFind->get(FilesPlugin::DOWNLOADURL_PROPERTYNAME));
375
-		$this->assertEquals('my_fingerprint', $propFind->get(FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME));
376
-		$this->assertEquals([FilesPlugin::DOWNLOADURL_PROPERTYNAME], $propFind->get404Properties());
377
-	}
378
-
379
-	public function testGetPropertiesForRootDirectory(): void {
380
-		/** @var Directory&MockObject $node */
381
-		$node = $this->createMock(Directory::class);
382
-		$node->expects($this->any())->method('getPath')->willReturn('/');
383
-
384
-		$fileInfo = $this->createMock(FileInfo::class);
385
-		$fileInfo->expects($this->any())
386
-			->method('isReadable')
387
-			->willReturn(true);
388
-
389
-		$node->expects($this->any())
390
-			->method('getFileInfo')
391
-			->willReturn($fileInfo);
392
-
393
-		$propFind = new PropFind(
394
-			'/',
395
-			[
396
-				FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME,
397
-			],
398
-			0
399
-		);
400
-
401
-		$this->plugin->handleGetProperties(
402
-			$propFind,
403
-			$node
404
-		);
405
-
406
-		$this->assertEquals('my_fingerprint', $propFind->get(FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME));
407
-	}
408
-
409
-	public function testGetPropertiesWhenNoPermission(): void {
410
-		// No read permissions can be caused by files access control.
411
-		// But we still want to load the directory list, so this is okay for us.
412
-		// $this->expectException(\Sabre\DAV\Exception\NotFound::class);
413
-		/** @var Directory&MockObject $node */
414
-		$node = $this->createMock(Directory::class);
415
-		$node->expects($this->any())->method('getPath')->willReturn('/');
416
-
417
-		$fileInfo = $this->createMock(FileInfo::class);
418
-		$fileInfo->expects($this->any())
419
-			->method('isReadable')
420
-			->willReturn(false);
421
-
422
-		$node->expects($this->any())
423
-			->method('getFileInfo')
424
-			->willReturn($fileInfo);
425
-
426
-		$propFind = new PropFind(
427
-			'/test',
428
-			[
429
-				FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME,
430
-			],
431
-			0
432
-		);
433
-
434
-		$this->plugin->handleGetProperties(
435
-			$propFind,
436
-			$node
437
-		);
438
-
439
-		$this->addToAssertionCount(1);
440
-	}
441
-
442
-	public function testUpdateProps(): void {
443
-		$node = $this->createTestNode(File::class);
444
-
445
-		$testDate = 'Fri, 13 Feb 2015 00:01:02 GMT';
446
-		$testCreationDate = '2007-08-31T16:47+00:00';
447
-
448
-		$node->expects($this->once())
449
-			->method('touch')
450
-			->with($testDate);
451
-
452
-		$node->expects($this->once())
453
-			->method('setEtag')
454
-			->with('newetag')
455
-			->willReturn(true);
456
-
457
-		$node->expects($this->once())
458
-			->method('setCreationTime')
459
-			->with('1188578820');
460
-
461
-		// properties to set
462
-		$propPatch = new PropPatch([
463
-			FilesPlugin::GETETAG_PROPERTYNAME => 'newetag',
464
-			FilesPlugin::LASTMODIFIED_PROPERTYNAME => $testDate,
465
-			FilesPlugin::CREATIONDATE_PROPERTYNAME => $testCreationDate,
466
-		]);
467
-
468
-
469
-		$this->plugin->handleUpdateProperties(
470
-			'/dummypath',
471
-			$propPatch
472
-		);
473
-
474
-		$propPatch->commit();
475
-
476
-		$this->assertEmpty($propPatch->getRemainingMutations());
477
-
478
-		$result = $propPatch->getResult();
479
-		$this->assertEquals(200, $result[FilesPlugin::LASTMODIFIED_PROPERTYNAME]);
480
-		$this->assertEquals(200, $result[FilesPlugin::GETETAG_PROPERTYNAME]);
481
-		$this->assertEquals(200, $result[FilesPlugin::CREATIONDATE_PROPERTYNAME]);
482
-	}
483
-
484
-	public function testUpdatePropsForbidden(): void {
485
-		$propPatch = new PropPatch([
486
-			FilesPlugin::OWNER_ID_PROPERTYNAME => 'user2',
487
-			FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME => 'User Two',
488
-			FilesPlugin::FILEID_PROPERTYNAME => 12345,
489
-			FilesPlugin::PERMISSIONS_PROPERTYNAME => 'C',
490
-			FilesPlugin::SIZE_PROPERTYNAME => 123,
491
-			FilesPlugin::DOWNLOADURL_PROPERTYNAME => 'http://example.com/',
492
-		]);
493
-
494
-		$this->plugin->handleUpdateProperties(
495
-			'/dummypath',
496
-			$propPatch
497
-		);
498
-
499
-		$propPatch->commit();
500
-
501
-		$this->assertEmpty($propPatch->getRemainingMutations());
502
-
503
-		$result = $propPatch->getResult();
504
-		$this->assertEquals(403, $result[FilesPlugin::OWNER_ID_PROPERTYNAME]);
505
-		$this->assertEquals(403, $result[FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME]);
506
-		$this->assertEquals(403, $result[FilesPlugin::FILEID_PROPERTYNAME]);
507
-		$this->assertEquals(403, $result[FilesPlugin::PERMISSIONS_PROPERTYNAME]);
508
-		$this->assertEquals(403, $result[FilesPlugin::SIZE_PROPERTYNAME]);
509
-		$this->assertEquals(403, $result[FilesPlugin::DOWNLOADURL_PROPERTYNAME]);
510
-	}
511
-
512
-	/**
513
-	 * Test case from https://github.com/owncloud/core/issues/5251
514
-	 *
515
-	 * |-FolderA
516
-	 *  |-text.txt
517
-	 * |-test.txt
518
-	 *
519
-	 * FolderA is an incoming shared folder and there are no delete permissions.
520
-	 * Thus moving /FolderA/test.txt to /test.txt should fail already on that check
521
-	 *
522
-	 */
523
-	public function testMoveSrcNotDeletable(): void {
524
-		$this->expectException(\Sabre\DAV\Exception\Forbidden::class);
525
-		$this->expectExceptionMessage('FolderA/test.txt cannot be deleted');
526
-
527
-		$fileInfoFolderATestTXT = $this->createMock(FileInfo::class);
528
-		$fileInfoFolderATestTXT->expects($this->once())
529
-			->method('isDeletable')
530
-			->willReturn(false);
531
-
532
-		$node = $this->createMock(Node::class);
533
-		$node->expects($this->atLeastOnce())
534
-			->method('getFileInfo')
535
-			->willReturn($fileInfoFolderATestTXT);
536
-
537
-		$this->tree->expects($this->atLeastOnce())
538
-			->method('getNodeForPath')
539
-			->willReturn($node);
540
-
541
-		$this->plugin->checkMove('FolderA/test.txt', 'test.txt');
542
-	}
543
-
544
-	public function testMoveSrcDeletable(): void {
545
-		$fileInfoFolderATestTXT = $this->createMock(FileInfo::class);
546
-		$fileInfoFolderATestTXT->expects($this->once())
547
-			->method('isDeletable')
548
-			->willReturn(true);
549
-
550
-		$node = $this->createMock(Node::class);
551
-		$node->expects($this->atLeastOnce())
552
-			->method('getFileInfo')
553
-			->willReturn($fileInfoFolderATestTXT);
554
-
555
-		$this->tree->expects($this->atLeastOnce())
556
-			->method('getNodeForPath')
557
-			->willReturn($node);
558
-
559
-		$this->plugin->checkMove('FolderA/test.txt', 'test.txt');
560
-	}
561
-
562
-	public function testMoveSrcNotExist(): void {
563
-		$this->expectException(\Sabre\DAV\Exception\NotFound::class);
564
-		$this->expectExceptionMessage('FolderA/test.txt does not exist');
565
-
566
-		$node = $this->createMock(Node::class);
567
-		$node->expects($this->atLeastOnce())
568
-			->method('getFileInfo')
569
-			->willReturn(null);
570
-
571
-		$this->tree->expects($this->atLeastOnce())
572
-			->method('getNodeForPath')
573
-			->willReturn($node);
574
-
575
-		$this->plugin->checkMove('FolderA/test.txt', 'test.txt');
576
-	}
577
-
578
-	public function testMoveDestinationInvalid(): void {
579
-		$this->expectException(InvalidPath::class);
580
-		$this->expectExceptionMessage('Mocked exception');
581
-
582
-		$fileInfoFolderATestTXT = $this->createMock(FileInfo::class);
583
-		$fileInfoFolderATestTXT->expects(self::any())
584
-			->method('isDeletable')
585
-			->willReturn(true);
586
-
587
-		$node = $this->createMock(Node::class);
588
-		$node->expects($this->atLeastOnce())
589
-			->method('getFileInfo')
590
-			->willReturn($fileInfoFolderATestTXT);
591
-
592
-		$this->tree->expects($this->atLeastOnce())
593
-			->method('getNodeForPath')
594
-			->willReturn($node);
595
-
596
-		$this->filenameValidator->expects(self::once())
597
-			->method('validateFilename')
598
-			->with('invalid\\path.txt')
599
-			->willThrowException(new InvalidPathException('Mocked exception'));
600
-
601
-		$this->plugin->checkMove('FolderA/test.txt', 'invalid\\path.txt');
602
-	}
603
-
604
-	public function testCopySrcNotExist(): void {
605
-		$this->expectException(\Sabre\DAV\Exception\NotFound::class);
606
-		$this->expectExceptionMessage('FolderA/test.txt does not exist');
607
-
608
-		$node = $this->createMock(Node::class);
609
-		$node->expects($this->atLeastOnce())
610
-			->method('getFileInfo')
611
-			->willReturn(null);
612
-
613
-		$this->tree->expects($this->atLeastOnce())
614
-			->method('getNodeForPath')
615
-			->willReturn($node);
616
-
617
-		$this->plugin->checkCopy('FolderA/test.txt', 'test.txt');
618
-	}
619
-
620
-	public function testCopyDestinationInvalid(): void {
621
-		$this->expectException(InvalidPath::class);
622
-		$this->expectExceptionMessage('Mocked exception');
623
-
624
-		$fileInfoFolderATestTXT = $this->createMock(FileInfo::class);
625
-		$node = $this->createMock(Node::class);
626
-		$node->expects($this->atLeastOnce())
627
-			->method('getFileInfo')
628
-			->willReturn($fileInfoFolderATestTXT);
629
-
630
-		$this->tree->expects($this->atLeastOnce())
631
-			->method('getNodeForPath')
632
-			->willReturn($node);
633
-
634
-		$this->filenameValidator->expects(self::once())
635
-			->method('validateFilename')
636
-			->with('invalid\\path.txt')
637
-			->willThrowException(new InvalidPathException('Mocked exception'));
638
-
639
-		$this->plugin->checkCopy('FolderA/test.txt', 'invalid\\path.txt');
640
-	}
641
-
642
-	public static function downloadHeadersProvider(): array {
643
-		return [
644
-			[
645
-				false,
646
-				'attachment; filename*=UTF-8\'\'somefile.xml; filename="somefile.xml"'
647
-			],
648
-			[
649
-				true,
650
-				'attachment; filename="somefile.xml"'
651
-			],
652
-		];
653
-	}
654
-
655
-	#[\PHPUnit\Framework\Attributes\DataProvider('downloadHeadersProvider')]
656
-	public function testDownloadHeaders(bool $isClumsyAgent, string $contentDispositionHeader): void {
657
-		$request = $this->createMock(RequestInterface::class);
658
-		$response = $this->createMock(ResponseInterface::class);
659
-
660
-		$request
661
-			->expects($this->once())
662
-			->method('getPath')
663
-			->willReturn('test/somefile.xml');
664
-
665
-		$node = $this->createMock(File::class);
666
-		$node
667
-			->expects($this->once())
668
-			->method('getName')
669
-			->willReturn('somefile.xml');
670
-
671
-		$this->tree
672
-			->expects($this->once())
673
-			->method('getNodeForPath')
674
-			->with('test/somefile.xml')
675
-			->willReturn($node);
676
-
677
-		$this->request
678
-			->expects($this->once())
679
-			->method('isUserAgent')
680
-			->willReturn($isClumsyAgent);
681
-
682
-		$calls = [
683
-			['Content-Disposition', $contentDispositionHeader],
684
-			['X-Accel-Buffering', 'no'],
685
-		];
686
-		$response
687
-			->expects($this->exactly(count($calls)))
688
-			->method('addHeader')
689
-			->willReturnCallback(function () use (&$calls): void {
690
-				$expected = array_shift($calls);
691
-				$this->assertSame($expected, func_get_args());
692
-			});
693
-
694
-		$this->plugin->httpGet($request, $response);
695
-	}
696
-
697
-	public function testHasPreview(): void {
698
-		/** @var Directory&MockObject $node */
699
-		$node = $this->createTestNode(Directory::class);
700
-
701
-		$propFind = new PropFind(
702
-			'/dummyPath',
703
-			[
704
-				FilesPlugin::HAS_PREVIEW_PROPERTYNAME
705
-			],
706
-			0
707
-		);
708
-
709
-		$this->previewManager->expects($this->once())
710
-			->method('isAvailable')
711
-			->willReturn(false);
712
-
713
-		$this->plugin->handleGetProperties(
714
-			$propFind,
715
-			$node
716
-		);
717
-
718
-		$this->assertEquals('false', $propFind->get(FilesPlugin::HAS_PREVIEW_PROPERTYNAME));
719
-	}
43
+    private Tree&MockObject $tree;
44
+    private Server&MockObject $server;
45
+    private IConfig&MockObject $config;
46
+    private IRequest&MockObject $request;
47
+    private IPreview&MockObject $previewManager;
48
+    private IUserSession&MockObject $userSession;
49
+    private IFilenameValidator&MockObject $filenameValidator;
50
+    private IAccountManager&MockObject $accountManager;
51
+    private FilesPlugin $plugin;
52
+
53
+    protected function setUp(): void {
54
+        parent::setUp();
55
+        $this->server = $this->createMock(Server::class);
56
+        $this->tree = $this->createMock(Tree::class);
57
+        $this->config = $this->createMock(IConfig::class);
58
+        $this->config->expects($this->any())->method('getSystemValue')
59
+            ->with($this->equalTo('data-fingerprint'), $this->equalTo(''))
60
+            ->willReturn('my_fingerprint');
61
+        $this->request = $this->createMock(IRequest::class);
62
+        $this->previewManager = $this->createMock(IPreview::class);
63
+        $this->userSession = $this->createMock(IUserSession::class);
64
+        $this->filenameValidator = $this->createMock(IFilenameValidator::class);
65
+        $this->accountManager = $this->createMock(IAccountManager::class);
66
+
67
+        $this->plugin = new FilesPlugin(
68
+            $this->tree,
69
+            $this->config,
70
+            $this->request,
71
+            $this->previewManager,
72
+            $this->userSession,
73
+            $this->filenameValidator,
74
+            $this->accountManager,
75
+        );
76
+
77
+        $response = $this->createMock(ResponseInterface::class);
78
+        $this->server->httpResponse = $response;
79
+        $this->server->xml = new Service();
80
+
81
+        $this->plugin->initialize($this->server);
82
+    }
83
+
84
+    private function createTestNode(string $class, string $path = '/dummypath'): MockObject {
85
+        $node = $this->createMock($class);
86
+
87
+        $node->expects($this->any())
88
+            ->method('getId')
89
+            ->willReturn(123);
90
+
91
+        $this->tree->expects($this->any())
92
+            ->method('getNodeForPath')
93
+            ->with($path)
94
+            ->willReturn($node);
95
+
96
+        $node->expects($this->any())
97
+            ->method('getFileId')
98
+            ->willReturn('00000123instanceid');
99
+        $node->expects($this->any())
100
+            ->method('getInternalFileId')
101
+            ->willReturn('123');
102
+        $node->expects($this->any())
103
+            ->method('getEtag')
104
+            ->willReturn('"abc"');
105
+        $node->expects($this->any())
106
+            ->method('getDavPermissions')
107
+            ->willReturn('DWCKMSR');
108
+
109
+        $fileInfo = $this->createMock(FileInfo::class);
110
+        $fileInfo->expects($this->any())
111
+            ->method('isReadable')
112
+            ->willReturn(true);
113
+        $fileInfo->expects($this->any())
114
+            ->method('getCreationTime')
115
+            ->willReturn(123456789);
116
+
117
+        $node->expects($this->any())
118
+            ->method('getFileInfo')
119
+            ->willReturn($fileInfo);
120
+
121
+        return $node;
122
+    }
123
+
124
+    public function testGetPropertiesForFile(): void {
125
+        /** @var File&MockObject $node */
126
+        $node = $this->createTestNode(File::class);
127
+
128
+        $propFind = new PropFind(
129
+            '/dummyPath',
130
+            [
131
+                FilesPlugin::GETETAG_PROPERTYNAME,
132
+                FilesPlugin::FILEID_PROPERTYNAME,
133
+                FilesPlugin::INTERNAL_FILEID_PROPERTYNAME,
134
+                FilesPlugin::SIZE_PROPERTYNAME,
135
+                FilesPlugin::PERMISSIONS_PROPERTYNAME,
136
+                FilesPlugin::DOWNLOADURL_PROPERTYNAME,
137
+                FilesPlugin::OWNER_ID_PROPERTYNAME,
138
+                FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME,
139
+                FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME,
140
+                FilesPlugin::CREATIONDATE_PROPERTYNAME,
141
+            ],
142
+            0
143
+        );
144
+
145
+        $user = $this->createMock(User::class);
146
+        $user
147
+            ->expects($this->once())
148
+            ->method('getUID')
149
+            ->willReturn('foo');
150
+        $user
151
+            ->expects($this->once())
152
+            ->method('getDisplayName')
153
+            ->willReturn('M. Foo');
154
+
155
+        $owner = $this->createMock(Account::class);
156
+        $this->accountManager->expects($this->once())
157
+            ->method('getAccount')
158
+            ->with($user)
159
+            ->willReturn($owner);
160
+
161
+        $node->expects($this->once())
162
+            ->method('getDirectDownload')
163
+            ->willReturn(['url' => 'http://example.com/']);
164
+        $node->expects($this->exactly(2))
165
+            ->method('getOwner')
166
+            ->willReturn($user);
167
+
168
+        $displayNameProp = $this->createMock(AccountProperty::class);
169
+        $owner
170
+            ->expects($this->once())
171
+            ->method('getProperty')
172
+            ->with(IAccountManager::PROPERTY_DISPLAYNAME)
173
+            ->willReturn($displayNameProp);
174
+        $displayNameProp
175
+            ->expects($this->once())
176
+            ->method('getScope')
177
+            ->willReturn(IAccountManager::SCOPE_PUBLISHED);
178
+
179
+        $this->plugin->handleGetProperties(
180
+            $propFind,
181
+            $node
182
+        );
183
+
184
+        $this->assertEquals('"abc"', $propFind->get(FilesPlugin::GETETAG_PROPERTYNAME));
185
+        $this->assertEquals('00000123instanceid', $propFind->get(FilesPlugin::FILEID_PROPERTYNAME));
186
+        $this->assertEquals('123', $propFind->get(FilesPlugin::INTERNAL_FILEID_PROPERTYNAME));
187
+        $this->assertEquals('1973-11-29T21:33:09+00:00', $propFind->get(FilesPlugin::CREATIONDATE_PROPERTYNAME));
188
+        $this->assertEquals(0, $propFind->get(FilesPlugin::SIZE_PROPERTYNAME));
189
+        $this->assertEquals('DWCKMSR', $propFind->get(FilesPlugin::PERMISSIONS_PROPERTYNAME));
190
+        $this->assertEquals('http://example.com/', $propFind->get(FilesPlugin::DOWNLOADURL_PROPERTYNAME));
191
+        $this->assertEquals('foo', $propFind->get(FilesPlugin::OWNER_ID_PROPERTYNAME));
192
+        $this->assertEquals('M. Foo', $propFind->get(FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME));
193
+        $this->assertEquals('my_fingerprint', $propFind->get(FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME));
194
+        $this->assertEquals([], $propFind->get404Properties());
195
+    }
196
+
197
+    public function testGetDisplayNamePropertyWhenNotPublished(): void {
198
+        $node = $this->createTestNode(File::class);
199
+        $propFind = new PropFind(
200
+            '/dummyPath',
201
+            [
202
+                FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME,
203
+            ],
204
+            0
205
+        );
206
+
207
+        $this->userSession->expects($this->once())
208
+            ->method('getUser')
209
+            ->willReturn(null);
210
+
211
+        $user = $this->createMock(User::class);
212
+
213
+        $user->expects($this->never())
214
+            ->method('getDisplayName');
215
+
216
+        $owner = $this->createMock(Account::class);
217
+        $this->accountManager->expects($this->once())
218
+            ->method('getAccount')
219
+            ->with($user)
220
+            ->willReturn($owner);
221
+
222
+        $node->expects($this->once())
223
+            ->method('getOwner')
224
+            ->willReturn($user);
225
+
226
+        $displayNameProp = $this->createMock(AccountProperty::class);
227
+        $owner
228
+            ->expects($this->once())
229
+            ->method('getProperty')
230
+            ->with(IAccountManager::PROPERTY_DISPLAYNAME)
231
+            ->willReturn($displayNameProp);
232
+        $displayNameProp
233
+            ->expects($this->once())
234
+            ->method('getScope')
235
+            ->willReturn(IAccountManager::SCOPE_PRIVATE);
236
+
237
+        $this->plugin->handleGetProperties(
238
+            $propFind,
239
+            $node
240
+        );
241
+
242
+        $this->assertEquals(null, $propFind->get(FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME));
243
+    }
244
+
245
+    public function testGetDisplayNamePropertyWhenNotPublishedButLoggedIn(): void {
246
+        $node = $this->createTestNode(File::class);
247
+
248
+        $propFind = new PropFind(
249
+            '/dummyPath',
250
+            [
251
+                FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME,
252
+            ],
253
+            0
254
+        );
255
+
256
+        $user = $this->createMock(User::class);
257
+
258
+        $node->expects($this->once())
259
+            ->method('getOwner')
260
+            ->willReturn($user);
261
+
262
+        $loggedInUser = $this->createMock(User::class);
263
+        $this->userSession->expects($this->once())
264
+            ->method('getUser')
265
+            ->willReturn($loggedInUser);
266
+
267
+        $user
268
+            ->expects($this->once())
269
+            ->method('getDisplayName')
270
+            ->willReturn('M. Foo');
271
+
272
+        $this->accountManager->expects($this->never())
273
+            ->method('getAccount');
274
+
275
+        $this->plugin->handleGetProperties(
276
+            $propFind,
277
+            $node
278
+        );
279
+
280
+        $this->assertEquals('M. Foo', $propFind->get(FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME));
281
+    }
282
+
283
+    public function testGetPropertiesStorageNotAvailable(): void {
284
+        /** @var File&MockObject $node */
285
+        $node = $this->createTestNode(File::class);
286
+
287
+        $propFind = new PropFind(
288
+            '/dummyPath',
289
+            [
290
+                FilesPlugin::DOWNLOADURL_PROPERTYNAME,
291
+            ],
292
+            0
293
+        );
294
+
295
+        $node->expects($this->once())
296
+            ->method('getDirectDownload')
297
+            ->willThrowException(new StorageNotAvailableException());
298
+
299
+        $this->plugin->handleGetProperties(
300
+            $propFind,
301
+            $node
302
+        );
303
+
304
+        $this->assertEquals(null, $propFind->get(FilesPlugin::DOWNLOADURL_PROPERTYNAME));
305
+    }
306
+
307
+    public function testGetPublicPermissions(): void {
308
+        /** @var IRequest&MockObject */
309
+        $request = $this->createMock(IRequest::class);
310
+        $this->plugin = new FilesPlugin(
311
+            $this->tree,
312
+            $this->config,
313
+            $request,
314
+            $this->previewManager,
315
+            $this->userSession,
316
+            $this->filenameValidator,
317
+            $this->accountManager,
318
+            true,
319
+        );
320
+        $this->plugin->initialize($this->server);
321
+
322
+        $propFind = new PropFind(
323
+            '/dummyPath',
324
+            [
325
+                FilesPlugin::PERMISSIONS_PROPERTYNAME,
326
+            ],
327
+            0
328
+        );
329
+
330
+        /** @var File&MockObject $node */
331
+        $node = $this->createTestNode(File::class);
332
+        $node->expects($this->any())
333
+            ->method('getDavPermissions')
334
+            ->willReturn('DWCKMSR');
335
+
336
+        $this->plugin->handleGetProperties(
337
+            $propFind,
338
+            $node
339
+        );
340
+
341
+        $this->assertEquals('DWCKR', $propFind->get(FilesPlugin::PERMISSIONS_PROPERTYNAME));
342
+    }
343
+
344
+    public function testGetPropertiesForDirectory(): void {
345
+        /** @var Directory&MockObject $node */
346
+        $node = $this->createTestNode(Directory::class);
347
+
348
+        $propFind = new PropFind(
349
+            '/dummyPath',
350
+            [
351
+                FilesPlugin::GETETAG_PROPERTYNAME,
352
+                FilesPlugin::FILEID_PROPERTYNAME,
353
+                FilesPlugin::SIZE_PROPERTYNAME,
354
+                FilesPlugin::PERMISSIONS_PROPERTYNAME,
355
+                FilesPlugin::DOWNLOADURL_PROPERTYNAME,
356
+                FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME,
357
+            ],
358
+            0
359
+        );
360
+
361
+        $node->expects($this->once())
362
+            ->method('getSize')
363
+            ->willReturn(1025);
364
+
365
+        $this->plugin->handleGetProperties(
366
+            $propFind,
367
+            $node
368
+        );
369
+
370
+        $this->assertEquals('"abc"', $propFind->get(FilesPlugin::GETETAG_PROPERTYNAME));
371
+        $this->assertEquals('00000123instanceid', $propFind->get(FilesPlugin::FILEID_PROPERTYNAME));
372
+        $this->assertEquals(1025, $propFind->get(FilesPlugin::SIZE_PROPERTYNAME));
373
+        $this->assertEquals('DWCKMSR', $propFind->get(FilesPlugin::PERMISSIONS_PROPERTYNAME));
374
+        $this->assertEquals(null, $propFind->get(FilesPlugin::DOWNLOADURL_PROPERTYNAME));
375
+        $this->assertEquals('my_fingerprint', $propFind->get(FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME));
376
+        $this->assertEquals([FilesPlugin::DOWNLOADURL_PROPERTYNAME], $propFind->get404Properties());
377
+    }
378
+
379
+    public function testGetPropertiesForRootDirectory(): void {
380
+        /** @var Directory&MockObject $node */
381
+        $node = $this->createMock(Directory::class);
382
+        $node->expects($this->any())->method('getPath')->willReturn('/');
383
+
384
+        $fileInfo = $this->createMock(FileInfo::class);
385
+        $fileInfo->expects($this->any())
386
+            ->method('isReadable')
387
+            ->willReturn(true);
388
+
389
+        $node->expects($this->any())
390
+            ->method('getFileInfo')
391
+            ->willReturn($fileInfo);
392
+
393
+        $propFind = new PropFind(
394
+            '/',
395
+            [
396
+                FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME,
397
+            ],
398
+            0
399
+        );
400
+
401
+        $this->plugin->handleGetProperties(
402
+            $propFind,
403
+            $node
404
+        );
405
+
406
+        $this->assertEquals('my_fingerprint', $propFind->get(FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME));
407
+    }
408
+
409
+    public function testGetPropertiesWhenNoPermission(): void {
410
+        // No read permissions can be caused by files access control.
411
+        // But we still want to load the directory list, so this is okay for us.
412
+        // $this->expectException(\Sabre\DAV\Exception\NotFound::class);
413
+        /** @var Directory&MockObject $node */
414
+        $node = $this->createMock(Directory::class);
415
+        $node->expects($this->any())->method('getPath')->willReturn('/');
416
+
417
+        $fileInfo = $this->createMock(FileInfo::class);
418
+        $fileInfo->expects($this->any())
419
+            ->method('isReadable')
420
+            ->willReturn(false);
421
+
422
+        $node->expects($this->any())
423
+            ->method('getFileInfo')
424
+            ->willReturn($fileInfo);
425
+
426
+        $propFind = new PropFind(
427
+            '/test',
428
+            [
429
+                FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME,
430
+            ],
431
+            0
432
+        );
433
+
434
+        $this->plugin->handleGetProperties(
435
+            $propFind,
436
+            $node
437
+        );
438
+
439
+        $this->addToAssertionCount(1);
440
+    }
441
+
442
+    public function testUpdateProps(): void {
443
+        $node = $this->createTestNode(File::class);
444
+
445
+        $testDate = 'Fri, 13 Feb 2015 00:01:02 GMT';
446
+        $testCreationDate = '2007-08-31T16:47+00:00';
447
+
448
+        $node->expects($this->once())
449
+            ->method('touch')
450
+            ->with($testDate);
451
+
452
+        $node->expects($this->once())
453
+            ->method('setEtag')
454
+            ->with('newetag')
455
+            ->willReturn(true);
456
+
457
+        $node->expects($this->once())
458
+            ->method('setCreationTime')
459
+            ->with('1188578820');
460
+
461
+        // properties to set
462
+        $propPatch = new PropPatch([
463
+            FilesPlugin::GETETAG_PROPERTYNAME => 'newetag',
464
+            FilesPlugin::LASTMODIFIED_PROPERTYNAME => $testDate,
465
+            FilesPlugin::CREATIONDATE_PROPERTYNAME => $testCreationDate,
466
+        ]);
467
+
468
+
469
+        $this->plugin->handleUpdateProperties(
470
+            '/dummypath',
471
+            $propPatch
472
+        );
473
+
474
+        $propPatch->commit();
475
+
476
+        $this->assertEmpty($propPatch->getRemainingMutations());
477
+
478
+        $result = $propPatch->getResult();
479
+        $this->assertEquals(200, $result[FilesPlugin::LASTMODIFIED_PROPERTYNAME]);
480
+        $this->assertEquals(200, $result[FilesPlugin::GETETAG_PROPERTYNAME]);
481
+        $this->assertEquals(200, $result[FilesPlugin::CREATIONDATE_PROPERTYNAME]);
482
+    }
483
+
484
+    public function testUpdatePropsForbidden(): void {
485
+        $propPatch = new PropPatch([
486
+            FilesPlugin::OWNER_ID_PROPERTYNAME => 'user2',
487
+            FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME => 'User Two',
488
+            FilesPlugin::FILEID_PROPERTYNAME => 12345,
489
+            FilesPlugin::PERMISSIONS_PROPERTYNAME => 'C',
490
+            FilesPlugin::SIZE_PROPERTYNAME => 123,
491
+            FilesPlugin::DOWNLOADURL_PROPERTYNAME => 'http://example.com/',
492
+        ]);
493
+
494
+        $this->plugin->handleUpdateProperties(
495
+            '/dummypath',
496
+            $propPatch
497
+        );
498
+
499
+        $propPatch->commit();
500
+
501
+        $this->assertEmpty($propPatch->getRemainingMutations());
502
+
503
+        $result = $propPatch->getResult();
504
+        $this->assertEquals(403, $result[FilesPlugin::OWNER_ID_PROPERTYNAME]);
505
+        $this->assertEquals(403, $result[FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME]);
506
+        $this->assertEquals(403, $result[FilesPlugin::FILEID_PROPERTYNAME]);
507
+        $this->assertEquals(403, $result[FilesPlugin::PERMISSIONS_PROPERTYNAME]);
508
+        $this->assertEquals(403, $result[FilesPlugin::SIZE_PROPERTYNAME]);
509
+        $this->assertEquals(403, $result[FilesPlugin::DOWNLOADURL_PROPERTYNAME]);
510
+    }
511
+
512
+    /**
513
+     * Test case from https://github.com/owncloud/core/issues/5251
514
+     *
515
+     * |-FolderA
516
+     *  |-text.txt
517
+     * |-test.txt
518
+     *
519
+     * FolderA is an incoming shared folder and there are no delete permissions.
520
+     * Thus moving /FolderA/test.txt to /test.txt should fail already on that check
521
+     *
522
+     */
523
+    public function testMoveSrcNotDeletable(): void {
524
+        $this->expectException(\Sabre\DAV\Exception\Forbidden::class);
525
+        $this->expectExceptionMessage('FolderA/test.txt cannot be deleted');
526
+
527
+        $fileInfoFolderATestTXT = $this->createMock(FileInfo::class);
528
+        $fileInfoFolderATestTXT->expects($this->once())
529
+            ->method('isDeletable')
530
+            ->willReturn(false);
531
+
532
+        $node = $this->createMock(Node::class);
533
+        $node->expects($this->atLeastOnce())
534
+            ->method('getFileInfo')
535
+            ->willReturn($fileInfoFolderATestTXT);
536
+
537
+        $this->tree->expects($this->atLeastOnce())
538
+            ->method('getNodeForPath')
539
+            ->willReturn($node);
540
+
541
+        $this->plugin->checkMove('FolderA/test.txt', 'test.txt');
542
+    }
543
+
544
+    public function testMoveSrcDeletable(): void {
545
+        $fileInfoFolderATestTXT = $this->createMock(FileInfo::class);
546
+        $fileInfoFolderATestTXT->expects($this->once())
547
+            ->method('isDeletable')
548
+            ->willReturn(true);
549
+
550
+        $node = $this->createMock(Node::class);
551
+        $node->expects($this->atLeastOnce())
552
+            ->method('getFileInfo')
553
+            ->willReturn($fileInfoFolderATestTXT);
554
+
555
+        $this->tree->expects($this->atLeastOnce())
556
+            ->method('getNodeForPath')
557
+            ->willReturn($node);
558
+
559
+        $this->plugin->checkMove('FolderA/test.txt', 'test.txt');
560
+    }
561
+
562
+    public function testMoveSrcNotExist(): void {
563
+        $this->expectException(\Sabre\DAV\Exception\NotFound::class);
564
+        $this->expectExceptionMessage('FolderA/test.txt does not exist');
565
+
566
+        $node = $this->createMock(Node::class);
567
+        $node->expects($this->atLeastOnce())
568
+            ->method('getFileInfo')
569
+            ->willReturn(null);
570
+
571
+        $this->tree->expects($this->atLeastOnce())
572
+            ->method('getNodeForPath')
573
+            ->willReturn($node);
574
+
575
+        $this->plugin->checkMove('FolderA/test.txt', 'test.txt');
576
+    }
577
+
578
+    public function testMoveDestinationInvalid(): void {
579
+        $this->expectException(InvalidPath::class);
580
+        $this->expectExceptionMessage('Mocked exception');
581
+
582
+        $fileInfoFolderATestTXT = $this->createMock(FileInfo::class);
583
+        $fileInfoFolderATestTXT->expects(self::any())
584
+            ->method('isDeletable')
585
+            ->willReturn(true);
586
+
587
+        $node = $this->createMock(Node::class);
588
+        $node->expects($this->atLeastOnce())
589
+            ->method('getFileInfo')
590
+            ->willReturn($fileInfoFolderATestTXT);
591
+
592
+        $this->tree->expects($this->atLeastOnce())
593
+            ->method('getNodeForPath')
594
+            ->willReturn($node);
595
+
596
+        $this->filenameValidator->expects(self::once())
597
+            ->method('validateFilename')
598
+            ->with('invalid\\path.txt')
599
+            ->willThrowException(new InvalidPathException('Mocked exception'));
600
+
601
+        $this->plugin->checkMove('FolderA/test.txt', 'invalid\\path.txt');
602
+    }
603
+
604
+    public function testCopySrcNotExist(): void {
605
+        $this->expectException(\Sabre\DAV\Exception\NotFound::class);
606
+        $this->expectExceptionMessage('FolderA/test.txt does not exist');
607
+
608
+        $node = $this->createMock(Node::class);
609
+        $node->expects($this->atLeastOnce())
610
+            ->method('getFileInfo')
611
+            ->willReturn(null);
612
+
613
+        $this->tree->expects($this->atLeastOnce())
614
+            ->method('getNodeForPath')
615
+            ->willReturn($node);
616
+
617
+        $this->plugin->checkCopy('FolderA/test.txt', 'test.txt');
618
+    }
619
+
620
+    public function testCopyDestinationInvalid(): void {
621
+        $this->expectException(InvalidPath::class);
622
+        $this->expectExceptionMessage('Mocked exception');
623
+
624
+        $fileInfoFolderATestTXT = $this->createMock(FileInfo::class);
625
+        $node = $this->createMock(Node::class);
626
+        $node->expects($this->atLeastOnce())
627
+            ->method('getFileInfo')
628
+            ->willReturn($fileInfoFolderATestTXT);
629
+
630
+        $this->tree->expects($this->atLeastOnce())
631
+            ->method('getNodeForPath')
632
+            ->willReturn($node);
633
+
634
+        $this->filenameValidator->expects(self::once())
635
+            ->method('validateFilename')
636
+            ->with('invalid\\path.txt')
637
+            ->willThrowException(new InvalidPathException('Mocked exception'));
638
+
639
+        $this->plugin->checkCopy('FolderA/test.txt', 'invalid\\path.txt');
640
+    }
641
+
642
+    public static function downloadHeadersProvider(): array {
643
+        return [
644
+            [
645
+                false,
646
+                'attachment; filename*=UTF-8\'\'somefile.xml; filename="somefile.xml"'
647
+            ],
648
+            [
649
+                true,
650
+                'attachment; filename="somefile.xml"'
651
+            ],
652
+        ];
653
+    }
654
+
655
+    #[\PHPUnit\Framework\Attributes\DataProvider('downloadHeadersProvider')]
656
+    public function testDownloadHeaders(bool $isClumsyAgent, string $contentDispositionHeader): void {
657
+        $request = $this->createMock(RequestInterface::class);
658
+        $response = $this->createMock(ResponseInterface::class);
659
+
660
+        $request
661
+            ->expects($this->once())
662
+            ->method('getPath')
663
+            ->willReturn('test/somefile.xml');
664
+
665
+        $node = $this->createMock(File::class);
666
+        $node
667
+            ->expects($this->once())
668
+            ->method('getName')
669
+            ->willReturn('somefile.xml');
670
+
671
+        $this->tree
672
+            ->expects($this->once())
673
+            ->method('getNodeForPath')
674
+            ->with('test/somefile.xml')
675
+            ->willReturn($node);
676
+
677
+        $this->request
678
+            ->expects($this->once())
679
+            ->method('isUserAgent')
680
+            ->willReturn($isClumsyAgent);
681
+
682
+        $calls = [
683
+            ['Content-Disposition', $contentDispositionHeader],
684
+            ['X-Accel-Buffering', 'no'],
685
+        ];
686
+        $response
687
+            ->expects($this->exactly(count($calls)))
688
+            ->method('addHeader')
689
+            ->willReturnCallback(function () use (&$calls): void {
690
+                $expected = array_shift($calls);
691
+                $this->assertSame($expected, func_get_args());
692
+            });
693
+
694
+        $this->plugin->httpGet($request, $response);
695
+    }
696
+
697
+    public function testHasPreview(): void {
698
+        /** @var Directory&MockObject $node */
699
+        $node = $this->createTestNode(Directory::class);
700
+
701
+        $propFind = new PropFind(
702
+            '/dummyPath',
703
+            [
704
+                FilesPlugin::HAS_PREVIEW_PROPERTYNAME
705
+            ],
706
+            0
707
+        );
708
+
709
+        $this->previewManager->expects($this->once())
710
+            ->method('isAvailable')
711
+            ->willReturn(false);
712
+
713
+        $this->plugin->handleGetProperties(
714
+            $propFind,
715
+            $node
716
+        );
717
+
718
+        $this->assertEquals('false', $propFind->get(FilesPlugin::HAS_PREVIEW_PROPERTYNAME));
719
+    }
720 720
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -686,7 +686,7 @@
 block discarded – undo
686 686
 		$response
687 687
 			->expects($this->exactly(count($calls)))
688 688
 			->method('addHeader')
689
-			->willReturnCallback(function () use (&$calls): void {
689
+			->willReturnCallback(function() use (&$calls): void {
690 690
 				$expected = array_shift($calls);
691 691
 				$this->assertSame($expected, func_get_args());
692 692
 			});
Please login to merge, or discard this patch.
apps/dav/tests/unit/CardDAV/AddressBookImplTest.php 1 patch
Indentation   +514 added lines, -514 removed lines patch added patch discarded remove patch
@@ -19,518 +19,518 @@
 block discarded – undo
19 19
 use Test\TestCase;
20 20
 
21 21
 class AddressBookImplTest extends TestCase {
22
-	private array $addressBookInfo;
23
-	private AddressBook&MockObject $addressBook;
24
-	private IURLGenerator&MockObject $urlGenerator;
25
-	private CardDavBackend&MockObject $backend;
26
-	private PropertyMapper&MockObject $propertyMapper;
27
-	private VCard&MockObject $vCard;
28
-	private AddressBookImpl $addressBookImpl;
29
-
30
-	protected function setUp(): void {
31
-		parent::setUp();
32
-
33
-		$this->addressBookInfo = [
34
-			'id' => 42,
35
-			'uri' => 'system',
36
-			'principaluri' => 'principals/system/system',
37
-			'{DAV:}displayname' => 'display name',
38
-		];
39
-		$this->addressBook = $this->createMock(AddressBook::class);
40
-		$this->backend = $this->createMock(CardDavBackend::class);
41
-		$this->vCard = $this->createMock(VCard::class);
42
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
43
-		$this->propertyMapper = $this->createMock(PropertyMapper::class);
44
-
45
-		$this->addressBookImpl = new AddressBookImpl(
46
-			$this->addressBook,
47
-			$this->addressBookInfo,
48
-			$this->backend,
49
-			$this->urlGenerator,
50
-			$this->propertyMapper,
51
-			null
52
-		);
53
-	}
54
-
55
-	public function testGetKey(): void {
56
-		$this->assertSame($this->addressBookInfo['id'],
57
-			$this->addressBookImpl->getKey());
58
-	}
59
-
60
-	public function testGetDisplayName(): void {
61
-		$this->assertSame($this->addressBookInfo['{DAV:}displayname'],
62
-			$this->addressBookImpl->getDisplayName());
63
-	}
64
-
65
-	public function testSearch(): void {
66
-		/** @var MockObject&AddressBookImpl $addressBookImpl */
67
-		$addressBookImpl = $this->getMockBuilder(AddressBookImpl::class)
68
-			->setConstructorArgs(
69
-				[
70
-					$this->addressBook,
71
-					$this->addressBookInfo,
72
-					$this->backend,
73
-					$this->urlGenerator,
74
-					$this->propertyMapper,
75
-					null
76
-				]
77
-			)
78
-			->onlyMethods(['vCard2Array', 'readCard'])
79
-			->getMock();
80
-
81
-		$pattern = 'pattern';
82
-		$searchProperties = 'properties';
83
-
84
-		$this->backend->expects($this->once())->method('search')
85
-			->with($this->addressBookInfo['id'], $pattern, $searchProperties)
86
-			->willReturn(
87
-				[
88
-					['uri' => 'foo.vcf', 'carddata' => 'cardData1'],
89
-					['uri' => 'bar.vcf', 'carddata' => 'cardData2']
90
-				]
91
-			);
92
-
93
-		$addressBookImpl->expects($this->exactly(2))->method('readCard')
94
-			->willReturn($this->vCard);
95
-		$addressBookImpl->expects($this->exactly(2))->method('vCard2Array')
96
-			->willReturnMap([
97
-				['foo.vcf', $this->vCard, 'vCard'],
98
-				['bar.vcf', $this->vCard, 'vCard'],
99
-			]);
100
-
101
-		$result = $addressBookImpl->search($pattern, $searchProperties, []);
102
-		$this->assertTrue((is_array($result)));
103
-		$this->assertSame(2, count($result));
104
-	}
105
-
106
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestCreate')]
107
-	public function testCreate(array $properties): void {
108
-		$uid = 'uid';
109
-
110
-		/** @var MockObject&AddressBookImpl $addressBookImpl */
111
-		$addressBookImpl = $this->getMockBuilder(AddressBookImpl::class)
112
-			->setConstructorArgs(
113
-				[
114
-					$this->addressBook,
115
-					$this->addressBookInfo,
116
-					$this->backend,
117
-					$this->urlGenerator,
118
-					$this->propertyMapper,
119
-					null
120
-				]
121
-			)
122
-			->onlyMethods(['vCard2Array', 'createUid', 'createEmptyVCard'])
123
-			->getMock();
124
-
125
-		$expectedProperties = 0;
126
-		foreach ($properties as $data) {
127
-			if (is_string($data)) {
128
-				$expectedProperties++;
129
-			} else {
130
-				$expectedProperties += count($data);
131
-			}
132
-		}
133
-
134
-		$addressBookImpl->expects($this->once())->method('createUid')
135
-			->willReturn($uid);
136
-		$addressBookImpl->expects($this->once())->method('createEmptyVCard')
137
-			->with($uid)->willReturn($this->vCard);
138
-		$this->vCard->expects($this->exactly($expectedProperties))
139
-			->method('createProperty');
140
-		$this->backend->expects($this->once())->method('createCard');
141
-		$this->backend->expects($this->never())->method('updateCard');
142
-		$this->backend->expects($this->never())->method('getCard');
143
-		$addressBookImpl->expects($this->once())->method('vCard2Array')
144
-			->with('uid.vcf', $this->vCard)->willReturn(true);
145
-
146
-		$this->assertTrue($addressBookImpl->createOrUpdate($properties));
147
-	}
148
-
149
-	public static function dataTestCreate(): array {
150
-		return [
151
-			[[]],
152
-			[['FN' => 'John Doe']],
153
-			[['FN' => 'John Doe', 'EMAIL' => ['[email protected]', '[email protected]']]],
154
-		];
155
-	}
156
-
157
-	public function testUpdate(): void {
158
-		$uid = 'uid';
159
-		$uri = 'bla.vcf';
160
-		$properties = ['URI' => $uri, 'UID' => $uid, 'FN' => 'John Doe'];
161
-
162
-		/** @var MockObject&AddressBookImpl $addressBookImpl */
163
-		$addressBookImpl = $this->getMockBuilder(AddressBookImpl::class)
164
-			->setConstructorArgs(
165
-				[
166
-					$this->addressBook,
167
-					$this->addressBookInfo,
168
-					$this->backend,
169
-					$this->urlGenerator,
170
-					$this->propertyMapper,
171
-					null
172
-				]
173
-			)
174
-			->onlyMethods(['vCard2Array', 'createUid', 'createEmptyVCard', 'readCard'])
175
-			->getMock();
176
-
177
-		$addressBookImpl->expects($this->never())->method('createUid');
178
-		$addressBookImpl->expects($this->never())->method('createEmptyVCard');
179
-		$this->backend->expects($this->once())->method('getCard')
180
-			->with($this->addressBookInfo['id'], $uri)
181
-			->willReturn(['carddata' => 'data']);
182
-		$addressBookImpl->expects($this->once())->method('readCard')
183
-			->with('data')->willReturn($this->vCard);
184
-		$this->vCard->expects($this->exactly(count($properties) - 1))
185
-			->method('createProperty');
186
-		$this->backend->expects($this->never())->method('createCard');
187
-		$this->backend->expects($this->once())->method('updateCard');
188
-		$addressBookImpl->expects($this->once())->method('vCard2Array')
189
-			->with($uri, $this->vCard)->willReturn(true);
190
-
191
-		$this->assertTrue($addressBookImpl->createOrUpdate($properties));
192
-	}
193
-
194
-	public function testUpdateWithTypes(): void {
195
-		$uid = 'uid';
196
-		$uri = 'bla.vcf';
197
-		$properties = ['URI' => $uri, 'UID' => $uid, 'FN' => 'John Doe', 'ADR' => [['type' => 'HOME', 'value' => ';;street;city;;;country']]];
198
-		$vCard = new vCard;
199
-		$textProperty = $vCard->createProperty('KEY', 'value');
200
-
201
-		/** @var MockObject&AddressBookImpl $addressBookImpl */
202
-		$addressBookImpl = $this->getMockBuilder(AddressBookImpl::class)
203
-			->setConstructorArgs(
204
-				[
205
-					$this->addressBook,
206
-					$this->addressBookInfo,
207
-					$this->backend,
208
-					$this->urlGenerator,
209
-					$this->propertyMapper,
210
-					null
211
-				]
212
-			)
213
-			->onlyMethods(['vCard2Array', 'createUid', 'createEmptyVCard', 'readCard'])
214
-			->getMock();
215
-
216
-		$this->backend->expects($this->once())->method('getCard')
217
-			->with($this->addressBookInfo['id'], $uri)
218
-			->willReturn(['carddata' => 'data']);
219
-		$addressBookImpl->expects($this->once())->method('readCard')
220
-			->with('data')->willReturn($this->vCard);
221
-		$this->vCard->method('createProperty')->willReturn($textProperty);
222
-		$this->vCard->expects($this->exactly(count($properties) - 1))
223
-			->method('createProperty');
224
-		$this->vCard->expects($this->once())->method('remove')
225
-			->with('ADR');
226
-		$this->vCard->expects($this->once())->method('add');
227
-
228
-		$addressBookImpl->createOrUpdate($properties);
229
-	}
230
-
231
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestGetPermissions')]
232
-	public function testGetPermissions(array $permissions, int $expected): void {
233
-		$this->addressBook->expects($this->once())->method('getACL')
234
-			->willReturn($permissions);
235
-
236
-		$this->assertSame($expected,
237
-			$this->addressBookImpl->getPermissions()
238
-		);
239
-	}
240
-
241
-	public static function dataTestGetPermissions(): array {
242
-		return [
243
-			[[], 0],
244
-			[[['privilege' => '{DAV:}read']], 1],
245
-			[[['privilege' => '{DAV:}write']], 6],
246
-			[[['privilege' => '{DAV:}all']], 31],
247
-			[[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write']], 7],
248
-			[[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}all']], 31],
249
-			[[['privilege' => '{DAV:}all'],['privilege' => '{DAV:}write']], 31],
250
-			[[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write'],['privilege' => '{DAV:}all']], 31],
251
-			[[['privilege' => '{DAV:}all'],['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write']], 31],
252
-		];
253
-	}
254
-
255
-	public function testDelete(): void {
256
-		$cardId = 1;
257
-		$cardUri = 'cardUri';
258
-		$this->backend->expects($this->once())->method('getCardUri')
259
-			->with($cardId)->willReturn($cardUri);
260
-		$this->backend->expects($this->once())->method('deleteCard')
261
-			->with($this->addressBookInfo['id'], $cardUri)
262
-			->willReturn(true);
263
-
264
-		$this->assertTrue($this->addressBookImpl->delete($cardId));
265
-	}
266
-
267
-	public function testReadCard(): void {
268
-		$vCard = new VCard();
269
-		$vCard->add(new Text($vCard, 'UID', 'uid'));
270
-		$vCardSerialized = $vCard->serialize();
271
-
272
-		$result = $this->invokePrivate($this->addressBookImpl, 'readCard', [$vCardSerialized]);
273
-		$resultSerialized = $result->serialize();
274
-
275
-		$this->assertSame($vCardSerialized, $resultSerialized);
276
-	}
277
-
278
-	public function testCreateUid(): void {
279
-		/** @var MockObject&AddressBookImpl $addressBookImpl */
280
-		$addressBookImpl = $this->getMockBuilder(AddressBookImpl::class)
281
-			->setConstructorArgs(
282
-				[
283
-					$this->addressBook,
284
-					$this->addressBookInfo,
285
-					$this->backend,
286
-					$this->urlGenerator,
287
-					$this->propertyMapper,
288
-					null
289
-				]
290
-			)
291
-			->onlyMethods(['getUid'])
292
-			->getMock();
293
-
294
-		$addressBookImpl->expects($this->exactly(2))
295
-			->method('getUid')
296
-			->willReturnOnConsecutiveCalls(
297
-				'uid0',
298
-				'uid1',
299
-			);
300
-
301
-		// simulate that 'uid0' already exists, so the second uid will be returned
302
-		$this->backend->expects($this->exactly(2))->method('getContact')
303
-			->willReturnCallback(
304
-				function ($id, $uid) {
305
-					return ($uid === 'uid0.vcf');
306
-				}
307
-			);
308
-
309
-		$this->assertSame('uid1',
310
-			$this->invokePrivate($addressBookImpl, 'createUid', [])
311
-		);
312
-	}
313
-
314
-	public function testCreateEmptyVCard(): void {
315
-		$uid = 'uid';
316
-		$expectedVCard = new VCard();
317
-		$expectedVCard->UID = $uid;
318
-		$expectedVCardSerialized = $expectedVCard->serialize();
319
-
320
-		$result = $this->invokePrivate($this->addressBookImpl, 'createEmptyVCard', [$uid]);
321
-		$resultSerialized = $result->serialize();
322
-
323
-		$this->assertSame($expectedVCardSerialized, $resultSerialized);
324
-	}
325
-
326
-	public function testVCard2Array(): void {
327
-		$vCard = new VCard();
328
-
329
-		$vCard->add($vCard->createProperty('FN', 'Full Name'));
330
-
331
-		// Multi-value properties
332
-		$vCard->add($vCard->createProperty('CLOUD', 'cloud-user1@localhost'));
333
-		$vCard->add($vCard->createProperty('CLOUD', '[email protected]'));
334
-		$vCard->add($vCard->createProperty('EMAIL', 'email-user1@localhost'));
335
-		$vCard->add($vCard->createProperty('EMAIL', '[email protected]'));
336
-		$vCard->add($vCard->createProperty('IMPP', 'impp-user1@localhost'));
337
-		$vCard->add($vCard->createProperty('IMPP', '[email protected]'));
338
-		$vCard->add($vCard->createProperty('TEL', '+49 123456789'));
339
-		$vCard->add($vCard->createProperty('TEL', '+1 555 123456789'));
340
-		$vCard->add($vCard->createProperty('URL', 'https://localhost'));
341
-		$vCard->add($vCard->createProperty('URL', 'https://example.tld'));
342
-
343
-		// Type depending properties
344
-		$property = $vCard->createProperty('X-SOCIALPROFILE', 'tw-example');
345
-		$property->add('TYPE', 'twitter');
346
-		$vCard->add($property);
347
-		$property = $vCard->createProperty('X-SOCIALPROFILE', 'tw-example-2');
348
-		$property->add('TYPE', 'twitter');
349
-		$vCard->add($property);
350
-		$property = $vCard->createProperty('X-SOCIALPROFILE', 'fb-example');
351
-		$property->add('TYPE', 'facebook');
352
-		$vCard->add($property);
353
-
354
-		$array = $this->invokePrivate($this->addressBookImpl, 'vCard2Array', ['uri', $vCard]);
355
-		unset($array['PRODID']);
356
-		unset($array['UID']);
357
-
358
-		$this->assertEquals([
359
-			'URI' => 'uri',
360
-			'VERSION' => '4.0',
361
-			'FN' => 'Full Name',
362
-			'CLOUD' => [
363
-				'cloud-user1@localhost',
364
-				'[email protected]',
365
-			],
366
-			'EMAIL' => [
367
-				'email-user1@localhost',
368
-				'[email protected]',
369
-			],
370
-			'IMPP' => [
371
-				'impp-user1@localhost',
372
-				'[email protected]',
373
-			],
374
-			'TEL' => [
375
-				'+49 123456789',
376
-				'+1 555 123456789',
377
-			],
378
-			'URL' => [
379
-				'https://localhost',
380
-				'https://example.tld',
381
-			],
382
-
383
-			'X-SOCIALPROFILE' => [
384
-				'tw-example',
385
-				'tw-example-2',
386
-				'fb-example',
387
-			],
388
-
389
-			'isLocalSystemBook' => true,
390
-		], $array);
391
-	}
392
-
393
-	public function testVCard2ArrayWithTypes(): void {
394
-		$vCard = new VCard();
395
-
396
-		$vCard->add($vCard->createProperty('FN', 'Full Name'));
397
-
398
-		// Multi-value properties
399
-		$vCard->add($vCard->createProperty('CLOUD', 'cloud-user1@localhost'));
400
-		$vCard->add($vCard->createProperty('CLOUD', '[email protected]'));
401
-
402
-		$property = $vCard->createProperty('EMAIL', 'email-user1@localhost');
403
-		$property->add('TYPE', 'HOME');
404
-		$vCard->add($property);
405
-		$property = $vCard->createProperty('EMAIL', '[email protected]');
406
-		$property->add('TYPE', 'WORK');
407
-		$vCard->add($property);
408
-
409
-		$vCard->add($vCard->createProperty('IMPP', 'impp-user1@localhost'));
410
-		$vCard->add($vCard->createProperty('IMPP', '[email protected]'));
411
-
412
-		$property = $vCard->createProperty('TEL', '+49 123456789');
413
-		$property->add('TYPE', 'HOME,VOICE');
414
-		$vCard->add($property);
415
-		$property = $vCard->createProperty('TEL', '+1 555 123456789');
416
-		$property->add('TYPE', 'WORK');
417
-		$vCard->add($property);
418
-
419
-		$vCard->add($vCard->createProperty('URL', 'https://localhost'));
420
-		$vCard->add($vCard->createProperty('URL', 'https://example.tld'));
421
-
422
-		// Type depending properties
423
-		$property = $vCard->createProperty('X-SOCIALPROFILE', 'tw-example');
424
-		$property->add('TYPE', 'twitter');
425
-		$vCard->add($property);
426
-		$property = $vCard->createProperty('X-SOCIALPROFILE', 'tw-example-2');
427
-		$property->add('TYPE', 'twitter');
428
-		$vCard->add($property);
429
-		$property = $vCard->createProperty('X-SOCIALPROFILE', 'fb-example');
430
-		$property->add('TYPE', 'facebook');
431
-		$vCard->add($property);
432
-
433
-		$array = $this->invokePrivate($this->addressBookImpl, 'vCard2Array', ['uri', $vCard, true]);
434
-		unset($array['PRODID']);
435
-		unset($array['UID']);
436
-
437
-		$this->assertEquals([
438
-			'URI' => 'uri',
439
-			'VERSION' => '4.0',
440
-			'FN' => 'Full Name',
441
-			'CLOUD' => [
442
-				['type' => '', 'value' => 'cloud-user1@localhost'],
443
-				['type' => '', 'value' => '[email protected]'],
444
-			],
445
-			'EMAIL' => [
446
-				['type' => 'HOME', 'value' => 'email-user1@localhost'],
447
-				['type' => 'WORK', 'value' => '[email protected]'],
448
-			],
449
-			'IMPP' => [
450
-				['type' => '', 'value' => 'impp-user1@localhost'],
451
-				['type' => '', 'value' => '[email protected]'],
452
-			],
453
-			'TEL' => [
454
-				['type' => 'HOME,VOICE', 'value' => '+49 123456789'],
455
-				['type' => 'WORK', 'value' => '+1 555 123456789'],
456
-			],
457
-			'URL' => [
458
-				['type' => '', 'value' => 'https://localhost'],
459
-				['type' => '', 'value' => 'https://example.tld'],
460
-			],
461
-
462
-			'X-SOCIALPROFILE' => [
463
-				['type' => 'twitter', 'value' => 'tw-example'],
464
-				['type' => 'twitter', 'value' => 'tw-example-2'],
465
-				['type' => 'facebook', 'value' => 'fb-example'],
466
-			],
467
-
468
-			'isLocalSystemBook' => true,
469
-		], $array);
470
-	}
471
-
472
-	public function testIsSystemAddressBook(): void {
473
-		$addressBookInfo = [
474
-			'{http://owncloud.org/ns}owner-principal' => 'principals/system/system',
475
-			'principaluri' => 'principals/system/system',
476
-			'{DAV:}displayname' => 'display name',
477
-			'id' => 666,
478
-			'uri' => 'system',
479
-		];
480
-
481
-		$addressBookImpl = new AddressBookImpl(
482
-			$this->addressBook,
483
-			$addressBookInfo,
484
-			$this->backend,
485
-			$this->urlGenerator,
486
-			$this->propertyMapper,
487
-			null
488
-		);
489
-
490
-		$this->assertTrue($addressBookImpl->isSystemAddressBook());
491
-	}
492
-
493
-	public function testIsShared(): void {
494
-		$addressBookInfo = [
495
-			'{http://owncloud.org/ns}owner-principal' => 'user1',
496
-			'{DAV:}displayname' => 'Test address book',
497
-			'principaluri' => 'user2',
498
-			'id' => 666,
499
-			'uri' => 'default',
500
-		];
501
-
502
-		$addressBookImpl = new AddressBookImpl(
503
-			$this->addressBook,
504
-			$addressBookInfo,
505
-			$this->backend,
506
-			$this->urlGenerator,
507
-			$this->propertyMapper,
508
-			'user2'
509
-		);
510
-
511
-		$this->assertFalse($addressBookImpl->isSystemAddressBook());
512
-		$this->assertTrue($addressBookImpl->isShared());
513
-	}
514
-
515
-	public function testIsNotShared(): void {
516
-		$addressBookInfo = [
517
-			'{http://owncloud.org/ns}owner-principal' => 'user1',
518
-			'{DAV:}displayname' => 'Test address book',
519
-			'principaluri' => 'user1',
520
-			'id' => 666,
521
-			'uri' => 'default',
522
-		];
523
-
524
-		$addressBookImpl = new AddressBookImpl(
525
-			$this->addressBook,
526
-			$addressBookInfo,
527
-			$this->backend,
528
-			$this->urlGenerator,
529
-			$this->propertyMapper,
530
-			'user2'
531
-		);
532
-
533
-		$this->assertFalse($addressBookImpl->isSystemAddressBook());
534
-		$this->assertFalse($addressBookImpl->isShared());
535
-	}
22
+    private array $addressBookInfo;
23
+    private AddressBook&MockObject $addressBook;
24
+    private IURLGenerator&MockObject $urlGenerator;
25
+    private CardDavBackend&MockObject $backend;
26
+    private PropertyMapper&MockObject $propertyMapper;
27
+    private VCard&MockObject $vCard;
28
+    private AddressBookImpl $addressBookImpl;
29
+
30
+    protected function setUp(): void {
31
+        parent::setUp();
32
+
33
+        $this->addressBookInfo = [
34
+            'id' => 42,
35
+            'uri' => 'system',
36
+            'principaluri' => 'principals/system/system',
37
+            '{DAV:}displayname' => 'display name',
38
+        ];
39
+        $this->addressBook = $this->createMock(AddressBook::class);
40
+        $this->backend = $this->createMock(CardDavBackend::class);
41
+        $this->vCard = $this->createMock(VCard::class);
42
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
43
+        $this->propertyMapper = $this->createMock(PropertyMapper::class);
44
+
45
+        $this->addressBookImpl = new AddressBookImpl(
46
+            $this->addressBook,
47
+            $this->addressBookInfo,
48
+            $this->backend,
49
+            $this->urlGenerator,
50
+            $this->propertyMapper,
51
+            null
52
+        );
53
+    }
54
+
55
+    public function testGetKey(): void {
56
+        $this->assertSame($this->addressBookInfo['id'],
57
+            $this->addressBookImpl->getKey());
58
+    }
59
+
60
+    public function testGetDisplayName(): void {
61
+        $this->assertSame($this->addressBookInfo['{DAV:}displayname'],
62
+            $this->addressBookImpl->getDisplayName());
63
+    }
64
+
65
+    public function testSearch(): void {
66
+        /** @var MockObject&AddressBookImpl $addressBookImpl */
67
+        $addressBookImpl = $this->getMockBuilder(AddressBookImpl::class)
68
+            ->setConstructorArgs(
69
+                [
70
+                    $this->addressBook,
71
+                    $this->addressBookInfo,
72
+                    $this->backend,
73
+                    $this->urlGenerator,
74
+                    $this->propertyMapper,
75
+                    null
76
+                ]
77
+            )
78
+            ->onlyMethods(['vCard2Array', 'readCard'])
79
+            ->getMock();
80
+
81
+        $pattern = 'pattern';
82
+        $searchProperties = 'properties';
83
+
84
+        $this->backend->expects($this->once())->method('search')
85
+            ->with($this->addressBookInfo['id'], $pattern, $searchProperties)
86
+            ->willReturn(
87
+                [
88
+                    ['uri' => 'foo.vcf', 'carddata' => 'cardData1'],
89
+                    ['uri' => 'bar.vcf', 'carddata' => 'cardData2']
90
+                ]
91
+            );
92
+
93
+        $addressBookImpl->expects($this->exactly(2))->method('readCard')
94
+            ->willReturn($this->vCard);
95
+        $addressBookImpl->expects($this->exactly(2))->method('vCard2Array')
96
+            ->willReturnMap([
97
+                ['foo.vcf', $this->vCard, 'vCard'],
98
+                ['bar.vcf', $this->vCard, 'vCard'],
99
+            ]);
100
+
101
+        $result = $addressBookImpl->search($pattern, $searchProperties, []);
102
+        $this->assertTrue((is_array($result)));
103
+        $this->assertSame(2, count($result));
104
+    }
105
+
106
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestCreate')]
107
+    public function testCreate(array $properties): void {
108
+        $uid = 'uid';
109
+
110
+        /** @var MockObject&AddressBookImpl $addressBookImpl */
111
+        $addressBookImpl = $this->getMockBuilder(AddressBookImpl::class)
112
+            ->setConstructorArgs(
113
+                [
114
+                    $this->addressBook,
115
+                    $this->addressBookInfo,
116
+                    $this->backend,
117
+                    $this->urlGenerator,
118
+                    $this->propertyMapper,
119
+                    null
120
+                ]
121
+            )
122
+            ->onlyMethods(['vCard2Array', 'createUid', 'createEmptyVCard'])
123
+            ->getMock();
124
+
125
+        $expectedProperties = 0;
126
+        foreach ($properties as $data) {
127
+            if (is_string($data)) {
128
+                $expectedProperties++;
129
+            } else {
130
+                $expectedProperties += count($data);
131
+            }
132
+        }
133
+
134
+        $addressBookImpl->expects($this->once())->method('createUid')
135
+            ->willReturn($uid);
136
+        $addressBookImpl->expects($this->once())->method('createEmptyVCard')
137
+            ->with($uid)->willReturn($this->vCard);
138
+        $this->vCard->expects($this->exactly($expectedProperties))
139
+            ->method('createProperty');
140
+        $this->backend->expects($this->once())->method('createCard');
141
+        $this->backend->expects($this->never())->method('updateCard');
142
+        $this->backend->expects($this->never())->method('getCard');
143
+        $addressBookImpl->expects($this->once())->method('vCard2Array')
144
+            ->with('uid.vcf', $this->vCard)->willReturn(true);
145
+
146
+        $this->assertTrue($addressBookImpl->createOrUpdate($properties));
147
+    }
148
+
149
+    public static function dataTestCreate(): array {
150
+        return [
151
+            [[]],
152
+            [['FN' => 'John Doe']],
153
+            [['FN' => 'John Doe', 'EMAIL' => ['[email protected]', '[email protected]']]],
154
+        ];
155
+    }
156
+
157
+    public function testUpdate(): void {
158
+        $uid = 'uid';
159
+        $uri = 'bla.vcf';
160
+        $properties = ['URI' => $uri, 'UID' => $uid, 'FN' => 'John Doe'];
161
+
162
+        /** @var MockObject&AddressBookImpl $addressBookImpl */
163
+        $addressBookImpl = $this->getMockBuilder(AddressBookImpl::class)
164
+            ->setConstructorArgs(
165
+                [
166
+                    $this->addressBook,
167
+                    $this->addressBookInfo,
168
+                    $this->backend,
169
+                    $this->urlGenerator,
170
+                    $this->propertyMapper,
171
+                    null
172
+                ]
173
+            )
174
+            ->onlyMethods(['vCard2Array', 'createUid', 'createEmptyVCard', 'readCard'])
175
+            ->getMock();
176
+
177
+        $addressBookImpl->expects($this->never())->method('createUid');
178
+        $addressBookImpl->expects($this->never())->method('createEmptyVCard');
179
+        $this->backend->expects($this->once())->method('getCard')
180
+            ->with($this->addressBookInfo['id'], $uri)
181
+            ->willReturn(['carddata' => 'data']);
182
+        $addressBookImpl->expects($this->once())->method('readCard')
183
+            ->with('data')->willReturn($this->vCard);
184
+        $this->vCard->expects($this->exactly(count($properties) - 1))
185
+            ->method('createProperty');
186
+        $this->backend->expects($this->never())->method('createCard');
187
+        $this->backend->expects($this->once())->method('updateCard');
188
+        $addressBookImpl->expects($this->once())->method('vCard2Array')
189
+            ->with($uri, $this->vCard)->willReturn(true);
190
+
191
+        $this->assertTrue($addressBookImpl->createOrUpdate($properties));
192
+    }
193
+
194
+    public function testUpdateWithTypes(): void {
195
+        $uid = 'uid';
196
+        $uri = 'bla.vcf';
197
+        $properties = ['URI' => $uri, 'UID' => $uid, 'FN' => 'John Doe', 'ADR' => [['type' => 'HOME', 'value' => ';;street;city;;;country']]];
198
+        $vCard = new vCard;
199
+        $textProperty = $vCard->createProperty('KEY', 'value');
200
+
201
+        /** @var MockObject&AddressBookImpl $addressBookImpl */
202
+        $addressBookImpl = $this->getMockBuilder(AddressBookImpl::class)
203
+            ->setConstructorArgs(
204
+                [
205
+                    $this->addressBook,
206
+                    $this->addressBookInfo,
207
+                    $this->backend,
208
+                    $this->urlGenerator,
209
+                    $this->propertyMapper,
210
+                    null
211
+                ]
212
+            )
213
+            ->onlyMethods(['vCard2Array', 'createUid', 'createEmptyVCard', 'readCard'])
214
+            ->getMock();
215
+
216
+        $this->backend->expects($this->once())->method('getCard')
217
+            ->with($this->addressBookInfo['id'], $uri)
218
+            ->willReturn(['carddata' => 'data']);
219
+        $addressBookImpl->expects($this->once())->method('readCard')
220
+            ->with('data')->willReturn($this->vCard);
221
+        $this->vCard->method('createProperty')->willReturn($textProperty);
222
+        $this->vCard->expects($this->exactly(count($properties) - 1))
223
+            ->method('createProperty');
224
+        $this->vCard->expects($this->once())->method('remove')
225
+            ->with('ADR');
226
+        $this->vCard->expects($this->once())->method('add');
227
+
228
+        $addressBookImpl->createOrUpdate($properties);
229
+    }
230
+
231
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestGetPermissions')]
232
+    public function testGetPermissions(array $permissions, int $expected): void {
233
+        $this->addressBook->expects($this->once())->method('getACL')
234
+            ->willReturn($permissions);
235
+
236
+        $this->assertSame($expected,
237
+            $this->addressBookImpl->getPermissions()
238
+        );
239
+    }
240
+
241
+    public static function dataTestGetPermissions(): array {
242
+        return [
243
+            [[], 0],
244
+            [[['privilege' => '{DAV:}read']], 1],
245
+            [[['privilege' => '{DAV:}write']], 6],
246
+            [[['privilege' => '{DAV:}all']], 31],
247
+            [[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write']], 7],
248
+            [[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}all']], 31],
249
+            [[['privilege' => '{DAV:}all'],['privilege' => '{DAV:}write']], 31],
250
+            [[['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write'],['privilege' => '{DAV:}all']], 31],
251
+            [[['privilege' => '{DAV:}all'],['privilege' => '{DAV:}read'],['privilege' => '{DAV:}write']], 31],
252
+        ];
253
+    }
254
+
255
+    public function testDelete(): void {
256
+        $cardId = 1;
257
+        $cardUri = 'cardUri';
258
+        $this->backend->expects($this->once())->method('getCardUri')
259
+            ->with($cardId)->willReturn($cardUri);
260
+        $this->backend->expects($this->once())->method('deleteCard')
261
+            ->with($this->addressBookInfo['id'], $cardUri)
262
+            ->willReturn(true);
263
+
264
+        $this->assertTrue($this->addressBookImpl->delete($cardId));
265
+    }
266
+
267
+    public function testReadCard(): void {
268
+        $vCard = new VCard();
269
+        $vCard->add(new Text($vCard, 'UID', 'uid'));
270
+        $vCardSerialized = $vCard->serialize();
271
+
272
+        $result = $this->invokePrivate($this->addressBookImpl, 'readCard', [$vCardSerialized]);
273
+        $resultSerialized = $result->serialize();
274
+
275
+        $this->assertSame($vCardSerialized, $resultSerialized);
276
+    }
277
+
278
+    public function testCreateUid(): void {
279
+        /** @var MockObject&AddressBookImpl $addressBookImpl */
280
+        $addressBookImpl = $this->getMockBuilder(AddressBookImpl::class)
281
+            ->setConstructorArgs(
282
+                [
283
+                    $this->addressBook,
284
+                    $this->addressBookInfo,
285
+                    $this->backend,
286
+                    $this->urlGenerator,
287
+                    $this->propertyMapper,
288
+                    null
289
+                ]
290
+            )
291
+            ->onlyMethods(['getUid'])
292
+            ->getMock();
293
+
294
+        $addressBookImpl->expects($this->exactly(2))
295
+            ->method('getUid')
296
+            ->willReturnOnConsecutiveCalls(
297
+                'uid0',
298
+                'uid1',
299
+            );
300
+
301
+        // simulate that 'uid0' already exists, so the second uid will be returned
302
+        $this->backend->expects($this->exactly(2))->method('getContact')
303
+            ->willReturnCallback(
304
+                function ($id, $uid) {
305
+                    return ($uid === 'uid0.vcf');
306
+                }
307
+            );
308
+
309
+        $this->assertSame('uid1',
310
+            $this->invokePrivate($addressBookImpl, 'createUid', [])
311
+        );
312
+    }
313
+
314
+    public function testCreateEmptyVCard(): void {
315
+        $uid = 'uid';
316
+        $expectedVCard = new VCard();
317
+        $expectedVCard->UID = $uid;
318
+        $expectedVCardSerialized = $expectedVCard->serialize();
319
+
320
+        $result = $this->invokePrivate($this->addressBookImpl, 'createEmptyVCard', [$uid]);
321
+        $resultSerialized = $result->serialize();
322
+
323
+        $this->assertSame($expectedVCardSerialized, $resultSerialized);
324
+    }
325
+
326
+    public function testVCard2Array(): void {
327
+        $vCard = new VCard();
328
+
329
+        $vCard->add($vCard->createProperty('FN', 'Full Name'));
330
+
331
+        // Multi-value properties
332
+        $vCard->add($vCard->createProperty('CLOUD', 'cloud-user1@localhost'));
333
+        $vCard->add($vCard->createProperty('CLOUD', '[email protected]'));
334
+        $vCard->add($vCard->createProperty('EMAIL', 'email-user1@localhost'));
335
+        $vCard->add($vCard->createProperty('EMAIL', '[email protected]'));
336
+        $vCard->add($vCard->createProperty('IMPP', 'impp-user1@localhost'));
337
+        $vCard->add($vCard->createProperty('IMPP', '[email protected]'));
338
+        $vCard->add($vCard->createProperty('TEL', '+49 123456789'));
339
+        $vCard->add($vCard->createProperty('TEL', '+1 555 123456789'));
340
+        $vCard->add($vCard->createProperty('URL', 'https://localhost'));
341
+        $vCard->add($vCard->createProperty('URL', 'https://example.tld'));
342
+
343
+        // Type depending properties
344
+        $property = $vCard->createProperty('X-SOCIALPROFILE', 'tw-example');
345
+        $property->add('TYPE', 'twitter');
346
+        $vCard->add($property);
347
+        $property = $vCard->createProperty('X-SOCIALPROFILE', 'tw-example-2');
348
+        $property->add('TYPE', 'twitter');
349
+        $vCard->add($property);
350
+        $property = $vCard->createProperty('X-SOCIALPROFILE', 'fb-example');
351
+        $property->add('TYPE', 'facebook');
352
+        $vCard->add($property);
353
+
354
+        $array = $this->invokePrivate($this->addressBookImpl, 'vCard2Array', ['uri', $vCard]);
355
+        unset($array['PRODID']);
356
+        unset($array['UID']);
357
+
358
+        $this->assertEquals([
359
+            'URI' => 'uri',
360
+            'VERSION' => '4.0',
361
+            'FN' => 'Full Name',
362
+            'CLOUD' => [
363
+                'cloud-user1@localhost',
364
+                '[email protected]',
365
+            ],
366
+            'EMAIL' => [
367
+                'email-user1@localhost',
368
+                '[email protected]',
369
+            ],
370
+            'IMPP' => [
371
+                'impp-user1@localhost',
372
+                '[email protected]',
373
+            ],
374
+            'TEL' => [
375
+                '+49 123456789',
376
+                '+1 555 123456789',
377
+            ],
378
+            'URL' => [
379
+                'https://localhost',
380
+                'https://example.tld',
381
+            ],
382
+
383
+            'X-SOCIALPROFILE' => [
384
+                'tw-example',
385
+                'tw-example-2',
386
+                'fb-example',
387
+            ],
388
+
389
+            'isLocalSystemBook' => true,
390
+        ], $array);
391
+    }
392
+
393
+    public function testVCard2ArrayWithTypes(): void {
394
+        $vCard = new VCard();
395
+
396
+        $vCard->add($vCard->createProperty('FN', 'Full Name'));
397
+
398
+        // Multi-value properties
399
+        $vCard->add($vCard->createProperty('CLOUD', 'cloud-user1@localhost'));
400
+        $vCard->add($vCard->createProperty('CLOUD', '[email protected]'));
401
+
402
+        $property = $vCard->createProperty('EMAIL', 'email-user1@localhost');
403
+        $property->add('TYPE', 'HOME');
404
+        $vCard->add($property);
405
+        $property = $vCard->createProperty('EMAIL', '[email protected]');
406
+        $property->add('TYPE', 'WORK');
407
+        $vCard->add($property);
408
+
409
+        $vCard->add($vCard->createProperty('IMPP', 'impp-user1@localhost'));
410
+        $vCard->add($vCard->createProperty('IMPP', '[email protected]'));
411
+
412
+        $property = $vCard->createProperty('TEL', '+49 123456789');
413
+        $property->add('TYPE', 'HOME,VOICE');
414
+        $vCard->add($property);
415
+        $property = $vCard->createProperty('TEL', '+1 555 123456789');
416
+        $property->add('TYPE', 'WORK');
417
+        $vCard->add($property);
418
+
419
+        $vCard->add($vCard->createProperty('URL', 'https://localhost'));
420
+        $vCard->add($vCard->createProperty('URL', 'https://example.tld'));
421
+
422
+        // Type depending properties
423
+        $property = $vCard->createProperty('X-SOCIALPROFILE', 'tw-example');
424
+        $property->add('TYPE', 'twitter');
425
+        $vCard->add($property);
426
+        $property = $vCard->createProperty('X-SOCIALPROFILE', 'tw-example-2');
427
+        $property->add('TYPE', 'twitter');
428
+        $vCard->add($property);
429
+        $property = $vCard->createProperty('X-SOCIALPROFILE', 'fb-example');
430
+        $property->add('TYPE', 'facebook');
431
+        $vCard->add($property);
432
+
433
+        $array = $this->invokePrivate($this->addressBookImpl, 'vCard2Array', ['uri', $vCard, true]);
434
+        unset($array['PRODID']);
435
+        unset($array['UID']);
436
+
437
+        $this->assertEquals([
438
+            'URI' => 'uri',
439
+            'VERSION' => '4.0',
440
+            'FN' => 'Full Name',
441
+            'CLOUD' => [
442
+                ['type' => '', 'value' => 'cloud-user1@localhost'],
443
+                ['type' => '', 'value' => '[email protected]'],
444
+            ],
445
+            'EMAIL' => [
446
+                ['type' => 'HOME', 'value' => 'email-user1@localhost'],
447
+                ['type' => 'WORK', 'value' => '[email protected]'],
448
+            ],
449
+            'IMPP' => [
450
+                ['type' => '', 'value' => 'impp-user1@localhost'],
451
+                ['type' => '', 'value' => '[email protected]'],
452
+            ],
453
+            'TEL' => [
454
+                ['type' => 'HOME,VOICE', 'value' => '+49 123456789'],
455
+                ['type' => 'WORK', 'value' => '+1 555 123456789'],
456
+            ],
457
+            'URL' => [
458
+                ['type' => '', 'value' => 'https://localhost'],
459
+                ['type' => '', 'value' => 'https://example.tld'],
460
+            ],
461
+
462
+            'X-SOCIALPROFILE' => [
463
+                ['type' => 'twitter', 'value' => 'tw-example'],
464
+                ['type' => 'twitter', 'value' => 'tw-example-2'],
465
+                ['type' => 'facebook', 'value' => 'fb-example'],
466
+            ],
467
+
468
+            'isLocalSystemBook' => true,
469
+        ], $array);
470
+    }
471
+
472
+    public function testIsSystemAddressBook(): void {
473
+        $addressBookInfo = [
474
+            '{http://owncloud.org/ns}owner-principal' => 'principals/system/system',
475
+            'principaluri' => 'principals/system/system',
476
+            '{DAV:}displayname' => 'display name',
477
+            'id' => 666,
478
+            'uri' => 'system',
479
+        ];
480
+
481
+        $addressBookImpl = new AddressBookImpl(
482
+            $this->addressBook,
483
+            $addressBookInfo,
484
+            $this->backend,
485
+            $this->urlGenerator,
486
+            $this->propertyMapper,
487
+            null
488
+        );
489
+
490
+        $this->assertTrue($addressBookImpl->isSystemAddressBook());
491
+    }
492
+
493
+    public function testIsShared(): void {
494
+        $addressBookInfo = [
495
+            '{http://owncloud.org/ns}owner-principal' => 'user1',
496
+            '{DAV:}displayname' => 'Test address book',
497
+            'principaluri' => 'user2',
498
+            'id' => 666,
499
+            'uri' => 'default',
500
+        ];
501
+
502
+        $addressBookImpl = new AddressBookImpl(
503
+            $this->addressBook,
504
+            $addressBookInfo,
505
+            $this->backend,
506
+            $this->urlGenerator,
507
+            $this->propertyMapper,
508
+            'user2'
509
+        );
510
+
511
+        $this->assertFalse($addressBookImpl->isSystemAddressBook());
512
+        $this->assertTrue($addressBookImpl->isShared());
513
+    }
514
+
515
+    public function testIsNotShared(): void {
516
+        $addressBookInfo = [
517
+            '{http://owncloud.org/ns}owner-principal' => 'user1',
518
+            '{DAV:}displayname' => 'Test address book',
519
+            'principaluri' => 'user1',
520
+            'id' => 666,
521
+            'uri' => 'default',
522
+        ];
523
+
524
+        $addressBookImpl = new AddressBookImpl(
525
+            $this->addressBook,
526
+            $addressBookInfo,
527
+            $this->backend,
528
+            $this->urlGenerator,
529
+            $this->propertyMapper,
530
+            'user2'
531
+        );
532
+
533
+        $this->assertFalse($addressBookImpl->isSystemAddressBook());
534
+        $this->assertFalse($addressBookImpl->isShared());
535
+    }
536 536
 }
Please login to merge, or discard this patch.
apps/dav/tests/unit/CardDAV/CardDavBackendTest.php 2 patches
Indentation   +866 added lines, -866 removed lines patch added patch discarded remove patch
@@ -46,870 +46,870 @@
 block discarded – undo
46 46
  * @package OCA\DAV\Tests\unit\CardDAV
47 47
  */
48 48
 class CardDavBackendTest extends TestCase {
49
-	private Principal&MockObject $principal;
50
-	private IUserManager&MockObject $userManager;
51
-	private IGroupManager&MockObject $groupManager;
52
-	private IEventDispatcher&MockObject $dispatcher;
53
-	private Backend $sharingBackend;
54
-	private IDBConnection $db;
55
-	private CardDavBackend $backend;
56
-	private string $dbCardsTable = 'cards';
57
-	private string $dbCardsPropertiesTable = 'cards_properties';
58
-
59
-	public const UNIT_TEST_USER = 'principals/users/carddav-unit-test';
60
-	public const UNIT_TEST_USER1 = 'principals/users/carddav-unit-test1';
61
-	public const UNIT_TEST_GROUP = 'principals/groups/carddav-unit-test-group';
62
-
63
-	private $vcardTest0 = 'BEGIN:VCARD' . PHP_EOL
64
-		. 'VERSION:3.0' . PHP_EOL
65
-		. 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
66
-		. 'UID:Test' . PHP_EOL
67
-		. 'FN:Test' . PHP_EOL
68
-		. 'N:Test;;;;' . PHP_EOL
69
-		. 'END:VCARD';
70
-
71
-	private $vcardTest1 = 'BEGIN:VCARD' . PHP_EOL
72
-		. 'VERSION:3.0' . PHP_EOL
73
-		. 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
74
-		. 'UID:Test2' . PHP_EOL
75
-		. 'FN:Test2' . PHP_EOL
76
-		. 'N:Test2;;;;' . PHP_EOL
77
-		. 'END:VCARD';
78
-
79
-	private $vcardTest2 = 'BEGIN:VCARD' . PHP_EOL
80
-		. 'VERSION:3.0' . PHP_EOL
81
-		. 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
82
-		. 'UID:Test3' . PHP_EOL
83
-		. 'FN:Test3' . PHP_EOL
84
-		. 'N:Test3;;;;' . PHP_EOL
85
-		. 'END:VCARD';
86
-
87
-	private $vcardTestNoUID = 'BEGIN:VCARD' . PHP_EOL
88
-		. 'VERSION:3.0' . PHP_EOL
89
-		. 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
90
-		. 'FN:TestNoUID' . PHP_EOL
91
-		. 'N:TestNoUID;;;;' . PHP_EOL
92
-		. 'END:VCARD';
93
-
94
-	protected function setUp(): void {
95
-		parent::setUp();
96
-
97
-		$this->userManager = $this->createMock(IUserManager::class);
98
-		$this->groupManager = $this->createMock(IGroupManager::class);
99
-		$this->principal = $this->getMockBuilder(Principal::class)
100
-			->setConstructorArgs([
101
-				$this->userManager,
102
-				$this->groupManager,
103
-				$this->createMock(IAccountManager::class),
104
-				$this->createMock(ShareManager::class),
105
-				$this->createMock(IUserSession::class),
106
-				$this->createMock(IAppManager::class),
107
-				$this->createMock(ProxyMapper::class),
108
-				$this->createMock(KnownUserService::class),
109
-				$this->createMock(IConfig::class),
110
-				$this->createMock(IFactory::class)
111
-			])
112
-			->onlyMethods(['getPrincipalByPath', 'getGroupMembership', 'findByUri'])
113
-			->getMock();
114
-		$this->principal->method('getPrincipalByPath')
115
-			->willReturn([
116
-				'uri' => 'principals/best-friend',
117
-				'{DAV:}displayname' => 'User\'s displayname',
118
-			]);
119
-		$this->principal->method('getGroupMembership')
120
-			->withAnyParameters()
121
-			->willReturn([self::UNIT_TEST_GROUP]);
122
-		$this->dispatcher = $this->createMock(IEventDispatcher::class);
123
-
124
-		$this->db = Server::get(IDBConnection::class);
125
-		$this->sharingBackend = new Backend($this->userManager,
126
-			$this->groupManager,
127
-			$this->principal,
128
-			$this->createMock(ICacheFactory::class),
129
-			new Service(new SharingMapper($this->db)),
130
-			$this->createMock(LoggerInterface::class)
131
-		);
132
-
133
-		$this->backend = new CardDavBackend($this->db,
134
-			$this->principal,
135
-			$this->userManager,
136
-			$this->dispatcher,
137
-			$this->sharingBackend,
138
-		);
139
-		// start every test with a empty cards_properties and cards table
140
-		$query = $this->db->getQueryBuilder();
141
-		$query->delete('cards_properties')->executeStatement();
142
-		$query = $this->db->getQueryBuilder();
143
-		$query->delete('cards')->executeStatement();
144
-
145
-		$this->principal->method('getGroupMembership')
146
-			->withAnyParameters()
147
-			->willReturn([self::UNIT_TEST_GROUP]);
148
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
149
-		foreach ($books as $book) {
150
-			$this->backend->deleteAddressBook($book['id']);
151
-		}
152
-	}
153
-
154
-	protected function tearDown(): void {
155
-		if (is_null($this->backend)) {
156
-			return;
157
-		}
158
-
159
-		$this->principal->method('getGroupMembership')
160
-			->withAnyParameters()
161
-			->willReturn([self::UNIT_TEST_GROUP]);
162
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
163
-		foreach ($books as $book) {
164
-			$this->backend->deleteAddressBook($book['id']);
165
-		}
166
-
167
-		parent::tearDown();
168
-	}
169
-
170
-	public function testAddressBookOperations(): void {
171
-		// create a new address book
172
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
173
-
174
-		$this->assertEquals(1, $this->backend->getAddressBooksForUserCount(self::UNIT_TEST_USER));
175
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
176
-		$this->assertEquals(1, count($books));
177
-		$this->assertEquals('Example', $books[0]['{DAV:}displayname']);
178
-		$this->assertEquals('User\'s displayname', $books[0]['{http://nextcloud.com/ns}owner-displayname']);
179
-
180
-		// update its display name
181
-		$patch = new PropPatch([
182
-			'{DAV:}displayname' => 'Unit test',
183
-			'{urn:ietf:params:xml:ns:carddav}addressbook-description' => 'Addressbook used for unit testing'
184
-		]);
185
-		$this->backend->updateAddressBook($books[0]['id'], $patch);
186
-		$patch->commit();
187
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
188
-		$this->assertEquals(1, count($books));
189
-		$this->assertEquals('Unit test', $books[0]['{DAV:}displayname']);
190
-		$this->assertEquals('Addressbook used for unit testing', $books[0]['{urn:ietf:params:xml:ns:carddav}addressbook-description']);
191
-
192
-		// delete the address book
193
-		$this->backend->deleteAddressBook($books[0]['id']);
194
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
195
-		$this->assertEquals(0, count($books));
196
-	}
197
-
198
-	public function testAddressBookSharing(): void {
199
-		$this->userManager->expects($this->any())
200
-			->method('userExists')
201
-			->willReturn(true);
202
-		$this->groupManager->expects($this->any())
203
-			->method('groupExists')
204
-			->willReturn(true);
205
-		$this->principal->expects(self::atLeastOnce())
206
-			->method('findByUri')
207
-			->willReturnOnConsecutiveCalls(self::UNIT_TEST_USER1, self::UNIT_TEST_GROUP);
208
-
209
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
210
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
211
-		$this->assertEquals(1, count($books));
212
-		$l = $this->createMock(IL10N::class);
213
-		$addressBook = new AddressBook($this->backend, $books[0], $l);
214
-		$this->backend->updateShares($addressBook, [
215
-			[
216
-				'href' => 'principal:' . self::UNIT_TEST_USER1,
217
-			],
218
-			[
219
-				'href' => 'principal:' . self::UNIT_TEST_GROUP,
220
-			]
221
-		], []);
222
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER1);
223
-		$this->assertEquals(1, count($books));
224
-
225
-		// delete the address book
226
-		$this->backend->deleteAddressBook($books[0]['id']);
227
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
228
-		$this->assertEquals(0, count($books));
229
-	}
230
-
231
-	public function testCardOperations(): void {
232
-		/** @var CardDavBackend&MockObject $backend */
233
-		$backend = $this->getMockBuilder(CardDavBackend::class)
234
-			->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend])
235
-			->onlyMethods(['updateProperties', 'purgeProperties'])
236
-			->getMock();
237
-
238
-		// create a new address book
239
-		$backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
240
-		$books = $backend->getAddressBooksForUser(self::UNIT_TEST_USER);
241
-		$this->assertEquals(1, count($books));
242
-		$bookId = $books[0]['id'];
243
-
244
-		$uri = $this->getUniqueID('card');
245
-		// updateProperties is expected twice, once for createCard and once for updateCard
246
-		$calls = [
247
-			[$bookId, $uri, $this->vcardTest0],
248
-			[$bookId, $uri, $this->vcardTest1],
249
-		];
250
-		$backend->expects($this->exactly(count($calls)))
251
-			->method('updateProperties')
252
-			->willReturnCallback(function () use (&$calls): void {
253
-				$expected = array_shift($calls);
254
-				$this->assertEquals($expected, func_get_args());
255
-			});
256
-
257
-		// Expect event
258
-		$this->dispatcher
259
-			->expects($this->exactly(3))
260
-			->method('dispatchTyped');
261
-
262
-		// create a card
263
-		$backend->createCard($bookId, $uri, $this->vcardTest0);
264
-
265
-		// get all the cards
266
-		$cards = $backend->getCards($bookId);
267
-		$this->assertEquals(1, count($cards));
268
-		$this->assertEquals($this->vcardTest0, $cards[0]['carddata']);
269
-
270
-		// get the cards
271
-		$card = $backend->getCard($bookId, $uri);
272
-		$this->assertNotNull($card);
273
-		$this->assertArrayHasKey('id', $card);
274
-		$this->assertArrayHasKey('uri', $card);
275
-		$this->assertArrayHasKey('lastmodified', $card);
276
-		$this->assertArrayHasKey('etag', $card);
277
-		$this->assertArrayHasKey('size', $card);
278
-		$this->assertEquals($this->vcardTest0, $card['carddata']);
279
-
280
-		// update the card
281
-		$backend->updateCard($bookId, $uri, $this->vcardTest1);
282
-		$card = $backend->getCard($bookId, $uri);
283
-		$this->assertEquals($this->vcardTest1, $card['carddata']);
284
-
285
-		// delete the card
286
-		$backend->expects($this->once())->method('purgeProperties')->with($bookId, $card['id']);
287
-		$backend->deleteCard($bookId, $uri);
288
-		$cards = $backend->getCards($bookId);
289
-		$this->assertEquals(0, count($cards));
290
-	}
291
-
292
-	public function testMultiCard(): void {
293
-		$this->backend = $this->getMockBuilder(CardDavBackend::class)
294
-			->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend])
295
-			->onlyMethods(['updateProperties'])
296
-			->getMock();
297
-
298
-		// create a new address book
299
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
300
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
301
-		$this->assertEquals(1, count($books));
302
-		$bookId = $books[0]['id'];
303
-
304
-		// create a card
305
-		$uri0 = self::getUniqueID('card');
306
-		$this->backend->createCard($bookId, $uri0, $this->vcardTest0);
307
-		$uri1 = self::getUniqueID('card');
308
-		$this->backend->createCard($bookId, $uri1, $this->vcardTest1);
309
-		$uri2 = self::getUniqueID('card');
310
-		$this->backend->createCard($bookId, $uri2, $this->vcardTest2);
311
-
312
-		// get all the cards
313
-		$cards = $this->backend->getCards($bookId);
314
-		$this->assertEquals(3, count($cards));
315
-		usort($cards, function ($a, $b) {
316
-			return $a['id'] < $b['id'] ? -1 : 1;
317
-		});
318
-
319
-		$this->assertEquals($this->vcardTest0, $cards[0]['carddata']);
320
-		$this->assertEquals($this->vcardTest1, $cards[1]['carddata']);
321
-		$this->assertEquals($this->vcardTest2, $cards[2]['carddata']);
322
-
323
-		// get the cards 1 & 2 (not 0)
324
-		$cards = $this->backend->getMultipleCards($bookId, [$uri1, $uri2]);
325
-		$this->assertEquals(2, count($cards));
326
-		usort($cards, function ($a, $b) {
327
-			return $a['id'] < $b['id'] ? -1 : 1;
328
-		});
329
-		foreach ($cards as $index => $card) {
330
-			$this->assertArrayHasKey('id', $card);
331
-			$this->assertArrayHasKey('uri', $card);
332
-			$this->assertArrayHasKey('lastmodified', $card);
333
-			$this->assertArrayHasKey('etag', $card);
334
-			$this->assertArrayHasKey('size', $card);
335
-			$this->assertEquals($this->{ 'vcardTest' . ($index + 1) }, $card['carddata']);
336
-		}
337
-
338
-		// delete the card
339
-		$this->backend->deleteCard($bookId, $uri0);
340
-		$this->backend->deleteCard($bookId, $uri1);
341
-		$this->backend->deleteCard($bookId, $uri2);
342
-		$cards = $this->backend->getCards($bookId);
343
-		$this->assertEquals(0, count($cards));
344
-	}
345
-
346
-	public function testMultipleUIDOnDifferentAddressbooks(): void {
347
-		$this->backend = $this->getMockBuilder(CardDavBackend::class)
348
-			->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend])
349
-			->onlyMethods(['updateProperties'])
350
-			->getMock();
351
-
352
-		// create 2 new address books
353
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
354
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example2', []);
355
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
356
-		$this->assertEquals(2, count($books));
357
-		$bookId0 = $books[0]['id'];
358
-		$bookId1 = $books[1]['id'];
359
-
360
-		// create a card
361
-		$uri0 = $this->getUniqueID('card');
362
-		$this->backend->createCard($bookId0, $uri0, $this->vcardTest0);
363
-
364
-		// create another card with same uid but in second address book
365
-		$uri1 = $this->getUniqueID('card');
366
-		$this->backend->createCard($bookId1, $uri1, $this->vcardTest0);
367
-	}
368
-
369
-	public function testMultipleUIDDenied(): void {
370
-		$this->backend = $this->getMockBuilder(CardDavBackend::class)
371
-			->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend])
372
-			->onlyMethods(['updateProperties'])
373
-			->getMock();
374
-
375
-		// create a new address book
376
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
377
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
378
-		$this->assertEquals(1, count($books));
379
-		$bookId = $books[0]['id'];
380
-
381
-		// create a card
382
-		$uri0 = $this->getUniqueID('card');
383
-		$this->backend->createCard($bookId, $uri0, $this->vcardTest0);
384
-
385
-		// create another card with same uid
386
-		$uri1 = $this->getUniqueID('card');
387
-		$this->expectException(BadRequest::class);
388
-		$test = $this->backend->createCard($bookId, $uri1, $this->vcardTest0);
389
-	}
390
-
391
-	public function testNoValidUID(): void {
392
-		$this->backend = $this->getMockBuilder(CardDavBackend::class)
393
-			->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend])
394
-			->onlyMethods(['updateProperties'])
395
-			->getMock();
396
-
397
-		// create a new address book
398
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
399
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
400
-		$this->assertEquals(1, count($books));
401
-		$bookId = $books[0]['id'];
402
-
403
-		// create a card without uid
404
-		$uri1 = $this->getUniqueID('card');
405
-		$this->expectException(BadRequest::class);
406
-		$test = $this->backend->createCard($bookId, $uri1, $this->vcardTestNoUID);
407
-	}
408
-
409
-	public function testDeleteWithoutCard(): void {
410
-		$this->backend = $this->getMockBuilder(CardDavBackend::class)
411
-			->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend])
412
-			->onlyMethods([
413
-				'getCardId',
414
-				'addChange',
415
-				'purgeProperties',
416
-				'updateProperties',
417
-			])
418
-			->getMock();
419
-
420
-		// create a new address book
421
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
422
-		$books = $this->backend->getUsersOwnAddressBooks(self::UNIT_TEST_USER);
423
-		$this->assertEquals(1, count($books));
424
-
425
-		$bookId = $books[0]['id'];
426
-		$uri = $this->getUniqueID('card');
427
-
428
-		// create a new address book
429
-		$this->backend->expects($this->once())
430
-			->method('getCardId')
431
-			->with($bookId, $uri)
432
-			->willThrowException(new \InvalidArgumentException());
433
-
434
-		$calls = [
435
-			[$bookId, $uri, 1],
436
-			[$bookId, $uri, 3],
437
-		];
438
-		$this->backend->expects($this->exactly(count($calls)))
439
-			->method('addChange')
440
-			->willReturnCallback(function () use (&$calls): void {
441
-				$expected = array_shift($calls);
442
-				$this->assertEquals($expected, func_get_args());
443
-			});
444
-		$this->backend->expects($this->never())
445
-			->method('purgeProperties');
446
-
447
-		// create a card
448
-		$this->backend->createCard($bookId, $uri, $this->vcardTest0);
449
-
450
-		// delete the card
451
-		$this->assertTrue($this->backend->deleteCard($bookId, $uri));
452
-	}
453
-
454
-	public function testSyncSupport(): void {
455
-		$this->backend = $this->getMockBuilder(CardDavBackend::class)
456
-			->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend])
457
-			->onlyMethods(['updateProperties'])
458
-			->getMock();
459
-
460
-		// create a new address book
461
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
462
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
463
-		$this->assertEquals(1, count($books));
464
-		$bookId = $books[0]['id'];
465
-
466
-		// fist call without synctoken
467
-		$changes = $this->backend->getChangesForAddressBook($bookId, '', 1);
468
-		$syncToken = $changes['syncToken'];
469
-
470
-		// add a change
471
-		$uri0 = $this->getUniqueID('card');
472
-		$this->backend->createCard($bookId, $uri0, $this->vcardTest0);
473
-
474
-		// look for changes
475
-		$changes = $this->backend->getChangesForAddressBook($bookId, $syncToken, 1);
476
-		$this->assertEquals($uri0, $changes['added'][0]);
477
-	}
478
-
479
-	public function testSharing(): void {
480
-		$this->userManager->expects($this->any())
481
-			->method('userExists')
482
-			->willReturn(true);
483
-		$this->groupManager->expects($this->any())
484
-			->method('groupExists')
485
-			->willReturn(true);
486
-		$this->principal->expects(self::any())
487
-			->method('findByUri')
488
-			->willReturn(self::UNIT_TEST_USER1);
489
-
490
-		$this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
491
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
492
-		$this->assertEquals(1, count($books));
493
-
494
-		$l = $this->createMock(IL10N::class);
495
-		$exampleBook = new AddressBook($this->backend, $books[0], $l);
496
-		$this->backend->updateShares($exampleBook, [['href' => 'principal:' . self::UNIT_TEST_USER1]], []);
497
-
498
-		$shares = $this->backend->getShares($exampleBook->getResourceId());
499
-		$this->assertEquals(1, count($shares));
500
-
501
-		// adding the same sharee again has no effect
502
-		$this->backend->updateShares($exampleBook, [['href' => 'principal:' . self::UNIT_TEST_USER1]], []);
503
-
504
-		$shares = $this->backend->getShares($exampleBook->getResourceId());
505
-		$this->assertEquals(1, count($shares));
506
-
507
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER1);
508
-		$this->assertEquals(1, count($books));
509
-
510
-		$this->backend->updateShares($exampleBook, [], ['principal:' . self::UNIT_TEST_USER1]);
511
-
512
-		$shares = $this->backend->getShares($exampleBook->getResourceId());
513
-		$this->assertEquals(0, count($shares));
514
-
515
-		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER1);
516
-		$this->assertEquals(0, count($books));
517
-	}
518
-
519
-	public function testUpdateProperties(): void {
520
-		$bookId = 42;
521
-		$cardUri = 'card-uri';
522
-		$cardId = 2;
523
-
524
-		$backend = $this->getMockBuilder(CardDavBackend::class)
525
-			->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend])
526
-			->onlyMethods(['getCardId'])->getMock();
527
-
528
-		$backend->expects($this->any())->method('getCardId')->willReturn($cardId);
529
-
530
-		// add properties for new vCard
531
-		$vCard = new VCard();
532
-		$vCard->UID = $cardUri;
533
-		$vCard->FN = 'John Doe';
534
-		$this->invokePrivate($backend, 'updateProperties', [$bookId, $cardUri, $vCard->serialize()]);
535
-
536
-		$query = $this->db->getQueryBuilder();
537
-		$query->select('*')
538
-			->from('cards_properties')
539
-			->orderBy('name');
540
-
541
-		$qResult = $query->execute();
542
-		$result = $qResult->fetchAll();
543
-		$qResult->closeCursor();
544
-
545
-		$this->assertSame(2, count($result));
546
-
547
-		$this->assertSame('FN', $result[0]['name']);
548
-		$this->assertSame('John Doe', $result[0]['value']);
549
-		$this->assertSame($bookId, (int)$result[0]['addressbookid']);
550
-		$this->assertSame($cardId, (int)$result[0]['cardid']);
551
-
552
-		$this->assertSame('UID', $result[1]['name']);
553
-		$this->assertSame($cardUri, $result[1]['value']);
554
-		$this->assertSame($bookId, (int)$result[1]['addressbookid']);
555
-		$this->assertSame($cardId, (int)$result[1]['cardid']);
556
-
557
-		// update properties for existing vCard
558
-		$vCard = new VCard();
559
-		$vCard->UID = $cardUri;
560
-		$this->invokePrivate($backend, 'updateProperties', [$bookId, $cardUri, $vCard->serialize()]);
561
-
562
-		$query = $this->db->getQueryBuilder();
563
-		$query->select('*')
564
-			->from('cards_properties');
565
-
566
-		$qResult = $query->execute();
567
-		$result = $qResult->fetchAll();
568
-		$qResult->closeCursor();
569
-
570
-		$this->assertSame(1, count($result));
571
-
572
-		$this->assertSame('UID', $result[0]['name']);
573
-		$this->assertSame($cardUri, $result[0]['value']);
574
-		$this->assertSame($bookId, (int)$result[0]['addressbookid']);
575
-		$this->assertSame($cardId, (int)$result[0]['cardid']);
576
-	}
577
-
578
-	public function testPurgeProperties(): void {
579
-		$query = $this->db->getQueryBuilder();
580
-		$query->insert('cards_properties')
581
-			->values(
582
-				[
583
-					'addressbookid' => $query->createNamedParameter(1),
584
-					'cardid' => $query->createNamedParameter(1),
585
-					'name' => $query->createNamedParameter('name1'),
586
-					'value' => $query->createNamedParameter('value1'),
587
-					'preferred' => $query->createNamedParameter(0)
588
-				]
589
-			);
590
-		$query->execute();
591
-
592
-		$query = $this->db->getQueryBuilder();
593
-		$query->insert('cards_properties')
594
-			->values(
595
-				[
596
-					'addressbookid' => $query->createNamedParameter(1),
597
-					'cardid' => $query->createNamedParameter(2),
598
-					'name' => $query->createNamedParameter('name2'),
599
-					'value' => $query->createNamedParameter('value2'),
600
-					'preferred' => $query->createNamedParameter(0)
601
-				]
602
-			);
603
-		$query->execute();
604
-
605
-		$this->invokePrivate($this->backend, 'purgeProperties', [1, 1]);
606
-
607
-		$query = $this->db->getQueryBuilder();
608
-		$query->select('*')
609
-			->from('cards_properties');
610
-
611
-		$qResult = $query->execute();
612
-		$result = $qResult->fetchAll();
613
-		$qResult->closeCursor();
614
-
615
-		$this->assertSame(1, count($result));
616
-		$this->assertSame(1, (int)$result[0]['addressbookid']);
617
-		$this->assertSame(2, (int)$result[0]['cardid']);
618
-	}
619
-
620
-	public function testGetCardId(): void {
621
-		$query = $this->db->getQueryBuilder();
622
-
623
-		$query->insert('cards')
624
-			->values(
625
-				[
626
-					'addressbookid' => $query->createNamedParameter(1),
627
-					'carddata' => $query->createNamedParameter(''),
628
-					'uri' => $query->createNamedParameter('uri'),
629
-					'lastmodified' => $query->createNamedParameter(4738743),
630
-					'etag' => $query->createNamedParameter('etag'),
631
-					'size' => $query->createNamedParameter(120)
632
-				]
633
-			);
634
-		$query->execute();
635
-		$id = $query->getLastInsertId();
636
-
637
-		$this->assertSame($id,
638
-			$this->invokePrivate($this->backend, 'getCardId', [1, 'uri']));
639
-	}
640
-
641
-
642
-	public function testGetCardIdFailed(): void {
643
-		$this->expectException(\InvalidArgumentException::class);
644
-
645
-		$this->invokePrivate($this->backend, 'getCardId', [1, 'uri']);
646
-	}
647
-
648
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataTestSearch')]
649
-	public function testSearch(string $pattern, array $properties, array $options, array $expected): void {
650
-		/** @var VCard $vCards */
651
-		$vCards = [];
652
-		$vCards[0] = new VCard();
653
-		$vCards[0]->add(new Text($vCards[0], 'UID', 'uid'));
654
-		$vCards[0]->add(new Text($vCards[0], 'FN', 'John Doe'));
655
-		$vCards[0]->add(new Text($vCards[0], 'CLOUD', '[email protected]'));
656
-		$vCards[1] = new VCard();
657
-		$vCards[1]->add(new Text($vCards[1], 'UID', 'uid'));
658
-		$vCards[1]->add(new Text($vCards[1], 'FN', 'John M. Doe'));
659
-		$vCards[2] = new VCard();
660
-		$vCards[2]->add(new Text($vCards[2], 'UID', 'uid'));
661
-		$vCards[2]->add(new Text($vCards[2], 'FN', 'find without options'));
662
-		$vCards[2]->add(new Text($vCards[2], 'CLOUD', '[email protected]'));
663
-
664
-		$vCardIds = [];
665
-		$query = $this->db->getQueryBuilder();
666
-		for ($i = 0; $i < 3; $i++) {
667
-			$query->insert($this->dbCardsTable)
668
-				->values(
669
-					[
670
-						'addressbookid' => $query->createNamedParameter(0),
671
-						'carddata' => $query->createNamedParameter($vCards[$i]->serialize(), IQueryBuilder::PARAM_LOB),
672
-						'uri' => $query->createNamedParameter('uri' . $i),
673
-						'lastmodified' => $query->createNamedParameter(time()),
674
-						'etag' => $query->createNamedParameter('etag' . $i),
675
-						'size' => $query->createNamedParameter(120),
676
-					]
677
-				);
678
-			$query->execute();
679
-			$vCardIds[] = $query->getLastInsertId();
680
-		}
681
-
682
-		$query = $this->db->getQueryBuilder();
683
-		$query->insert($this->dbCardsPropertiesTable)
684
-			->values(
685
-				[
686
-					'addressbookid' => $query->createNamedParameter(0),
687
-					'cardid' => $query->createNamedParameter($vCardIds[0]),
688
-					'name' => $query->createNamedParameter('FN'),
689
-					'value' => $query->createNamedParameter('John Doe'),
690
-					'preferred' => $query->createNamedParameter(0)
691
-				]
692
-			);
693
-		$query->execute();
694
-		$query = $this->db->getQueryBuilder();
695
-		$query->insert($this->dbCardsPropertiesTable)
696
-			->values(
697
-				[
698
-					'addressbookid' => $query->createNamedParameter(0),
699
-					'cardid' => $query->createNamedParameter($vCardIds[0]),
700
-					'name' => $query->createNamedParameter('CLOUD'),
701
-					'value' => $query->createNamedParameter('[email protected]'),
702
-					'preferred' => $query->createNamedParameter(0)
703
-				]
704
-			);
705
-		$query->execute();
706
-		$query = $this->db->getQueryBuilder();
707
-		$query->insert($this->dbCardsPropertiesTable)
708
-			->values(
709
-				[
710
-					'addressbookid' => $query->createNamedParameter(0),
711
-					'cardid' => $query->createNamedParameter($vCardIds[1]),
712
-					'name' => $query->createNamedParameter('FN'),
713
-					'value' => $query->createNamedParameter('John M. Doe'),
714
-					'preferred' => $query->createNamedParameter(0)
715
-				]
716
-			);
717
-		$query->execute();
718
-		$query = $this->db->getQueryBuilder();
719
-		$query->insert($this->dbCardsPropertiesTable)
720
-			->values(
721
-				[
722
-					'addressbookid' => $query->createNamedParameter(0),
723
-					'cardid' => $query->createNamedParameter($vCardIds[2]),
724
-					'name' => $query->createNamedParameter('FN'),
725
-					'value' => $query->createNamedParameter('find without options'),
726
-					'preferred' => $query->createNamedParameter(0)
727
-				]
728
-			);
729
-		$query->execute();
730
-		$query = $this->db->getQueryBuilder();
731
-		$query->insert($this->dbCardsPropertiesTable)
732
-			->values(
733
-				[
734
-					'addressbookid' => $query->createNamedParameter(0),
735
-					'cardid' => $query->createNamedParameter($vCardIds[2]),
736
-					'name' => $query->createNamedParameter('CLOUD'),
737
-					'value' => $query->createNamedParameter('[email protected]'),
738
-					'preferred' => $query->createNamedParameter(0)
739
-				]
740
-			);
741
-		$query->execute();
742
-
743
-		$result = $this->backend->search(0, $pattern, $properties, $options);
744
-
745
-		// check result
746
-		$this->assertSame(count($expected), count($result));
747
-		$found = [];
748
-		foreach ($result as $r) {
749
-			foreach ($expected as $exp) {
750
-				if ($r['uri'] === $exp[0] && strpos($r['carddata'], $exp[1]) > 0) {
751
-					$found[$exp[1]] = true;
752
-					break;
753
-				}
754
-			}
755
-		}
756
-
757
-		$this->assertSame(count($expected), count($found));
758
-	}
759
-
760
-	public static function dataTestSearch(): array {
761
-		return [
762
-			['John', ['FN'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
763
-			['M. Doe', ['FN'], [], [['uri1', 'John M. Doe']]],
764
-			['Do', ['FN'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
765
-			'check if duplicates are handled correctly' => ['John', ['FN', 'CLOUD'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
766
-			'case insensitive' => ['john', ['FN'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
767
-			'limit' => ['john', ['FN'], ['limit' => 1], [['uri0', 'John Doe']]],
768
-			'limit and offset' => ['john', ['FN'], ['limit' => 1, 'offset' => 1], [['uri1', 'John M. Doe']]],
769
-			'find "_" escaped' => ['_', ['CLOUD'], [], [['uri2', 'find without options']]],
770
-			'find not empty CLOUD' => ['%_%', ['CLOUD'], ['escape_like_param' => false], [['uri0', 'John Doe'], ['uri2', 'find without options']]],
771
-		];
772
-	}
773
-
774
-	public function testGetCardUri(): void {
775
-		$query = $this->db->getQueryBuilder();
776
-		$query->insert($this->dbCardsTable)
777
-			->values(
778
-				[
779
-					'addressbookid' => $query->createNamedParameter(1),
780
-					'carddata' => $query->createNamedParameter('carddata', IQueryBuilder::PARAM_LOB),
781
-					'uri' => $query->createNamedParameter('uri'),
782
-					'lastmodified' => $query->createNamedParameter(5489543),
783
-					'etag' => $query->createNamedParameter('etag'),
784
-					'size' => $query->createNamedParameter(120),
785
-				]
786
-			);
787
-		$query->execute();
788
-
789
-		$id = $query->getLastInsertId();
790
-
791
-		$this->assertSame('uri', $this->backend->getCardUri($id));
792
-	}
793
-
794
-
795
-	public function testGetCardUriFailed(): void {
796
-		$this->expectException(\InvalidArgumentException::class);
797
-
798
-		$this->backend->getCardUri(1);
799
-	}
800
-
801
-	public function testGetContact(): void {
802
-		$query = $this->db->getQueryBuilder();
803
-		for ($i = 0; $i < 2; $i++) {
804
-			$query->insert($this->dbCardsTable)
805
-				->values(
806
-					[
807
-						'addressbookid' => $query->createNamedParameter($i),
808
-						'carddata' => $query->createNamedParameter('carddata' . $i, IQueryBuilder::PARAM_LOB),
809
-						'uri' => $query->createNamedParameter('uri' . $i),
810
-						'lastmodified' => $query->createNamedParameter(5489543),
811
-						'etag' => $query->createNamedParameter('etag' . $i),
812
-						'size' => $query->createNamedParameter(120),
813
-					]
814
-				);
815
-			$query->execute();
816
-		}
817
-
818
-		$result = $this->backend->getContact(0, 'uri0');
819
-		$this->assertSame(8, count($result));
820
-		$this->assertSame(0, (int)$result['addressbookid']);
821
-		$this->assertSame('uri0', $result['uri']);
822
-		$this->assertSame(5489543, (int)$result['lastmodified']);
823
-		$this->assertSame('"etag0"', $result['etag']);
824
-		$this->assertSame(120, (int)$result['size']);
825
-
826
-		// this shouldn't return any result because 'uri1' is in address book 1
827
-		// see https://github.com/nextcloud/server/issues/229
828
-		$result = $this->backend->getContact(0, 'uri1');
829
-		$this->assertEmpty($result);
830
-	}
831
-
832
-	public function testGetContactFail(): void {
833
-		$this->assertEmpty($this->backend->getContact(0, 'uri'));
834
-	}
835
-
836
-	public function testCollectCardProperties(): void {
837
-		$query = $this->db->getQueryBuilder();
838
-		$query->insert($this->dbCardsPropertiesTable)
839
-			->values(
840
-				[
841
-					'addressbookid' => $query->createNamedParameter(666),
842
-					'cardid' => $query->createNamedParameter(777),
843
-					'name' => $query->createNamedParameter('FN'),
844
-					'value' => $query->createNamedParameter('John Doe'),
845
-					'preferred' => $query->createNamedParameter(0)
846
-				]
847
-			)
848
-			->execute();
849
-
850
-		$result = $this->backend->collectCardProperties(666, 'FN');
851
-		$this->assertEquals(['John Doe'], $result);
852
-	}
853
-
854
-	/**
855
-	 * @throws \OCP\DB\Exception
856
-	 * @throws \Sabre\DAV\Exception\BadRequest
857
-	 */
858
-	public function testPruneOutdatedSyncTokens(): void {
859
-		$addressBookId = $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
860
-		$changes = $this->backend->getChangesForAddressBook($addressBookId, '', 1);
861
-		$syncToken = $changes['syncToken'];
862
-
863
-		$uri = $this->getUniqueID('card');
864
-		$this->backend->createCard($addressBookId, $uri, $this->vcardTest0);
865
-		$this->backend->updateCard($addressBookId, $uri, $this->vcardTest1);
866
-
867
-		// Do not delete anything if week data as old as ts=0
868
-		$deleted = $this->backend->pruneOutdatedSyncTokens(0, 0);
869
-		self::assertSame(0, $deleted);
870
-
871
-		$deleted = $this->backend->pruneOutdatedSyncTokens(0, time());
872
-		// At least one from the object creation and one from the object update
873
-		$this->assertGreaterThanOrEqual(2, $deleted);
874
-		$changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 1);
875
-		$this->assertEmpty($changes['added']);
876
-		$this->assertEmpty($changes['modified']);
877
-		$this->assertEmpty($changes['deleted']);
878
-
879
-		// Test that objects remain
880
-
881
-		// Currently changes are empty
882
-		$changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100);
883
-		$this->assertEquals(0, count($changes['added'] + $changes['modified'] + $changes['deleted']));
884
-
885
-		// Create card
886
-		$uri = $this->getUniqueID('card');
887
-		$this->backend->createCard($addressBookId, $uri, $this->vcardTest0);
888
-		// We now have one add
889
-		$changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100);
890
-		$this->assertEquals(1, count($changes['added']));
891
-		$this->assertEmpty($changes['modified']);
892
-		$this->assertEmpty($changes['deleted']);
893
-
894
-		// Update card
895
-		$this->backend->updateCard($addressBookId, $uri, $this->vcardTest1);
896
-		// One add, one modify, but shortened to modify
897
-		$changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100);
898
-		$this->assertEmpty($changes['added']);
899
-		$this->assertEquals(1, count($changes['modified']));
900
-		$this->assertEmpty($changes['deleted']);
901
-
902
-		// Delete all but last change
903
-		$deleted = $this->backend->pruneOutdatedSyncTokens(1, time());
904
-		$this->assertEquals(1, $deleted); // We had two changes before, now one
905
-
906
-		// Only update should remain
907
-		$changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100);
908
-		$this->assertEmpty($changes['added']);
909
-		$this->assertEquals(1, count($changes['modified']));
910
-		$this->assertEmpty($changes['deleted']);
911
-
912
-		// Check that no crash occurs when prune is called without current changes
913
-		$deleted = $this->backend->pruneOutdatedSyncTokens(1, time());
914
-	}
49
+    private Principal&MockObject $principal;
50
+    private IUserManager&MockObject $userManager;
51
+    private IGroupManager&MockObject $groupManager;
52
+    private IEventDispatcher&MockObject $dispatcher;
53
+    private Backend $sharingBackend;
54
+    private IDBConnection $db;
55
+    private CardDavBackend $backend;
56
+    private string $dbCardsTable = 'cards';
57
+    private string $dbCardsPropertiesTable = 'cards_properties';
58
+
59
+    public const UNIT_TEST_USER = 'principals/users/carddav-unit-test';
60
+    public const UNIT_TEST_USER1 = 'principals/users/carddav-unit-test1';
61
+    public const UNIT_TEST_GROUP = 'principals/groups/carddav-unit-test-group';
62
+
63
+    private $vcardTest0 = 'BEGIN:VCARD' . PHP_EOL
64
+        . 'VERSION:3.0' . PHP_EOL
65
+        . 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
66
+        . 'UID:Test' . PHP_EOL
67
+        . 'FN:Test' . PHP_EOL
68
+        . 'N:Test;;;;' . PHP_EOL
69
+        . 'END:VCARD';
70
+
71
+    private $vcardTest1 = 'BEGIN:VCARD' . PHP_EOL
72
+        . 'VERSION:3.0' . PHP_EOL
73
+        . 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
74
+        . 'UID:Test2' . PHP_EOL
75
+        . 'FN:Test2' . PHP_EOL
76
+        . 'N:Test2;;;;' . PHP_EOL
77
+        . 'END:VCARD';
78
+
79
+    private $vcardTest2 = 'BEGIN:VCARD' . PHP_EOL
80
+        . 'VERSION:3.0' . PHP_EOL
81
+        . 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
82
+        . 'UID:Test3' . PHP_EOL
83
+        . 'FN:Test3' . PHP_EOL
84
+        . 'N:Test3;;;;' . PHP_EOL
85
+        . 'END:VCARD';
86
+
87
+    private $vcardTestNoUID = 'BEGIN:VCARD' . PHP_EOL
88
+        . 'VERSION:3.0' . PHP_EOL
89
+        . 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
90
+        . 'FN:TestNoUID' . PHP_EOL
91
+        . 'N:TestNoUID;;;;' . PHP_EOL
92
+        . 'END:VCARD';
93
+
94
+    protected function setUp(): void {
95
+        parent::setUp();
96
+
97
+        $this->userManager = $this->createMock(IUserManager::class);
98
+        $this->groupManager = $this->createMock(IGroupManager::class);
99
+        $this->principal = $this->getMockBuilder(Principal::class)
100
+            ->setConstructorArgs([
101
+                $this->userManager,
102
+                $this->groupManager,
103
+                $this->createMock(IAccountManager::class),
104
+                $this->createMock(ShareManager::class),
105
+                $this->createMock(IUserSession::class),
106
+                $this->createMock(IAppManager::class),
107
+                $this->createMock(ProxyMapper::class),
108
+                $this->createMock(KnownUserService::class),
109
+                $this->createMock(IConfig::class),
110
+                $this->createMock(IFactory::class)
111
+            ])
112
+            ->onlyMethods(['getPrincipalByPath', 'getGroupMembership', 'findByUri'])
113
+            ->getMock();
114
+        $this->principal->method('getPrincipalByPath')
115
+            ->willReturn([
116
+                'uri' => 'principals/best-friend',
117
+                '{DAV:}displayname' => 'User\'s displayname',
118
+            ]);
119
+        $this->principal->method('getGroupMembership')
120
+            ->withAnyParameters()
121
+            ->willReturn([self::UNIT_TEST_GROUP]);
122
+        $this->dispatcher = $this->createMock(IEventDispatcher::class);
123
+
124
+        $this->db = Server::get(IDBConnection::class);
125
+        $this->sharingBackend = new Backend($this->userManager,
126
+            $this->groupManager,
127
+            $this->principal,
128
+            $this->createMock(ICacheFactory::class),
129
+            new Service(new SharingMapper($this->db)),
130
+            $this->createMock(LoggerInterface::class)
131
+        );
132
+
133
+        $this->backend = new CardDavBackend($this->db,
134
+            $this->principal,
135
+            $this->userManager,
136
+            $this->dispatcher,
137
+            $this->sharingBackend,
138
+        );
139
+        // start every test with a empty cards_properties and cards table
140
+        $query = $this->db->getQueryBuilder();
141
+        $query->delete('cards_properties')->executeStatement();
142
+        $query = $this->db->getQueryBuilder();
143
+        $query->delete('cards')->executeStatement();
144
+
145
+        $this->principal->method('getGroupMembership')
146
+            ->withAnyParameters()
147
+            ->willReturn([self::UNIT_TEST_GROUP]);
148
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
149
+        foreach ($books as $book) {
150
+            $this->backend->deleteAddressBook($book['id']);
151
+        }
152
+    }
153
+
154
+    protected function tearDown(): void {
155
+        if (is_null($this->backend)) {
156
+            return;
157
+        }
158
+
159
+        $this->principal->method('getGroupMembership')
160
+            ->withAnyParameters()
161
+            ->willReturn([self::UNIT_TEST_GROUP]);
162
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
163
+        foreach ($books as $book) {
164
+            $this->backend->deleteAddressBook($book['id']);
165
+        }
166
+
167
+        parent::tearDown();
168
+    }
169
+
170
+    public function testAddressBookOperations(): void {
171
+        // create a new address book
172
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
173
+
174
+        $this->assertEquals(1, $this->backend->getAddressBooksForUserCount(self::UNIT_TEST_USER));
175
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
176
+        $this->assertEquals(1, count($books));
177
+        $this->assertEquals('Example', $books[0]['{DAV:}displayname']);
178
+        $this->assertEquals('User\'s displayname', $books[0]['{http://nextcloud.com/ns}owner-displayname']);
179
+
180
+        // update its display name
181
+        $patch = new PropPatch([
182
+            '{DAV:}displayname' => 'Unit test',
183
+            '{urn:ietf:params:xml:ns:carddav}addressbook-description' => 'Addressbook used for unit testing'
184
+        ]);
185
+        $this->backend->updateAddressBook($books[0]['id'], $patch);
186
+        $patch->commit();
187
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
188
+        $this->assertEquals(1, count($books));
189
+        $this->assertEquals('Unit test', $books[0]['{DAV:}displayname']);
190
+        $this->assertEquals('Addressbook used for unit testing', $books[0]['{urn:ietf:params:xml:ns:carddav}addressbook-description']);
191
+
192
+        // delete the address book
193
+        $this->backend->deleteAddressBook($books[0]['id']);
194
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
195
+        $this->assertEquals(0, count($books));
196
+    }
197
+
198
+    public function testAddressBookSharing(): void {
199
+        $this->userManager->expects($this->any())
200
+            ->method('userExists')
201
+            ->willReturn(true);
202
+        $this->groupManager->expects($this->any())
203
+            ->method('groupExists')
204
+            ->willReturn(true);
205
+        $this->principal->expects(self::atLeastOnce())
206
+            ->method('findByUri')
207
+            ->willReturnOnConsecutiveCalls(self::UNIT_TEST_USER1, self::UNIT_TEST_GROUP);
208
+
209
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
210
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
211
+        $this->assertEquals(1, count($books));
212
+        $l = $this->createMock(IL10N::class);
213
+        $addressBook = new AddressBook($this->backend, $books[0], $l);
214
+        $this->backend->updateShares($addressBook, [
215
+            [
216
+                'href' => 'principal:' . self::UNIT_TEST_USER1,
217
+            ],
218
+            [
219
+                'href' => 'principal:' . self::UNIT_TEST_GROUP,
220
+            ]
221
+        ], []);
222
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER1);
223
+        $this->assertEquals(1, count($books));
224
+
225
+        // delete the address book
226
+        $this->backend->deleteAddressBook($books[0]['id']);
227
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
228
+        $this->assertEquals(0, count($books));
229
+    }
230
+
231
+    public function testCardOperations(): void {
232
+        /** @var CardDavBackend&MockObject $backend */
233
+        $backend = $this->getMockBuilder(CardDavBackend::class)
234
+            ->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend])
235
+            ->onlyMethods(['updateProperties', 'purgeProperties'])
236
+            ->getMock();
237
+
238
+        // create a new address book
239
+        $backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
240
+        $books = $backend->getAddressBooksForUser(self::UNIT_TEST_USER);
241
+        $this->assertEquals(1, count($books));
242
+        $bookId = $books[0]['id'];
243
+
244
+        $uri = $this->getUniqueID('card');
245
+        // updateProperties is expected twice, once for createCard and once for updateCard
246
+        $calls = [
247
+            [$bookId, $uri, $this->vcardTest0],
248
+            [$bookId, $uri, $this->vcardTest1],
249
+        ];
250
+        $backend->expects($this->exactly(count($calls)))
251
+            ->method('updateProperties')
252
+            ->willReturnCallback(function () use (&$calls): void {
253
+                $expected = array_shift($calls);
254
+                $this->assertEquals($expected, func_get_args());
255
+            });
256
+
257
+        // Expect event
258
+        $this->dispatcher
259
+            ->expects($this->exactly(3))
260
+            ->method('dispatchTyped');
261
+
262
+        // create a card
263
+        $backend->createCard($bookId, $uri, $this->vcardTest0);
264
+
265
+        // get all the cards
266
+        $cards = $backend->getCards($bookId);
267
+        $this->assertEquals(1, count($cards));
268
+        $this->assertEquals($this->vcardTest0, $cards[0]['carddata']);
269
+
270
+        // get the cards
271
+        $card = $backend->getCard($bookId, $uri);
272
+        $this->assertNotNull($card);
273
+        $this->assertArrayHasKey('id', $card);
274
+        $this->assertArrayHasKey('uri', $card);
275
+        $this->assertArrayHasKey('lastmodified', $card);
276
+        $this->assertArrayHasKey('etag', $card);
277
+        $this->assertArrayHasKey('size', $card);
278
+        $this->assertEquals($this->vcardTest0, $card['carddata']);
279
+
280
+        // update the card
281
+        $backend->updateCard($bookId, $uri, $this->vcardTest1);
282
+        $card = $backend->getCard($bookId, $uri);
283
+        $this->assertEquals($this->vcardTest1, $card['carddata']);
284
+
285
+        // delete the card
286
+        $backend->expects($this->once())->method('purgeProperties')->with($bookId, $card['id']);
287
+        $backend->deleteCard($bookId, $uri);
288
+        $cards = $backend->getCards($bookId);
289
+        $this->assertEquals(0, count($cards));
290
+    }
291
+
292
+    public function testMultiCard(): void {
293
+        $this->backend = $this->getMockBuilder(CardDavBackend::class)
294
+            ->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend])
295
+            ->onlyMethods(['updateProperties'])
296
+            ->getMock();
297
+
298
+        // create a new address book
299
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
300
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
301
+        $this->assertEquals(1, count($books));
302
+        $bookId = $books[0]['id'];
303
+
304
+        // create a card
305
+        $uri0 = self::getUniqueID('card');
306
+        $this->backend->createCard($bookId, $uri0, $this->vcardTest0);
307
+        $uri1 = self::getUniqueID('card');
308
+        $this->backend->createCard($bookId, $uri1, $this->vcardTest1);
309
+        $uri2 = self::getUniqueID('card');
310
+        $this->backend->createCard($bookId, $uri2, $this->vcardTest2);
311
+
312
+        // get all the cards
313
+        $cards = $this->backend->getCards($bookId);
314
+        $this->assertEquals(3, count($cards));
315
+        usort($cards, function ($a, $b) {
316
+            return $a['id'] < $b['id'] ? -1 : 1;
317
+        });
318
+
319
+        $this->assertEquals($this->vcardTest0, $cards[0]['carddata']);
320
+        $this->assertEquals($this->vcardTest1, $cards[1]['carddata']);
321
+        $this->assertEquals($this->vcardTest2, $cards[2]['carddata']);
322
+
323
+        // get the cards 1 & 2 (not 0)
324
+        $cards = $this->backend->getMultipleCards($bookId, [$uri1, $uri2]);
325
+        $this->assertEquals(2, count($cards));
326
+        usort($cards, function ($a, $b) {
327
+            return $a['id'] < $b['id'] ? -1 : 1;
328
+        });
329
+        foreach ($cards as $index => $card) {
330
+            $this->assertArrayHasKey('id', $card);
331
+            $this->assertArrayHasKey('uri', $card);
332
+            $this->assertArrayHasKey('lastmodified', $card);
333
+            $this->assertArrayHasKey('etag', $card);
334
+            $this->assertArrayHasKey('size', $card);
335
+            $this->assertEquals($this->{ 'vcardTest' . ($index + 1) }, $card['carddata']);
336
+        }
337
+
338
+        // delete the card
339
+        $this->backend->deleteCard($bookId, $uri0);
340
+        $this->backend->deleteCard($bookId, $uri1);
341
+        $this->backend->deleteCard($bookId, $uri2);
342
+        $cards = $this->backend->getCards($bookId);
343
+        $this->assertEquals(0, count($cards));
344
+    }
345
+
346
+    public function testMultipleUIDOnDifferentAddressbooks(): void {
347
+        $this->backend = $this->getMockBuilder(CardDavBackend::class)
348
+            ->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend])
349
+            ->onlyMethods(['updateProperties'])
350
+            ->getMock();
351
+
352
+        // create 2 new address books
353
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
354
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example2', []);
355
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
356
+        $this->assertEquals(2, count($books));
357
+        $bookId0 = $books[0]['id'];
358
+        $bookId1 = $books[1]['id'];
359
+
360
+        // create a card
361
+        $uri0 = $this->getUniqueID('card');
362
+        $this->backend->createCard($bookId0, $uri0, $this->vcardTest0);
363
+
364
+        // create another card with same uid but in second address book
365
+        $uri1 = $this->getUniqueID('card');
366
+        $this->backend->createCard($bookId1, $uri1, $this->vcardTest0);
367
+    }
368
+
369
+    public function testMultipleUIDDenied(): void {
370
+        $this->backend = $this->getMockBuilder(CardDavBackend::class)
371
+            ->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend])
372
+            ->onlyMethods(['updateProperties'])
373
+            ->getMock();
374
+
375
+        // create a new address book
376
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
377
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
378
+        $this->assertEquals(1, count($books));
379
+        $bookId = $books[0]['id'];
380
+
381
+        // create a card
382
+        $uri0 = $this->getUniqueID('card');
383
+        $this->backend->createCard($bookId, $uri0, $this->vcardTest0);
384
+
385
+        // create another card with same uid
386
+        $uri1 = $this->getUniqueID('card');
387
+        $this->expectException(BadRequest::class);
388
+        $test = $this->backend->createCard($bookId, $uri1, $this->vcardTest0);
389
+    }
390
+
391
+    public function testNoValidUID(): void {
392
+        $this->backend = $this->getMockBuilder(CardDavBackend::class)
393
+            ->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend])
394
+            ->onlyMethods(['updateProperties'])
395
+            ->getMock();
396
+
397
+        // create a new address book
398
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
399
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
400
+        $this->assertEquals(1, count($books));
401
+        $bookId = $books[0]['id'];
402
+
403
+        // create a card without uid
404
+        $uri1 = $this->getUniqueID('card');
405
+        $this->expectException(BadRequest::class);
406
+        $test = $this->backend->createCard($bookId, $uri1, $this->vcardTestNoUID);
407
+    }
408
+
409
+    public function testDeleteWithoutCard(): void {
410
+        $this->backend = $this->getMockBuilder(CardDavBackend::class)
411
+            ->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend])
412
+            ->onlyMethods([
413
+                'getCardId',
414
+                'addChange',
415
+                'purgeProperties',
416
+                'updateProperties',
417
+            ])
418
+            ->getMock();
419
+
420
+        // create a new address book
421
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
422
+        $books = $this->backend->getUsersOwnAddressBooks(self::UNIT_TEST_USER);
423
+        $this->assertEquals(1, count($books));
424
+
425
+        $bookId = $books[0]['id'];
426
+        $uri = $this->getUniqueID('card');
427
+
428
+        // create a new address book
429
+        $this->backend->expects($this->once())
430
+            ->method('getCardId')
431
+            ->with($bookId, $uri)
432
+            ->willThrowException(new \InvalidArgumentException());
433
+
434
+        $calls = [
435
+            [$bookId, $uri, 1],
436
+            [$bookId, $uri, 3],
437
+        ];
438
+        $this->backend->expects($this->exactly(count($calls)))
439
+            ->method('addChange')
440
+            ->willReturnCallback(function () use (&$calls): void {
441
+                $expected = array_shift($calls);
442
+                $this->assertEquals($expected, func_get_args());
443
+            });
444
+        $this->backend->expects($this->never())
445
+            ->method('purgeProperties');
446
+
447
+        // create a card
448
+        $this->backend->createCard($bookId, $uri, $this->vcardTest0);
449
+
450
+        // delete the card
451
+        $this->assertTrue($this->backend->deleteCard($bookId, $uri));
452
+    }
453
+
454
+    public function testSyncSupport(): void {
455
+        $this->backend = $this->getMockBuilder(CardDavBackend::class)
456
+            ->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend])
457
+            ->onlyMethods(['updateProperties'])
458
+            ->getMock();
459
+
460
+        // create a new address book
461
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
462
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
463
+        $this->assertEquals(1, count($books));
464
+        $bookId = $books[0]['id'];
465
+
466
+        // fist call without synctoken
467
+        $changes = $this->backend->getChangesForAddressBook($bookId, '', 1);
468
+        $syncToken = $changes['syncToken'];
469
+
470
+        // add a change
471
+        $uri0 = $this->getUniqueID('card');
472
+        $this->backend->createCard($bookId, $uri0, $this->vcardTest0);
473
+
474
+        // look for changes
475
+        $changes = $this->backend->getChangesForAddressBook($bookId, $syncToken, 1);
476
+        $this->assertEquals($uri0, $changes['added'][0]);
477
+    }
478
+
479
+    public function testSharing(): void {
480
+        $this->userManager->expects($this->any())
481
+            ->method('userExists')
482
+            ->willReturn(true);
483
+        $this->groupManager->expects($this->any())
484
+            ->method('groupExists')
485
+            ->willReturn(true);
486
+        $this->principal->expects(self::any())
487
+            ->method('findByUri')
488
+            ->willReturn(self::UNIT_TEST_USER1);
489
+
490
+        $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
491
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER);
492
+        $this->assertEquals(1, count($books));
493
+
494
+        $l = $this->createMock(IL10N::class);
495
+        $exampleBook = new AddressBook($this->backend, $books[0], $l);
496
+        $this->backend->updateShares($exampleBook, [['href' => 'principal:' . self::UNIT_TEST_USER1]], []);
497
+
498
+        $shares = $this->backend->getShares($exampleBook->getResourceId());
499
+        $this->assertEquals(1, count($shares));
500
+
501
+        // adding the same sharee again has no effect
502
+        $this->backend->updateShares($exampleBook, [['href' => 'principal:' . self::UNIT_TEST_USER1]], []);
503
+
504
+        $shares = $this->backend->getShares($exampleBook->getResourceId());
505
+        $this->assertEquals(1, count($shares));
506
+
507
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER1);
508
+        $this->assertEquals(1, count($books));
509
+
510
+        $this->backend->updateShares($exampleBook, [], ['principal:' . self::UNIT_TEST_USER1]);
511
+
512
+        $shares = $this->backend->getShares($exampleBook->getResourceId());
513
+        $this->assertEquals(0, count($shares));
514
+
515
+        $books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER1);
516
+        $this->assertEquals(0, count($books));
517
+    }
518
+
519
+    public function testUpdateProperties(): void {
520
+        $bookId = 42;
521
+        $cardUri = 'card-uri';
522
+        $cardId = 2;
523
+
524
+        $backend = $this->getMockBuilder(CardDavBackend::class)
525
+            ->setConstructorArgs([$this->db, $this->principal, $this->userManager, $this->dispatcher, $this->sharingBackend])
526
+            ->onlyMethods(['getCardId'])->getMock();
527
+
528
+        $backend->expects($this->any())->method('getCardId')->willReturn($cardId);
529
+
530
+        // add properties for new vCard
531
+        $vCard = new VCard();
532
+        $vCard->UID = $cardUri;
533
+        $vCard->FN = 'John Doe';
534
+        $this->invokePrivate($backend, 'updateProperties', [$bookId, $cardUri, $vCard->serialize()]);
535
+
536
+        $query = $this->db->getQueryBuilder();
537
+        $query->select('*')
538
+            ->from('cards_properties')
539
+            ->orderBy('name');
540
+
541
+        $qResult = $query->execute();
542
+        $result = $qResult->fetchAll();
543
+        $qResult->closeCursor();
544
+
545
+        $this->assertSame(2, count($result));
546
+
547
+        $this->assertSame('FN', $result[0]['name']);
548
+        $this->assertSame('John Doe', $result[0]['value']);
549
+        $this->assertSame($bookId, (int)$result[0]['addressbookid']);
550
+        $this->assertSame($cardId, (int)$result[0]['cardid']);
551
+
552
+        $this->assertSame('UID', $result[1]['name']);
553
+        $this->assertSame($cardUri, $result[1]['value']);
554
+        $this->assertSame($bookId, (int)$result[1]['addressbookid']);
555
+        $this->assertSame($cardId, (int)$result[1]['cardid']);
556
+
557
+        // update properties for existing vCard
558
+        $vCard = new VCard();
559
+        $vCard->UID = $cardUri;
560
+        $this->invokePrivate($backend, 'updateProperties', [$bookId, $cardUri, $vCard->serialize()]);
561
+
562
+        $query = $this->db->getQueryBuilder();
563
+        $query->select('*')
564
+            ->from('cards_properties');
565
+
566
+        $qResult = $query->execute();
567
+        $result = $qResult->fetchAll();
568
+        $qResult->closeCursor();
569
+
570
+        $this->assertSame(1, count($result));
571
+
572
+        $this->assertSame('UID', $result[0]['name']);
573
+        $this->assertSame($cardUri, $result[0]['value']);
574
+        $this->assertSame($bookId, (int)$result[0]['addressbookid']);
575
+        $this->assertSame($cardId, (int)$result[0]['cardid']);
576
+    }
577
+
578
+    public function testPurgeProperties(): void {
579
+        $query = $this->db->getQueryBuilder();
580
+        $query->insert('cards_properties')
581
+            ->values(
582
+                [
583
+                    'addressbookid' => $query->createNamedParameter(1),
584
+                    'cardid' => $query->createNamedParameter(1),
585
+                    'name' => $query->createNamedParameter('name1'),
586
+                    'value' => $query->createNamedParameter('value1'),
587
+                    'preferred' => $query->createNamedParameter(0)
588
+                ]
589
+            );
590
+        $query->execute();
591
+
592
+        $query = $this->db->getQueryBuilder();
593
+        $query->insert('cards_properties')
594
+            ->values(
595
+                [
596
+                    'addressbookid' => $query->createNamedParameter(1),
597
+                    'cardid' => $query->createNamedParameter(2),
598
+                    'name' => $query->createNamedParameter('name2'),
599
+                    'value' => $query->createNamedParameter('value2'),
600
+                    'preferred' => $query->createNamedParameter(0)
601
+                ]
602
+            );
603
+        $query->execute();
604
+
605
+        $this->invokePrivate($this->backend, 'purgeProperties', [1, 1]);
606
+
607
+        $query = $this->db->getQueryBuilder();
608
+        $query->select('*')
609
+            ->from('cards_properties');
610
+
611
+        $qResult = $query->execute();
612
+        $result = $qResult->fetchAll();
613
+        $qResult->closeCursor();
614
+
615
+        $this->assertSame(1, count($result));
616
+        $this->assertSame(1, (int)$result[0]['addressbookid']);
617
+        $this->assertSame(2, (int)$result[0]['cardid']);
618
+    }
619
+
620
+    public function testGetCardId(): void {
621
+        $query = $this->db->getQueryBuilder();
622
+
623
+        $query->insert('cards')
624
+            ->values(
625
+                [
626
+                    'addressbookid' => $query->createNamedParameter(1),
627
+                    'carddata' => $query->createNamedParameter(''),
628
+                    'uri' => $query->createNamedParameter('uri'),
629
+                    'lastmodified' => $query->createNamedParameter(4738743),
630
+                    'etag' => $query->createNamedParameter('etag'),
631
+                    'size' => $query->createNamedParameter(120)
632
+                ]
633
+            );
634
+        $query->execute();
635
+        $id = $query->getLastInsertId();
636
+
637
+        $this->assertSame($id,
638
+            $this->invokePrivate($this->backend, 'getCardId', [1, 'uri']));
639
+    }
640
+
641
+
642
+    public function testGetCardIdFailed(): void {
643
+        $this->expectException(\InvalidArgumentException::class);
644
+
645
+        $this->invokePrivate($this->backend, 'getCardId', [1, 'uri']);
646
+    }
647
+
648
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestSearch')]
649
+    public function testSearch(string $pattern, array $properties, array $options, array $expected): void {
650
+        /** @var VCard $vCards */
651
+        $vCards = [];
652
+        $vCards[0] = new VCard();
653
+        $vCards[0]->add(new Text($vCards[0], 'UID', 'uid'));
654
+        $vCards[0]->add(new Text($vCards[0], 'FN', 'John Doe'));
655
+        $vCards[0]->add(new Text($vCards[0], 'CLOUD', '[email protected]'));
656
+        $vCards[1] = new VCard();
657
+        $vCards[1]->add(new Text($vCards[1], 'UID', 'uid'));
658
+        $vCards[1]->add(new Text($vCards[1], 'FN', 'John M. Doe'));
659
+        $vCards[2] = new VCard();
660
+        $vCards[2]->add(new Text($vCards[2], 'UID', 'uid'));
661
+        $vCards[2]->add(new Text($vCards[2], 'FN', 'find without options'));
662
+        $vCards[2]->add(new Text($vCards[2], 'CLOUD', '[email protected]'));
663
+
664
+        $vCardIds = [];
665
+        $query = $this->db->getQueryBuilder();
666
+        for ($i = 0; $i < 3; $i++) {
667
+            $query->insert($this->dbCardsTable)
668
+                ->values(
669
+                    [
670
+                        'addressbookid' => $query->createNamedParameter(0),
671
+                        'carddata' => $query->createNamedParameter($vCards[$i]->serialize(), IQueryBuilder::PARAM_LOB),
672
+                        'uri' => $query->createNamedParameter('uri' . $i),
673
+                        'lastmodified' => $query->createNamedParameter(time()),
674
+                        'etag' => $query->createNamedParameter('etag' . $i),
675
+                        'size' => $query->createNamedParameter(120),
676
+                    ]
677
+                );
678
+            $query->execute();
679
+            $vCardIds[] = $query->getLastInsertId();
680
+        }
681
+
682
+        $query = $this->db->getQueryBuilder();
683
+        $query->insert($this->dbCardsPropertiesTable)
684
+            ->values(
685
+                [
686
+                    'addressbookid' => $query->createNamedParameter(0),
687
+                    'cardid' => $query->createNamedParameter($vCardIds[0]),
688
+                    'name' => $query->createNamedParameter('FN'),
689
+                    'value' => $query->createNamedParameter('John Doe'),
690
+                    'preferred' => $query->createNamedParameter(0)
691
+                ]
692
+            );
693
+        $query->execute();
694
+        $query = $this->db->getQueryBuilder();
695
+        $query->insert($this->dbCardsPropertiesTable)
696
+            ->values(
697
+                [
698
+                    'addressbookid' => $query->createNamedParameter(0),
699
+                    'cardid' => $query->createNamedParameter($vCardIds[0]),
700
+                    'name' => $query->createNamedParameter('CLOUD'),
701
+                    'value' => $query->createNamedParameter('[email protected]'),
702
+                    'preferred' => $query->createNamedParameter(0)
703
+                ]
704
+            );
705
+        $query->execute();
706
+        $query = $this->db->getQueryBuilder();
707
+        $query->insert($this->dbCardsPropertiesTable)
708
+            ->values(
709
+                [
710
+                    'addressbookid' => $query->createNamedParameter(0),
711
+                    'cardid' => $query->createNamedParameter($vCardIds[1]),
712
+                    'name' => $query->createNamedParameter('FN'),
713
+                    'value' => $query->createNamedParameter('John M. Doe'),
714
+                    'preferred' => $query->createNamedParameter(0)
715
+                ]
716
+            );
717
+        $query->execute();
718
+        $query = $this->db->getQueryBuilder();
719
+        $query->insert($this->dbCardsPropertiesTable)
720
+            ->values(
721
+                [
722
+                    'addressbookid' => $query->createNamedParameter(0),
723
+                    'cardid' => $query->createNamedParameter($vCardIds[2]),
724
+                    'name' => $query->createNamedParameter('FN'),
725
+                    'value' => $query->createNamedParameter('find without options'),
726
+                    'preferred' => $query->createNamedParameter(0)
727
+                ]
728
+            );
729
+        $query->execute();
730
+        $query = $this->db->getQueryBuilder();
731
+        $query->insert($this->dbCardsPropertiesTable)
732
+            ->values(
733
+                [
734
+                    'addressbookid' => $query->createNamedParameter(0),
735
+                    'cardid' => $query->createNamedParameter($vCardIds[2]),
736
+                    'name' => $query->createNamedParameter('CLOUD'),
737
+                    'value' => $query->createNamedParameter('[email protected]'),
738
+                    'preferred' => $query->createNamedParameter(0)
739
+                ]
740
+            );
741
+        $query->execute();
742
+
743
+        $result = $this->backend->search(0, $pattern, $properties, $options);
744
+
745
+        // check result
746
+        $this->assertSame(count($expected), count($result));
747
+        $found = [];
748
+        foreach ($result as $r) {
749
+            foreach ($expected as $exp) {
750
+                if ($r['uri'] === $exp[0] && strpos($r['carddata'], $exp[1]) > 0) {
751
+                    $found[$exp[1]] = true;
752
+                    break;
753
+                }
754
+            }
755
+        }
756
+
757
+        $this->assertSame(count($expected), count($found));
758
+    }
759
+
760
+    public static function dataTestSearch(): array {
761
+        return [
762
+            ['John', ['FN'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
763
+            ['M. Doe', ['FN'], [], [['uri1', 'John M. Doe']]],
764
+            ['Do', ['FN'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
765
+            'check if duplicates are handled correctly' => ['John', ['FN', 'CLOUD'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
766
+            'case insensitive' => ['john', ['FN'], [], [['uri0', 'John Doe'], ['uri1', 'John M. Doe']]],
767
+            'limit' => ['john', ['FN'], ['limit' => 1], [['uri0', 'John Doe']]],
768
+            'limit and offset' => ['john', ['FN'], ['limit' => 1, 'offset' => 1], [['uri1', 'John M. Doe']]],
769
+            'find "_" escaped' => ['_', ['CLOUD'], [], [['uri2', 'find without options']]],
770
+            'find not empty CLOUD' => ['%_%', ['CLOUD'], ['escape_like_param' => false], [['uri0', 'John Doe'], ['uri2', 'find without options']]],
771
+        ];
772
+    }
773
+
774
+    public function testGetCardUri(): void {
775
+        $query = $this->db->getQueryBuilder();
776
+        $query->insert($this->dbCardsTable)
777
+            ->values(
778
+                [
779
+                    'addressbookid' => $query->createNamedParameter(1),
780
+                    'carddata' => $query->createNamedParameter('carddata', IQueryBuilder::PARAM_LOB),
781
+                    'uri' => $query->createNamedParameter('uri'),
782
+                    'lastmodified' => $query->createNamedParameter(5489543),
783
+                    'etag' => $query->createNamedParameter('etag'),
784
+                    'size' => $query->createNamedParameter(120),
785
+                ]
786
+            );
787
+        $query->execute();
788
+
789
+        $id = $query->getLastInsertId();
790
+
791
+        $this->assertSame('uri', $this->backend->getCardUri($id));
792
+    }
793
+
794
+
795
+    public function testGetCardUriFailed(): void {
796
+        $this->expectException(\InvalidArgumentException::class);
797
+
798
+        $this->backend->getCardUri(1);
799
+    }
800
+
801
+    public function testGetContact(): void {
802
+        $query = $this->db->getQueryBuilder();
803
+        for ($i = 0; $i < 2; $i++) {
804
+            $query->insert($this->dbCardsTable)
805
+                ->values(
806
+                    [
807
+                        'addressbookid' => $query->createNamedParameter($i),
808
+                        'carddata' => $query->createNamedParameter('carddata' . $i, IQueryBuilder::PARAM_LOB),
809
+                        'uri' => $query->createNamedParameter('uri' . $i),
810
+                        'lastmodified' => $query->createNamedParameter(5489543),
811
+                        'etag' => $query->createNamedParameter('etag' . $i),
812
+                        'size' => $query->createNamedParameter(120),
813
+                    ]
814
+                );
815
+            $query->execute();
816
+        }
817
+
818
+        $result = $this->backend->getContact(0, 'uri0');
819
+        $this->assertSame(8, count($result));
820
+        $this->assertSame(0, (int)$result['addressbookid']);
821
+        $this->assertSame('uri0', $result['uri']);
822
+        $this->assertSame(5489543, (int)$result['lastmodified']);
823
+        $this->assertSame('"etag0"', $result['etag']);
824
+        $this->assertSame(120, (int)$result['size']);
825
+
826
+        // this shouldn't return any result because 'uri1' is in address book 1
827
+        // see https://github.com/nextcloud/server/issues/229
828
+        $result = $this->backend->getContact(0, 'uri1');
829
+        $this->assertEmpty($result);
830
+    }
831
+
832
+    public function testGetContactFail(): void {
833
+        $this->assertEmpty($this->backend->getContact(0, 'uri'));
834
+    }
835
+
836
+    public function testCollectCardProperties(): void {
837
+        $query = $this->db->getQueryBuilder();
838
+        $query->insert($this->dbCardsPropertiesTable)
839
+            ->values(
840
+                [
841
+                    'addressbookid' => $query->createNamedParameter(666),
842
+                    'cardid' => $query->createNamedParameter(777),
843
+                    'name' => $query->createNamedParameter('FN'),
844
+                    'value' => $query->createNamedParameter('John Doe'),
845
+                    'preferred' => $query->createNamedParameter(0)
846
+                ]
847
+            )
848
+            ->execute();
849
+
850
+        $result = $this->backend->collectCardProperties(666, 'FN');
851
+        $this->assertEquals(['John Doe'], $result);
852
+    }
853
+
854
+    /**
855
+     * @throws \OCP\DB\Exception
856
+     * @throws \Sabre\DAV\Exception\BadRequest
857
+     */
858
+    public function testPruneOutdatedSyncTokens(): void {
859
+        $addressBookId = $this->backend->createAddressBook(self::UNIT_TEST_USER, 'Example', []);
860
+        $changes = $this->backend->getChangesForAddressBook($addressBookId, '', 1);
861
+        $syncToken = $changes['syncToken'];
862
+
863
+        $uri = $this->getUniqueID('card');
864
+        $this->backend->createCard($addressBookId, $uri, $this->vcardTest0);
865
+        $this->backend->updateCard($addressBookId, $uri, $this->vcardTest1);
866
+
867
+        // Do not delete anything if week data as old as ts=0
868
+        $deleted = $this->backend->pruneOutdatedSyncTokens(0, 0);
869
+        self::assertSame(0, $deleted);
870
+
871
+        $deleted = $this->backend->pruneOutdatedSyncTokens(0, time());
872
+        // At least one from the object creation and one from the object update
873
+        $this->assertGreaterThanOrEqual(2, $deleted);
874
+        $changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 1);
875
+        $this->assertEmpty($changes['added']);
876
+        $this->assertEmpty($changes['modified']);
877
+        $this->assertEmpty($changes['deleted']);
878
+
879
+        // Test that objects remain
880
+
881
+        // Currently changes are empty
882
+        $changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100);
883
+        $this->assertEquals(0, count($changes['added'] + $changes['modified'] + $changes['deleted']));
884
+
885
+        // Create card
886
+        $uri = $this->getUniqueID('card');
887
+        $this->backend->createCard($addressBookId, $uri, $this->vcardTest0);
888
+        // We now have one add
889
+        $changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100);
890
+        $this->assertEquals(1, count($changes['added']));
891
+        $this->assertEmpty($changes['modified']);
892
+        $this->assertEmpty($changes['deleted']);
893
+
894
+        // Update card
895
+        $this->backend->updateCard($addressBookId, $uri, $this->vcardTest1);
896
+        // One add, one modify, but shortened to modify
897
+        $changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100);
898
+        $this->assertEmpty($changes['added']);
899
+        $this->assertEquals(1, count($changes['modified']));
900
+        $this->assertEmpty($changes['deleted']);
901
+
902
+        // Delete all but last change
903
+        $deleted = $this->backend->pruneOutdatedSyncTokens(1, time());
904
+        $this->assertEquals(1, $deleted); // We had two changes before, now one
905
+
906
+        // Only update should remain
907
+        $changes = $this->backend->getChangesForAddressBook($addressBookId, $syncToken, 100);
908
+        $this->assertEmpty($changes['added']);
909
+        $this->assertEquals(1, count($changes['modified']));
910
+        $this->assertEmpty($changes['deleted']);
911
+
912
+        // Check that no crash occurs when prune is called without current changes
913
+        $deleted = $this->backend->pruneOutdatedSyncTokens(1, time());
914
+    }
915 915
 }
Please login to merge, or discard this patch.
Spacing   +49 added lines, -49 removed lines patch added patch discarded remove patch
@@ -60,35 +60,35 @@  discard block
 block discarded – undo
60 60
 	public const UNIT_TEST_USER1 = 'principals/users/carddav-unit-test1';
61 61
 	public const UNIT_TEST_GROUP = 'principals/groups/carddav-unit-test-group';
62 62
 
63
-	private $vcardTest0 = 'BEGIN:VCARD' . PHP_EOL
64
-		. 'VERSION:3.0' . PHP_EOL
65
-		. 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
66
-		. 'UID:Test' . PHP_EOL
67
-		. 'FN:Test' . PHP_EOL
68
-		. 'N:Test;;;;' . PHP_EOL
63
+	private $vcardTest0 = 'BEGIN:VCARD'.PHP_EOL
64
+		. 'VERSION:3.0'.PHP_EOL
65
+		. 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN'.PHP_EOL
66
+		. 'UID:Test'.PHP_EOL
67
+		. 'FN:Test'.PHP_EOL
68
+		. 'N:Test;;;;'.PHP_EOL
69 69
 		. 'END:VCARD';
70 70
 
71
-	private $vcardTest1 = 'BEGIN:VCARD' . PHP_EOL
72
-		. 'VERSION:3.0' . PHP_EOL
73
-		. 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
74
-		. 'UID:Test2' . PHP_EOL
75
-		. 'FN:Test2' . PHP_EOL
76
-		. 'N:Test2;;;;' . PHP_EOL
71
+	private $vcardTest1 = 'BEGIN:VCARD'.PHP_EOL
72
+		. 'VERSION:3.0'.PHP_EOL
73
+		. 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN'.PHP_EOL
74
+		. 'UID:Test2'.PHP_EOL
75
+		. 'FN:Test2'.PHP_EOL
76
+		. 'N:Test2;;;;'.PHP_EOL
77 77
 		. 'END:VCARD';
78 78
 
79
-	private $vcardTest2 = 'BEGIN:VCARD' . PHP_EOL
80
-		. 'VERSION:3.0' . PHP_EOL
81
-		. 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
82
-		. 'UID:Test3' . PHP_EOL
83
-		. 'FN:Test3' . PHP_EOL
84
-		. 'N:Test3;;;;' . PHP_EOL
79
+	private $vcardTest2 = 'BEGIN:VCARD'.PHP_EOL
80
+		. 'VERSION:3.0'.PHP_EOL
81
+		. 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN'.PHP_EOL
82
+		. 'UID:Test3'.PHP_EOL
83
+		. 'FN:Test3'.PHP_EOL
84
+		. 'N:Test3;;;;'.PHP_EOL
85 85
 		. 'END:VCARD';
86 86
 
87
-	private $vcardTestNoUID = 'BEGIN:VCARD' . PHP_EOL
88
-		. 'VERSION:3.0' . PHP_EOL
89
-		. 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN' . PHP_EOL
90
-		. 'FN:TestNoUID' . PHP_EOL
91
-		. 'N:TestNoUID;;;;' . PHP_EOL
87
+	private $vcardTestNoUID = 'BEGIN:VCARD'.PHP_EOL
88
+		. 'VERSION:3.0'.PHP_EOL
89
+		. 'PRODID:-//Sabre//Sabre VObject 4.1.2//EN'.PHP_EOL
90
+		. 'FN:TestNoUID'.PHP_EOL
91
+		. 'N:TestNoUID;;;;'.PHP_EOL
92 92
 		. 'END:VCARD';
93 93
 
94 94
 	protected function setUp(): void {
@@ -213,10 +213,10 @@  discard block
 block discarded – undo
213 213
 		$addressBook = new AddressBook($this->backend, $books[0], $l);
214 214
 		$this->backend->updateShares($addressBook, [
215 215
 			[
216
-				'href' => 'principal:' . self::UNIT_TEST_USER1,
216
+				'href' => 'principal:'.self::UNIT_TEST_USER1,
217 217
 			],
218 218
 			[
219
-				'href' => 'principal:' . self::UNIT_TEST_GROUP,
219
+				'href' => 'principal:'.self::UNIT_TEST_GROUP,
220 220
 			]
221 221
 		], []);
222 222
 		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER1);
@@ -249,7 +249,7 @@  discard block
 block discarded – undo
249 249
 		];
250 250
 		$backend->expects($this->exactly(count($calls)))
251 251
 			->method('updateProperties')
252
-			->willReturnCallback(function () use (&$calls): void {
252
+			->willReturnCallback(function() use (&$calls): void {
253 253
 				$expected = array_shift($calls);
254 254
 				$this->assertEquals($expected, func_get_args());
255 255
 			});
@@ -312,7 +312,7 @@  discard block
 block discarded – undo
312 312
 		// get all the cards
313 313
 		$cards = $this->backend->getCards($bookId);
314 314
 		$this->assertEquals(3, count($cards));
315
-		usort($cards, function ($a, $b) {
315
+		usort($cards, function($a, $b) {
316 316
 			return $a['id'] < $b['id'] ? -1 : 1;
317 317
 		});
318 318
 
@@ -323,7 +323,7 @@  discard block
 block discarded – undo
323 323
 		// get the cards 1 & 2 (not 0)
324 324
 		$cards = $this->backend->getMultipleCards($bookId, [$uri1, $uri2]);
325 325
 		$this->assertEquals(2, count($cards));
326
-		usort($cards, function ($a, $b) {
326
+		usort($cards, function($a, $b) {
327 327
 			return $a['id'] < $b['id'] ? -1 : 1;
328 328
 		});
329 329
 		foreach ($cards as $index => $card) {
@@ -332,7 +332,7 @@  discard block
 block discarded – undo
332 332
 			$this->assertArrayHasKey('lastmodified', $card);
333 333
 			$this->assertArrayHasKey('etag', $card);
334 334
 			$this->assertArrayHasKey('size', $card);
335
-			$this->assertEquals($this->{ 'vcardTest' . ($index + 1) }, $card['carddata']);
335
+			$this->assertEquals($this->{ 'vcardTest'.($index + 1) }, $card['carddata']);
336 336
 		}
337 337
 
338 338
 		// delete the card
@@ -437,7 +437,7 @@  discard block
 block discarded – undo
437 437
 		];
438 438
 		$this->backend->expects($this->exactly(count($calls)))
439 439
 			->method('addChange')
440
-			->willReturnCallback(function () use (&$calls): void {
440
+			->willReturnCallback(function() use (&$calls): void {
441 441
 				$expected = array_shift($calls);
442 442
 				$this->assertEquals($expected, func_get_args());
443 443
 			});
@@ -493,13 +493,13 @@  discard block
 block discarded – undo
493 493
 
494 494
 		$l = $this->createMock(IL10N::class);
495 495
 		$exampleBook = new AddressBook($this->backend, $books[0], $l);
496
-		$this->backend->updateShares($exampleBook, [['href' => 'principal:' . self::UNIT_TEST_USER1]], []);
496
+		$this->backend->updateShares($exampleBook, [['href' => 'principal:'.self::UNIT_TEST_USER1]], []);
497 497
 
498 498
 		$shares = $this->backend->getShares($exampleBook->getResourceId());
499 499
 		$this->assertEquals(1, count($shares));
500 500
 
501 501
 		// adding the same sharee again has no effect
502
-		$this->backend->updateShares($exampleBook, [['href' => 'principal:' . self::UNIT_TEST_USER1]], []);
502
+		$this->backend->updateShares($exampleBook, [['href' => 'principal:'.self::UNIT_TEST_USER1]], []);
503 503
 
504 504
 		$shares = $this->backend->getShares($exampleBook->getResourceId());
505 505
 		$this->assertEquals(1, count($shares));
@@ -507,7 +507,7 @@  discard block
 block discarded – undo
507 507
 		$books = $this->backend->getAddressBooksForUser(self::UNIT_TEST_USER1);
508 508
 		$this->assertEquals(1, count($books));
509 509
 
510
-		$this->backend->updateShares($exampleBook, [], ['principal:' . self::UNIT_TEST_USER1]);
510
+		$this->backend->updateShares($exampleBook, [], ['principal:'.self::UNIT_TEST_USER1]);
511 511
 
512 512
 		$shares = $this->backend->getShares($exampleBook->getResourceId());
513 513
 		$this->assertEquals(0, count($shares));
@@ -546,13 +546,13 @@  discard block
 block discarded – undo
546 546
 
547 547
 		$this->assertSame('FN', $result[0]['name']);
548 548
 		$this->assertSame('John Doe', $result[0]['value']);
549
-		$this->assertSame($bookId, (int)$result[0]['addressbookid']);
550
-		$this->assertSame($cardId, (int)$result[0]['cardid']);
549
+		$this->assertSame($bookId, (int) $result[0]['addressbookid']);
550
+		$this->assertSame($cardId, (int) $result[0]['cardid']);
551 551
 
552 552
 		$this->assertSame('UID', $result[1]['name']);
553 553
 		$this->assertSame($cardUri, $result[1]['value']);
554
-		$this->assertSame($bookId, (int)$result[1]['addressbookid']);
555
-		$this->assertSame($cardId, (int)$result[1]['cardid']);
554
+		$this->assertSame($bookId, (int) $result[1]['addressbookid']);
555
+		$this->assertSame($cardId, (int) $result[1]['cardid']);
556 556
 
557 557
 		// update properties for existing vCard
558 558
 		$vCard = new VCard();
@@ -571,8 +571,8 @@  discard block
 block discarded – undo
571 571
 
572 572
 		$this->assertSame('UID', $result[0]['name']);
573 573
 		$this->assertSame($cardUri, $result[0]['value']);
574
-		$this->assertSame($bookId, (int)$result[0]['addressbookid']);
575
-		$this->assertSame($cardId, (int)$result[0]['cardid']);
574
+		$this->assertSame($bookId, (int) $result[0]['addressbookid']);
575
+		$this->assertSame($cardId, (int) $result[0]['cardid']);
576 576
 	}
577 577
 
578 578
 	public function testPurgeProperties(): void {
@@ -613,8 +613,8 @@  discard block
 block discarded – undo
613 613
 		$qResult->closeCursor();
614 614
 
615 615
 		$this->assertSame(1, count($result));
616
-		$this->assertSame(1, (int)$result[0]['addressbookid']);
617
-		$this->assertSame(2, (int)$result[0]['cardid']);
616
+		$this->assertSame(1, (int) $result[0]['addressbookid']);
617
+		$this->assertSame(2, (int) $result[0]['cardid']);
618 618
 	}
619 619
 
620 620
 	public function testGetCardId(): void {
@@ -669,9 +669,9 @@  discard block
 block discarded – undo
669 669
 					[
670 670
 						'addressbookid' => $query->createNamedParameter(0),
671 671
 						'carddata' => $query->createNamedParameter($vCards[$i]->serialize(), IQueryBuilder::PARAM_LOB),
672
-						'uri' => $query->createNamedParameter('uri' . $i),
672
+						'uri' => $query->createNamedParameter('uri'.$i),
673 673
 						'lastmodified' => $query->createNamedParameter(time()),
674
-						'etag' => $query->createNamedParameter('etag' . $i),
674
+						'etag' => $query->createNamedParameter('etag'.$i),
675 675
 						'size' => $query->createNamedParameter(120),
676 676
 					]
677 677
 				);
@@ -805,10 +805,10 @@  discard block
 block discarded – undo
805 805
 				->values(
806 806
 					[
807 807
 						'addressbookid' => $query->createNamedParameter($i),
808
-						'carddata' => $query->createNamedParameter('carddata' . $i, IQueryBuilder::PARAM_LOB),
809
-						'uri' => $query->createNamedParameter('uri' . $i),
808
+						'carddata' => $query->createNamedParameter('carddata'.$i, IQueryBuilder::PARAM_LOB),
809
+						'uri' => $query->createNamedParameter('uri'.$i),
810 810
 						'lastmodified' => $query->createNamedParameter(5489543),
811
-						'etag' => $query->createNamedParameter('etag' . $i),
811
+						'etag' => $query->createNamedParameter('etag'.$i),
812 812
 						'size' => $query->createNamedParameter(120),
813 813
 					]
814 814
 				);
@@ -817,11 +817,11 @@  discard block
 block discarded – undo
817 817
 
818 818
 		$result = $this->backend->getContact(0, 'uri0');
819 819
 		$this->assertSame(8, count($result));
820
-		$this->assertSame(0, (int)$result['addressbookid']);
820
+		$this->assertSame(0, (int) $result['addressbookid']);
821 821
 		$this->assertSame('uri0', $result['uri']);
822
-		$this->assertSame(5489543, (int)$result['lastmodified']);
822
+		$this->assertSame(5489543, (int) $result['lastmodified']);
823 823
 		$this->assertSame('"etag0"', $result['etag']);
824
-		$this->assertSame(120, (int)$result['size']);
824
+		$this->assertSame(120, (int) $result['size']);
825 825
 
826 826
 		// this shouldn't return any result because 'uri1' is in address book 1
827 827
 		// see https://github.com/nextcloud/server/issues/229
Please login to merge, or discard this patch.