@@ -19,99 +19,99 @@ |
||
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 | } |
@@ -23,386 +23,386 @@ |
||
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 | } |
@@ -265,7 +265,7 @@ discard block |
||
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 |
||
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 | }); |
@@ -28,216 +28,216 @@ |
||
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 | } |
@@ -22,260 +22,260 @@ |
||
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 | } |
@@ -23,138 +23,138 @@ |
||
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 | } |
@@ -41,7 +41,7 @@ discard block |
||
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 |
||
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 | }); |
@@ -26,32 +26,32 @@ discard block |
||
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 |
||
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 | } |
@@ -40,681 +40,681 @@ |
||
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 | } |
@@ -686,7 +686,7 @@ |
||
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 | }); |
@@ -19,518 +19,518 @@ |
||
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 | } |
@@ -46,870 +46,870 @@ |
||
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 | } |
@@ -60,35 +60,35 @@ discard block |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |