Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like View often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use View, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
42 | class View extends \Test\TestCase { |
||
43 | /** |
||
44 | * @var \OC\Files\Storage\Storage[] $storages |
||
45 | */ |
||
46 | private $storages = array(); |
||
47 | |||
48 | /** |
||
49 | * @var string |
||
50 | */ |
||
51 | private $user; |
||
52 | |||
53 | /** |
||
54 | * @var \OCP\IUser |
||
55 | */ |
||
56 | private $userObject; |
||
57 | |||
58 | /** |
||
59 | * @var \OCP\IGroup |
||
60 | */ |
||
61 | private $groupObject; |
||
62 | |||
63 | /** @var \OC\Files\Storage\Storage */ |
||
64 | private $tempStorage; |
||
65 | |||
66 | protected function setUp() { |
||
67 | parent::setUp(); |
||
68 | \OC_Hook::clear(); |
||
69 | |||
70 | \OC_User::clearBackends(); |
||
71 | \OC_User::useBackend(new \Test\Util\User\Dummy()); |
||
72 | |||
73 | //login |
||
74 | $userManager = \OC::$server->getUserManager(); |
||
75 | $groupManager = \OC::$server->getGroupManager(); |
||
76 | $this->user = 'test'; |
||
77 | $this->userObject = $userManager->createUser('test', 'test'); |
||
|
|||
78 | |||
79 | $this->groupObject = $groupManager->createGroup('group1'); |
||
80 | $this->groupObject->addUser($this->userObject); |
||
81 | |||
82 | $this->loginAsUser($this->user); |
||
83 | // clear mounts but somehow keep the root storage |
||
84 | // that was initialized above... |
||
85 | \OC\Files\Filesystem::clearMounts(); |
||
86 | |||
87 | $this->tempStorage = null; |
||
88 | } |
||
89 | |||
90 | protected function tearDown() { |
||
91 | \OC_User::setUserId($this->user); |
||
92 | foreach ($this->storages as $storage) { |
||
93 | $cache = $storage->getCache(); |
||
94 | $ids = $cache->getAll(); |
||
95 | $cache->clear(); |
||
96 | } |
||
97 | |||
98 | if ($this->tempStorage && !\OC_Util::runningOnWindows()) { |
||
99 | system('rm -rf ' . escapeshellarg($this->tempStorage->getDataDir())); |
||
100 | } |
||
101 | |||
102 | $this->logout(); |
||
103 | |||
104 | $this->userObject->delete(); |
||
105 | $this->groupObject->delete(); |
||
106 | |||
107 | $mountProviderCollection = \OC::$server->getMountProviderCollection(); |
||
108 | \Test\TestCase::invokePrivate($mountProviderCollection, 'providers', [[]]); |
||
109 | |||
110 | parent::tearDown(); |
||
111 | } |
||
112 | |||
113 | /** |
||
114 | * @medium |
||
115 | */ |
||
116 | public function testCacheAPI() { |
||
117 | $storage1 = $this->getTestStorage(); |
||
118 | $storage2 = $this->getTestStorage(); |
||
119 | $storage3 = $this->getTestStorage(); |
||
120 | $root = $this->getUniqueID('/'); |
||
121 | \OC\Files\Filesystem::mount($storage1, array(), $root . '/'); |
||
122 | \OC\Files\Filesystem::mount($storage2, array(), $root . '/substorage'); |
||
123 | \OC\Files\Filesystem::mount($storage3, array(), $root . '/folder/anotherstorage'); |
||
124 | $textSize = strlen("dummy file data\n"); |
||
125 | $imageSize = filesize(\OC::$SERVERROOT . '/core/img/logo.png'); |
||
126 | $storageSize = $textSize * 2 + $imageSize; |
||
127 | |||
128 | $storageInfo = $storage3->getCache()->get(''); |
||
129 | $this->assertEquals($storageSize, $storageInfo['size']); |
||
130 | |||
131 | $rootView = new \OC\Files\View($root); |
||
132 | |||
133 | $cachedData = $rootView->getFileInfo('/foo.txt'); |
||
134 | $this->assertEquals($textSize, $cachedData['size']); |
||
135 | $this->assertEquals('text/plain', $cachedData['mimetype']); |
||
136 | $this->assertNotEquals(-1, $cachedData['permissions']); |
||
137 | |||
138 | $cachedData = $rootView->getFileInfo('/'); |
||
139 | $this->assertEquals($storageSize * 3, $cachedData['size']); |
||
140 | $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']); |
||
141 | |||
142 | // get cached data excluding mount points |
||
143 | $cachedData = $rootView->getFileInfo('/', false); |
||
144 | $this->assertEquals($storageSize, $cachedData['size']); |
||
145 | $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']); |
||
146 | |||
147 | $cachedData = $rootView->getFileInfo('/folder'); |
||
148 | $this->assertEquals($storageSize + $textSize, $cachedData['size']); |
||
149 | $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']); |
||
150 | |||
151 | $folderData = $rootView->getDirectoryContent('/'); |
||
152 | /** |
||
153 | * expected entries: |
||
154 | * folder |
||
155 | * foo.png |
||
156 | * foo.txt |
||
157 | * substorage |
||
158 | */ |
||
159 | $this->assertEquals(4, count($folderData)); |
||
160 | $this->assertEquals('folder', $folderData[0]['name']); |
||
161 | $this->assertEquals('foo.png', $folderData[1]['name']); |
||
162 | $this->assertEquals('foo.txt', $folderData[2]['name']); |
||
163 | $this->assertEquals('substorage', $folderData[3]['name']); |
||
164 | |||
165 | $this->assertEquals($storageSize + $textSize, $folderData[0]['size']); |
||
166 | $this->assertEquals($imageSize, $folderData[1]['size']); |
||
167 | $this->assertEquals($textSize, $folderData[2]['size']); |
||
168 | $this->assertEquals($storageSize, $folderData[3]['size']); |
||
169 | |||
170 | $folderData = $rootView->getDirectoryContent('/substorage'); |
||
171 | /** |
||
172 | * expected entries: |
||
173 | * folder |
||
174 | * foo.png |
||
175 | * foo.txt |
||
176 | */ |
||
177 | $this->assertEquals(3, count($folderData)); |
||
178 | $this->assertEquals('folder', $folderData[0]['name']); |
||
179 | $this->assertEquals('foo.png', $folderData[1]['name']); |
||
180 | $this->assertEquals('foo.txt', $folderData[2]['name']); |
||
181 | |||
182 | $folderView = new \OC\Files\View($root . '/folder'); |
||
183 | $this->assertEquals($rootView->getFileInfo('/folder'), $folderView->getFileInfo('/')); |
||
184 | |||
185 | $cachedData = $rootView->getFileInfo('/foo.txt'); |
||
186 | $this->assertFalse($cachedData['encrypted']); |
||
187 | $id = $rootView->putFileInfo('/foo.txt', array('encrypted' => true)); |
||
188 | $cachedData = $rootView->getFileInfo('/foo.txt'); |
||
189 | $this->assertTrue($cachedData['encrypted']); |
||
190 | $this->assertEquals($cachedData['fileid'], $id); |
||
191 | |||
192 | $this->assertFalse($rootView->getFileInfo('/non/existing')); |
||
193 | $this->assertEquals(array(), $rootView->getDirectoryContent('/non/existing')); |
||
194 | } |
||
195 | |||
196 | /** |
||
197 | * @medium |
||
198 | */ |
||
199 | public function testGetPath() { |
||
221 | |||
222 | /** |
||
223 | * @medium |
||
224 | */ |
||
225 | View Code Duplication | public function testMountPointOverwrite() { |
|
226 | $storage1 = $this->getTestStorage(false); |
||
227 | $storage2 = $this->getTestStorage(); |
||
228 | $storage1->mkdir('substorage'); |
||
229 | \OC\Files\Filesystem::mount($storage1, array(), '/'); |
||
230 | \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); |
||
231 | |||
232 | $rootView = new \OC\Files\View(''); |
||
233 | $folderContent = $rootView->getDirectoryContent('/'); |
||
234 | $this->assertEquals(4, count($folderContent)); |
||
235 | } |
||
236 | |||
237 | public function sharingDisabledPermissionProvider() { |
||
238 | return [ |
||
239 | ['no', '', true], |
||
240 | ['yes', 'group1', false], |
||
241 | ]; |
||
242 | } |
||
243 | |||
244 | /** |
||
245 | * @dataProvider sharingDisabledPermissionProvider |
||
246 | */ |
||
247 | public function testRemoveSharePermissionWhenSharingDisabledForUser($excludeGroups, $excludeGroupsList, $expectedShareable) { |
||
248 | $appConfig = \OC::$server->getAppConfig(); |
||
249 | $oldExcludeGroupsFlag = $appConfig->getValue('core', 'shareapi_exclude_groups', 'no'); |
||
250 | $oldExcludeGroupsList = $appConfig->getValue('core', 'shareapi_exclude_groups_list', ''); |
||
251 | $appConfig->setValue('core', 'shareapi_exclude_groups', $excludeGroups); |
||
252 | $appConfig->setValue('core', 'shareapi_exclude_groups_list', $excludeGroupsList); |
||
253 | |||
254 | $storage1 = $this->getTestStorage(); |
||
255 | $storage2 = $this->getTestStorage(); |
||
256 | \OC\Files\Filesystem::mount($storage1, array(), '/'); |
||
257 | \OC\Files\Filesystem::mount($storage2, array(), '/mount'); |
||
258 | |||
259 | $view = new \OC\Files\View('/'); |
||
260 | |||
261 | $folderContent = $view->getDirectoryContent(''); |
||
262 | $this->assertEquals($expectedShareable, $folderContent[0]->isShareable()); |
||
263 | |||
264 | $folderContent = $view->getDirectoryContent('mount'); |
||
265 | $this->assertEquals($expectedShareable, $folderContent[0]->isShareable()); |
||
266 | |||
267 | $appConfig->setValue('core', 'shareapi_exclude_groups', $oldExcludeGroupsFlag); |
||
268 | $appConfig->setValue('core', 'shareapi_exclude_groups_list', $oldExcludeGroupsList); |
||
269 | } |
||
270 | |||
271 | View Code Duplication | public function testCacheIncompleteFolder() { |
|
272 | $storage1 = $this->getTestStorage(false); |
||
273 | \OC\Files\Filesystem::clearMounts(); |
||
274 | \OC\Files\Filesystem::mount($storage1, array(), '/incomplete'); |
||
275 | $rootView = new \OC\Files\View('/incomplete'); |
||
276 | |||
277 | $entries = $rootView->getDirectoryContent('/'); |
||
278 | $this->assertEquals(3, count($entries)); |
||
279 | |||
280 | // /folder will already be in the cache but not scanned |
||
281 | $entries = $rootView->getDirectoryContent('/folder'); |
||
282 | $this->assertEquals(1, count($entries)); |
||
283 | } |
||
284 | |||
285 | public function testAutoScan() { |
||
286 | $storage1 = $this->getTestStorage(false); |
||
287 | $storage2 = $this->getTestStorage(false); |
||
288 | \OC\Files\Filesystem::mount($storage1, array(), '/'); |
||
289 | \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); |
||
290 | $textSize = strlen("dummy file data\n"); |
||
291 | |||
292 | $rootView = new \OC\Files\View(''); |
||
293 | |||
294 | $cachedData = $rootView->getFileInfo('/'); |
||
295 | $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']); |
||
296 | $this->assertEquals(-1, $cachedData['size']); |
||
297 | |||
298 | $folderData = $rootView->getDirectoryContent('/substorage/folder'); |
||
299 | $this->assertEquals('text/plain', $folderData[0]['mimetype']); |
||
300 | $this->assertEquals($textSize, $folderData[0]['size']); |
||
301 | } |
||
302 | |||
303 | /** |
||
304 | * @medium |
||
305 | */ |
||
306 | public function testSearch() { |
||
307 | $storage1 = $this->getTestStorage(); |
||
308 | $storage2 = $this->getTestStorage(); |
||
309 | $storage3 = $this->getTestStorage(); |
||
310 | \OC\Files\Filesystem::mount($storage1, array(), '/'); |
||
311 | \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); |
||
312 | \OC\Files\Filesystem::mount($storage3, array(), '/folder/anotherstorage'); |
||
313 | |||
314 | $rootView = new \OC\Files\View(''); |
||
315 | |||
316 | $results = $rootView->search('foo'); |
||
317 | $this->assertEquals(6, count($results)); |
||
318 | $paths = array(); |
||
319 | foreach ($results as $result) { |
||
320 | $this->assertEquals($result['path'], \OC\Files\Filesystem::normalizePath($result['path'])); |
||
321 | $paths[] = $result['path']; |
||
322 | } |
||
323 | $this->assertContains('/foo.txt', $paths); |
||
324 | $this->assertContains('/foo.png', $paths); |
||
325 | $this->assertContains('/substorage/foo.txt', $paths); |
||
326 | $this->assertContains('/substorage/foo.png', $paths); |
||
327 | $this->assertContains('/folder/anotherstorage/foo.txt', $paths); |
||
328 | $this->assertContains('/folder/anotherstorage/foo.png', $paths); |
||
329 | |||
330 | $folderView = new \OC\Files\View('/folder'); |
||
331 | $results = $folderView->search('bar'); |
||
332 | $this->assertEquals(2, count($results)); |
||
333 | $paths = array(); |
||
334 | foreach ($results as $result) { |
||
335 | $paths[] = $result['path']; |
||
336 | } |
||
337 | $this->assertContains('/anotherstorage/folder/bar.txt', $paths); |
||
338 | $this->assertContains('/bar.txt', $paths); |
||
339 | |||
340 | $results = $folderView->search('foo'); |
||
341 | $this->assertEquals(2, count($results)); |
||
342 | $paths = array(); |
||
343 | foreach ($results as $result) { |
||
344 | $paths[] = $result['path']; |
||
345 | } |
||
346 | $this->assertContains('/anotherstorage/foo.txt', $paths); |
||
347 | $this->assertContains('/anotherstorage/foo.png', $paths); |
||
348 | |||
349 | $this->assertEquals(6, count($rootView->searchByMime('text'))); |
||
350 | $this->assertEquals(3, count($folderView->searchByMime('text'))); |
||
351 | } |
||
352 | |||
353 | /** |
||
354 | * @medium |
||
355 | */ |
||
356 | public function testWatcher() { |
||
357 | $storage1 = $this->getTestStorage(); |
||
358 | \OC\Files\Filesystem::mount($storage1, array(), '/'); |
||
359 | $storage1->getWatcher()->setPolicy(Watcher::CHECK_ALWAYS); |
||
360 | |||
361 | $rootView = new \OC\Files\View(''); |
||
362 | |||
363 | $cachedData = $rootView->getFileInfo('foo.txt'); |
||
364 | $this->assertEquals(16, $cachedData['size']); |
||
365 | |||
366 | $rootView->putFileInfo('foo.txt', array('storage_mtime' => 10)); |
||
367 | $storage1->file_put_contents('foo.txt', 'foo'); |
||
368 | clearstatcache(); |
||
369 | |||
370 | $cachedData = $rootView->getFileInfo('foo.txt'); |
||
371 | $this->assertEquals(3, $cachedData['size']); |
||
372 | } |
||
373 | |||
374 | /** |
||
375 | * @medium |
||
376 | */ |
||
377 | public function testCopyBetweenStorageNoCross() { |
||
378 | $storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoCross'); |
||
379 | $storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoCross'); |
||
380 | $this->copyBetweenStorages($storage1, $storage2); |
||
381 | } |
||
382 | |||
383 | /** |
||
384 | * @medium |
||
385 | */ |
||
386 | public function testCopyBetweenStorageCross() { |
||
387 | $storage1 = $this->getTestStorage(); |
||
388 | $storage2 = $this->getTestStorage(); |
||
389 | $this->copyBetweenStorages($storage1, $storage2); |
||
390 | } |
||
391 | |||
392 | /** |
||
393 | * @medium |
||
394 | */ |
||
395 | public function testCopyBetweenStorageCrossNonLocal() { |
||
396 | $storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal'); |
||
397 | $storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal'); |
||
398 | $this->copyBetweenStorages($storage1, $storage2); |
||
399 | } |
||
400 | |||
401 | function copyBetweenStorages($storage1, $storage2) { |
||
402 | \OC\Files\Filesystem::mount($storage1, array(), '/'); |
||
403 | \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); |
||
404 | |||
405 | $rootView = new \OC\Files\View(''); |
||
406 | $rootView->mkdir('substorage/emptyfolder'); |
||
407 | $rootView->copy('substorage', 'anotherfolder'); |
||
408 | $this->assertTrue($rootView->is_dir('/anotherfolder')); |
||
409 | $this->assertTrue($rootView->is_dir('/substorage')); |
||
410 | $this->assertTrue($rootView->is_dir('/anotherfolder/emptyfolder')); |
||
411 | $this->assertTrue($rootView->is_dir('/substorage/emptyfolder')); |
||
412 | $this->assertTrue($rootView->file_exists('/anotherfolder/foo.txt')); |
||
413 | $this->assertTrue($rootView->file_exists('/anotherfolder/foo.png')); |
||
414 | $this->assertTrue($rootView->file_exists('/anotherfolder/folder/bar.txt')); |
||
415 | $this->assertTrue($rootView->file_exists('/substorage/foo.txt')); |
||
416 | $this->assertTrue($rootView->file_exists('/substorage/foo.png')); |
||
417 | $this->assertTrue($rootView->file_exists('/substorage/folder/bar.txt')); |
||
418 | } |
||
419 | |||
420 | /** |
||
421 | * @medium |
||
422 | */ |
||
423 | public function testMoveBetweenStorageNoCross() { |
||
424 | $storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoCross'); |
||
425 | $storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoCross'); |
||
426 | $this->moveBetweenStorages($storage1, $storage2); |
||
427 | } |
||
428 | |||
429 | /** |
||
430 | * @medium |
||
431 | */ |
||
432 | public function testMoveBetweenStorageCross() { |
||
433 | $storage1 = $this->getTestStorage(); |
||
434 | $storage2 = $this->getTestStorage(); |
||
435 | $this->moveBetweenStorages($storage1, $storage2); |
||
436 | } |
||
437 | |||
438 | /** |
||
439 | * @medium |
||
440 | */ |
||
441 | public function testMoveBetweenStorageCrossNonLocal() { |
||
442 | $storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal'); |
||
443 | $storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal'); |
||
444 | $this->moveBetweenStorages($storage1, $storage2); |
||
445 | } |
||
446 | |||
447 | View Code Duplication | function moveBetweenStorages($storage1, $storage2) { |
|
448 | \OC\Files\Filesystem::mount($storage1, array(), '/'); |
||
449 | \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); |
||
450 | |||
451 | $rootView = new \OC\Files\View(''); |
||
452 | $rootView->rename('foo.txt', 'substorage/folder/foo.txt'); |
||
453 | $this->assertFalse($rootView->file_exists('foo.txt')); |
||
454 | $this->assertTrue($rootView->file_exists('substorage/folder/foo.txt')); |
||
455 | $rootView->rename('substorage/folder', 'anotherfolder'); |
||
456 | $this->assertFalse($rootView->is_dir('substorage/folder')); |
||
457 | $this->assertTrue($rootView->file_exists('anotherfolder/foo.txt')); |
||
458 | $this->assertTrue($rootView->file_exists('anotherfolder/bar.txt')); |
||
459 | } |
||
460 | |||
461 | /** |
||
462 | * @medium |
||
463 | */ |
||
464 | public function testUnlink() { |
||
465 | $storage1 = $this->getTestStorage(); |
||
466 | $storage2 = $this->getTestStorage(); |
||
467 | \OC\Files\Filesystem::mount($storage1, array(), '/'); |
||
468 | \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); |
||
469 | |||
470 | $rootView = new \OC\Files\View(''); |
||
471 | $rootView->file_put_contents('/foo.txt', 'asd'); |
||
472 | $rootView->file_put_contents('/substorage/bar.txt', 'asd'); |
||
473 | |||
474 | $this->assertTrue($rootView->file_exists('foo.txt')); |
||
475 | $this->assertTrue($rootView->file_exists('substorage/bar.txt')); |
||
476 | |||
477 | $this->assertTrue($rootView->unlink('foo.txt')); |
||
478 | $this->assertTrue($rootView->unlink('substorage/bar.txt')); |
||
479 | |||
480 | $this->assertFalse($rootView->file_exists('foo.txt')); |
||
481 | $this->assertFalse($rootView->file_exists('substorage/bar.txt')); |
||
482 | } |
||
483 | |||
484 | /** |
||
485 | * @medium |
||
486 | */ |
||
487 | View Code Duplication | public function testUnlinkRootMustFail() { |
|
488 | $storage1 = $this->getTestStorage(); |
||
489 | $storage2 = $this->getTestStorage(); |
||
490 | \OC\Files\Filesystem::mount($storage1, array(), '/'); |
||
491 | \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); |
||
492 | |||
493 | $rootView = new \OC\Files\View(''); |
||
494 | $rootView->file_put_contents('/foo.txt', 'asd'); |
||
495 | $rootView->file_put_contents('/substorage/bar.txt', 'asd'); |
||
496 | |||
497 | $this->assertFalse($rootView->unlink('')); |
||
498 | $this->assertFalse($rootView->unlink('/')); |
||
499 | $this->assertFalse($rootView->unlink('substorage')); |
||
500 | $this->assertFalse($rootView->unlink('/substorage')); |
||
501 | } |
||
502 | |||
503 | /** |
||
504 | * @medium |
||
505 | */ |
||
506 | public function testTouch() { |
||
507 | $storage = $this->getTestStorage(true, '\Test\Files\TemporaryNoTouch'); |
||
508 | |||
509 | \OC\Files\Filesystem::mount($storage, array(), '/'); |
||
510 | |||
511 | $rootView = new \OC\Files\View(''); |
||
512 | $oldCachedData = $rootView->getFileInfo('foo.txt'); |
||
513 | |||
514 | $rootView->touch('foo.txt', 500); |
||
515 | |||
516 | $cachedData = $rootView->getFileInfo('foo.txt'); |
||
517 | $this->assertEquals(500, $cachedData['mtime']); |
||
518 | $this->assertEquals($oldCachedData['storage_mtime'], $cachedData['storage_mtime']); |
||
519 | |||
520 | $rootView->putFileInfo('foo.txt', array('storage_mtime' => 1000)); //make sure the watcher detects the change |
||
521 | $rootView->file_put_contents('foo.txt', 'asd'); |
||
522 | $cachedData = $rootView->getFileInfo('foo.txt'); |
||
523 | $this->assertGreaterThanOrEqual($oldCachedData['mtime'], $cachedData['mtime']); |
||
524 | $this->assertEquals($cachedData['storage_mtime'], $cachedData['mtime']); |
||
525 | } |
||
526 | |||
527 | /** |
||
528 | * @medium |
||
529 | */ |
||
530 | public function testViewHooks() { |
||
531 | $storage1 = $this->getTestStorage(); |
||
532 | $storage2 = $this->getTestStorage(); |
||
533 | $defaultRoot = \OC\Files\Filesystem::getRoot(); |
||
534 | \OC\Files\Filesystem::mount($storage1, array(), '/'); |
||
535 | \OC\Files\Filesystem::mount($storage2, array(), $defaultRoot . '/substorage'); |
||
536 | \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook'); |
||
537 | |||
538 | $rootView = new \OC\Files\View(''); |
||
539 | $subView = new \OC\Files\View($defaultRoot . '/substorage'); |
||
540 | $this->hookPath = null; |
||
541 | |||
542 | $rootView->file_put_contents('/foo.txt', 'asd'); |
||
543 | $this->assertNull($this->hookPath); |
||
544 | |||
545 | $subView->file_put_contents('/foo.txt', 'asd'); |
||
546 | $this->assertEquals('/substorage/foo.txt', $this->hookPath); |
||
547 | } |
||
548 | |||
549 | private $hookPath; |
||
550 | |||
551 | public function dummyHook($params) { |
||
554 | |||
555 | public function testSearchNotOutsideView() { |
||
556 | $storage1 = $this->getTestStorage(); |
||
557 | \OC\Files\Filesystem::mount($storage1, array(), '/'); |
||
558 | $storage1->rename('folder', 'foo'); |
||
559 | $scanner = $storage1->getScanner(); |
||
560 | $scanner->scan(''); |
||
561 | |||
562 | $view = new \OC\Files\View('/foo'); |
||
563 | |||
564 | $result = $view->search('.txt'); |
||
565 | $this->assertCount(1, $result); |
||
566 | } |
||
567 | |||
568 | /** |
||
569 | * @param bool $scan |
||
570 | * @param string $class |
||
571 | * @return \OC\Files\Storage\Storage |
||
572 | */ |
||
573 | View Code Duplication | private function getTestStorage($scan = true, $class = '\OC\Files\Storage\Temporary') { |
|
574 | /** |
||
575 | * @var \OC\Files\Storage\Storage $storage |
||
576 | */ |
||
577 | $storage = new $class(array()); |
||
578 | $textData = "dummy file data\n"; |
||
579 | $imgData = file_get_contents(\OC::$SERVERROOT . '/core/img/logo.png'); |
||
580 | $storage->mkdir('folder'); |
||
581 | $storage->file_put_contents('foo.txt', $textData); |
||
582 | $storage->file_put_contents('foo.png', $imgData); |
||
583 | $storage->file_put_contents('folder/bar.txt', $textData); |
||
584 | |||
585 | if ($scan) { |
||
586 | $scanner = $storage->getScanner(); |
||
587 | $scanner->scan(''); |
||
588 | } |
||
589 | $this->storages[] = $storage; |
||
590 | return $storage; |
||
591 | } |
||
592 | |||
593 | /** |
||
594 | * @medium |
||
595 | */ |
||
596 | public function testViewHooksIfRootStartsTheSame() { |
||
597 | $storage1 = $this->getTestStorage(); |
||
598 | $storage2 = $this->getTestStorage(); |
||
599 | $defaultRoot = \OC\Files\Filesystem::getRoot(); |
||
600 | \OC\Files\Filesystem::mount($storage1, array(), '/'); |
||
601 | \OC\Files\Filesystem::mount($storage2, array(), $defaultRoot . '_substorage'); |
||
602 | \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook'); |
||
603 | |||
604 | $subView = new \OC\Files\View($defaultRoot . '_substorage'); |
||
605 | $this->hookPath = null; |
||
606 | |||
607 | $subView->file_put_contents('/foo.txt', 'asd'); |
||
608 | $this->assertNull($this->hookPath); |
||
609 | } |
||
610 | |||
611 | private $hookWritePath; |
||
612 | private $hookCreatePath; |
||
613 | private $hookUpdatePath; |
||
614 | |||
615 | public function dummyHookWrite($params) { |
||
618 | |||
619 | public function dummyHookUpdate($params) { |
||
622 | |||
623 | public function dummyHookCreate($params) { |
||
626 | |||
627 | public function testEditNoCreateHook() { |
||
628 | $storage1 = $this->getTestStorage(); |
||
629 | $storage2 = $this->getTestStorage(); |
||
630 | $defaultRoot = \OC\Files\Filesystem::getRoot(); |
||
631 | \OC\Files\Filesystem::mount($storage1, array(), '/'); |
||
632 | \OC\Files\Filesystem::mount($storage2, array(), $defaultRoot); |
||
633 | \OC_Hook::connect('OC_Filesystem', 'post_create', $this, 'dummyHookCreate'); |
||
634 | \OC_Hook::connect('OC_Filesystem', 'post_update', $this, 'dummyHookUpdate'); |
||
635 | \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHookWrite'); |
||
636 | |||
637 | $view = new \OC\Files\View($defaultRoot); |
||
638 | $this->hookWritePath = $this->hookUpdatePath = $this->hookCreatePath = null; |
||
639 | |||
640 | $view->file_put_contents('/asd.txt', 'foo'); |
||
641 | $this->assertEquals('/asd.txt', $this->hookCreatePath); |
||
642 | $this->assertNull($this->hookUpdatePath); |
||
643 | $this->assertEquals('/asd.txt', $this->hookWritePath); |
||
644 | |||
645 | $this->hookWritePath = $this->hookUpdatePath = $this->hookCreatePath = null; |
||
646 | |||
647 | $view->file_put_contents('/asd.txt', 'foo'); |
||
648 | $this->assertNull($this->hookCreatePath); |
||
649 | $this->assertEquals('/asd.txt', $this->hookUpdatePath); |
||
650 | $this->assertEquals('/asd.txt', $this->hookWritePath); |
||
651 | |||
652 | \OC_Hook::clear('OC_Filesystem', 'post_create'); |
||
653 | \OC_Hook::clear('OC_Filesystem', 'post_update'); |
||
654 | \OC_Hook::clear('OC_Filesystem', 'post_write'); |
||
655 | } |
||
656 | |||
657 | /** |
||
658 | * @dataProvider resolvePathTestProvider |
||
659 | */ |
||
660 | public function testResolvePath($expected, $pathToTest) { |
||
661 | $storage1 = $this->getTestStorage(); |
||
662 | \OC\Files\Filesystem::mount($storage1, array(), '/'); |
||
663 | |||
664 | $view = new \OC\Files\View(''); |
||
665 | |||
666 | $result = $view->resolvePath($pathToTest); |
||
667 | $this->assertEquals($expected, $result[1]); |
||
668 | |||
669 | $exists = $view->file_exists($pathToTest); |
||
670 | $this->assertTrue($exists); |
||
671 | |||
672 | $exists = $view->file_exists($result[1]); |
||
673 | $this->assertTrue($exists); |
||
674 | } |
||
675 | |||
676 | function resolvePathTestProvider() { |
||
677 | return array( |
||
678 | array('foo.txt', 'foo.txt'), |
||
679 | array('foo.txt', '/foo.txt'), |
||
680 | array('folder', 'folder'), |
||
681 | array('folder', '/folder'), |
||
682 | array('folder', 'folder/'), |
||
683 | array('folder', '/folder/'), |
||
684 | array('folder/bar.txt', 'folder/bar.txt'), |
||
685 | array('folder/bar.txt', '/folder/bar.txt'), |
||
686 | array('', ''), |
||
687 | array('', '/'), |
||
688 | ); |
||
689 | } |
||
690 | |||
691 | public function testUTF8Names() { |
||
692 | $names = array('虚', '和知しゃ和で', 'regular ascii', 'sɨˈrɪlɪk', 'ѨѬ', 'أنا أحب القراءة كثيرا'); |
||
693 | |||
694 | $storage = new \OC\Files\Storage\Temporary(array()); |
||
695 | \OC\Files\Filesystem::mount($storage, array(), '/'); |
||
696 | |||
697 | $rootView = new \OC\Files\View(''); |
||
698 | foreach ($names as $name) { |
||
699 | $rootView->file_put_contents('/' . $name, 'dummy content'); |
||
700 | } |
||
701 | |||
702 | $list = $rootView->getDirectoryContent('/'); |
||
703 | |||
704 | $this->assertCount(count($names), $list); |
||
705 | foreach ($list as $item) { |
||
706 | $this->assertContains($item['name'], $names); |
||
707 | } |
||
708 | |||
709 | $cache = $storage->getCache(); |
||
710 | $scanner = $storage->getScanner(); |
||
711 | $scanner->scan(''); |
||
712 | |||
713 | $list = $cache->getFolderContents(''); |
||
714 | |||
715 | $this->assertCount(count($names), $list); |
||
716 | foreach ($list as $item) { |
||
717 | $this->assertContains($item['name'], $names); |
||
718 | } |
||
719 | } |
||
720 | |||
721 | public function xtestLongPath() { |
||
722 | |||
723 | $storage = new \OC\Files\Storage\Temporary(array()); |
||
724 | \OC\Files\Filesystem::mount($storage, array(), '/'); |
||
725 | |||
726 | $rootView = new \OC\Files\View(''); |
||
727 | |||
728 | $longPath = ''; |
||
729 | $ds = DIRECTORY_SEPARATOR; |
||
730 | /* |
||
731 | * 4096 is the maximum path length in file_cache.path in *nix |
||
732 | * 1024 is the max path length in mac |
||
733 | * 228 is the max path length in windows |
||
734 | */ |
||
735 | $folderName = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789'; |
||
736 | $tmpdirLength = strlen(\OC_Helper::tmpFolder()); |
||
737 | if (\OC_Util::runningOnWindows()) { |
||
738 | $this->markTestSkipped('[Windows] '); |
||
739 | $depth = ((260 - $tmpdirLength) / 57); |
||
740 | } elseif (\OC_Util::runningOnMac()) { |
||
741 | $depth = ((1024 - $tmpdirLength) / 57); |
||
742 | } else { |
||
743 | $depth = ((4000 - $tmpdirLength) / 57); |
||
744 | } |
||
745 | foreach (range(0, $depth - 1) as $i) { |
||
746 | $longPath .= $ds . $folderName; |
||
747 | $result = $rootView->mkdir($longPath); |
||
748 | $this->assertTrue($result, "mkdir failed on $i - path length: " . strlen($longPath)); |
||
749 | |||
750 | $result = $rootView->file_put_contents($longPath . "{$ds}test.txt", 'lorem'); |
||
751 | $this->assertEquals(5, $result, "file_put_contents failed on $i"); |
||
752 | |||
753 | $this->assertTrue($rootView->file_exists($longPath)); |
||
754 | $this->assertTrue($rootView->file_exists($longPath . "{$ds}test.txt")); |
||
755 | } |
||
756 | |||
757 | $cache = $storage->getCache(); |
||
758 | $scanner = $storage->getScanner(); |
||
759 | $scanner->scan(''); |
||
760 | |||
761 | $longPath = $folderName; |
||
762 | foreach (range(0, $depth - 1) as $i) { |
||
763 | $cachedFolder = $cache->get($longPath); |
||
764 | $this->assertTrue(is_array($cachedFolder), "No cache entry for folder at $i"); |
||
765 | $this->assertEquals($folderName, $cachedFolder['name'], "Wrong cache entry for folder at $i"); |
||
766 | |||
767 | $cachedFile = $cache->get($longPath . '/test.txt'); |
||
768 | $this->assertTrue(is_array($cachedFile), "No cache entry for file at $i"); |
||
769 | $this->assertEquals('test.txt', $cachedFile['name'], "Wrong cache entry for file at $i"); |
||
770 | |||
771 | $longPath .= $ds . $folderName; |
||
772 | } |
||
773 | } |
||
774 | |||
775 | public function testTouchNotSupported() { |
||
776 | $storage = new TemporaryNoTouch(array()); |
||
777 | $scanner = $storage->getScanner(); |
||
778 | \OC\Files\Filesystem::mount($storage, array(), '/test/'); |
||
779 | $past = time() - 100; |
||
780 | $storage->file_put_contents('test', 'foobar'); |
||
781 | $scanner->scan(''); |
||
782 | $view = new \OC\Files\View(''); |
||
783 | $info = $view->getFileInfo('/test/test'); |
||
784 | |||
785 | $view->touch('/test/test', $past); |
||
786 | $scanner->scanFile('test', \OC\Files\Cache\Scanner::REUSE_ETAG); |
||
787 | |||
788 | $info2 = $view->getFileInfo('/test/test'); |
||
789 | $this->assertSame($info['etag'], $info2['etag']); |
||
790 | } |
||
791 | |||
792 | public function testWatcherEtagCrossStorage() { |
||
793 | $storage1 = new Temporary(array()); |
||
794 | $storage2 = new Temporary(array()); |
||
795 | $scanner1 = $storage1->getScanner(); |
||
796 | $scanner2 = $storage2->getScanner(); |
||
797 | $storage1->mkdir('sub'); |
||
798 | \OC\Files\Filesystem::mount($storage1, array(), '/test/'); |
||
799 | \OC\Files\Filesystem::mount($storage2, array(), '/test/sub/storage'); |
||
800 | |||
801 | $past = time() - 100; |
||
802 | $storage2->file_put_contents('test.txt', 'foobar'); |
||
803 | $scanner1->scan(''); |
||
804 | $scanner2->scan(''); |
||
805 | $view = new \OC\Files\View(''); |
||
806 | |||
807 | $storage2->getWatcher('')->setPolicy(Watcher::CHECK_ALWAYS); |
||
808 | |||
809 | $oldFileInfo = $view->getFileInfo('/test/sub/storage/test.txt'); |
||
810 | $oldFolderInfo = $view->getFileInfo('/test'); |
||
811 | |||
812 | $storage2->getCache()->update($oldFileInfo->getId(), array( |
||
813 | 'storage_mtime' => $past |
||
814 | )); |
||
815 | |||
816 | $view->getFileInfo('/test/sub/storage/test.txt'); |
||
817 | $newFolderInfo = $view->getFileInfo('/test'); |
||
818 | |||
819 | $this->assertNotEquals($newFolderInfo->getEtag(), $oldFolderInfo->getEtag()); |
||
820 | } |
||
821 | |||
822 | /** |
||
823 | * @dataProvider absolutePathProvider |
||
824 | */ |
||
825 | public function testGetAbsolutePath($expectedPath, $relativePath) { |
||
829 | |||
830 | public function testPartFileInfo() { |
||
831 | $storage = new Temporary(array()); |
||
832 | $scanner = $storage->getScanner(); |
||
833 | \OC\Files\Filesystem::mount($storage, array(), '/test/'); |
||
834 | $storage->file_put_contents('test.part', 'foobar'); |
||
835 | $scanner->scan(''); |
||
836 | $view = new \OC\Files\View('/test'); |
||
837 | $info = $view->getFileInfo('test.part'); |
||
838 | |||
839 | $this->assertInstanceOf('\OCP\Files\FileInfo', $info); |
||
840 | $this->assertNull($info->getId()); |
||
841 | $this->assertEquals(6, $info->getSize()); |
||
842 | } |
||
843 | |||
844 | function absolutePathProvider() { |
||
845 | return array( |
||
846 | array('/files/', ''), |
||
847 | array('/files/0', '0'), |
||
848 | array('/files/false', 'false'), |
||
849 | array('/files/true', 'true'), |
||
850 | array('/files/', '/'), |
||
851 | array('/files/test', 'test'), |
||
852 | array('/files/test', '/test'), |
||
853 | ); |
||
854 | } |
||
855 | |||
856 | /** |
||
857 | * @dataProvider chrootRelativePathProvider |
||
858 | */ |
||
859 | function testChrootGetRelativePath($root, $absolutePath, $expectedPath) { |
||
860 | $view = new \OC\Files\View('/files'); |
||
861 | $view->chroot($root); |
||
862 | $this->assertEquals($expectedPath, $view->getRelativePath($absolutePath)); |
||
863 | } |
||
864 | |||
865 | public function chrootRelativePathProvider() { |
||
868 | |||
869 | /** |
||
870 | * @dataProvider initRelativePathProvider |
||
871 | */ |
||
872 | public function testInitGetRelativePath($root, $absolutePath, $expectedPath) { |
||
876 | |||
877 | public function initRelativePathProvider() { |
||
880 | |||
881 | public function relativePathProvider($missingRootExpectedPath) { |
||
882 | return array( |
||
883 | // No root - returns the path |
||
884 | array('', '/files', '/files'), |
||
885 | array('', '/files/', '/files/'), |
||
886 | |||
887 | // Root equals path - / |
||
888 | array('/files/', '/files/', '/'), |
||
889 | array('/files/', '/files', '/'), |
||
890 | array('/files', '/files/', '/'), |
||
891 | array('/files', '/files', '/'), |
||
892 | |||
893 | // False negatives: chroot fixes those by adding the leading slash. |
||
894 | // But setting them up with this root (instead of chroot($root)) |
||
895 | // will fail them, although they should be the same. |
||
896 | // TODO init should be fixed, so it also adds the leading slash |
||
897 | array('files/', '/files/', $missingRootExpectedPath), |
||
898 | array('files', '/files/', $missingRootExpectedPath), |
||
899 | array('files/', '/files', $missingRootExpectedPath), |
||
900 | array('files', '/files', $missingRootExpectedPath), |
||
901 | |||
902 | // False negatives: Paths provided to the method should have a leading slash |
||
903 | // TODO input should be checked to have a leading slash |
||
904 | array('/files/', 'files/', null), |
||
905 | array('/files', 'files/', null), |
||
906 | array('/files/', 'files', null), |
||
907 | array('/files', 'files', null), |
||
908 | |||
909 | // with trailing slashes |
||
910 | array('/files/', '/files/0', '0'), |
||
911 | array('/files/', '/files/false', 'false'), |
||
912 | array('/files/', '/files/true', 'true'), |
||
913 | array('/files/', '/files/test', 'test'), |
||
914 | array('/files/', '/files/test/foo', 'test/foo'), |
||
915 | |||
916 | // without trailing slashes |
||
917 | // TODO false expectation: Should match "with trailing slashes" |
||
918 | array('/files', '/files/0', '/0'), |
||
919 | array('/files', '/files/false', '/false'), |
||
920 | array('/files', '/files/true', '/true'), |
||
921 | array('/files', '/files/test', '/test'), |
||
922 | array('/files', '/files/test/foo', '/test/foo'), |
||
923 | |||
924 | // leading slashes |
||
925 | array('/files/', '/files_trashbin/', null), |
||
926 | array('/files', '/files_trashbin/', null), |
||
927 | array('/files/', '/files_trashbin', null), |
||
928 | array('/files', '/files_trashbin', null), |
||
929 | |||
930 | // no leading slashes |
||
931 | array('files/', 'files_trashbin/', null), |
||
932 | array('files', 'files_trashbin/', null), |
||
933 | array('files/', 'files_trashbin', null), |
||
934 | array('files', 'files_trashbin', null), |
||
935 | |||
936 | // mixed leading slashes |
||
937 | array('files/', '/files_trashbin/', null), |
||
938 | array('/files/', 'files_trashbin/', null), |
||
939 | array('files', '/files_trashbin/', null), |
||
940 | array('/files', 'files_trashbin/', null), |
||
941 | array('files/', '/files_trashbin', null), |
||
942 | array('/files/', 'files_trashbin', null), |
||
943 | array('files', '/files_trashbin', null), |
||
944 | array('/files', 'files_trashbin', null), |
||
945 | |||
946 | array('files', 'files_trashbin/test', null), |
||
947 | array('/files', '/files_trashbin/test', null), |
||
948 | array('/files', 'files_trashbin/test', null), |
||
949 | ); |
||
950 | } |
||
951 | |||
952 | public function testFileView() { |
||
953 | $storage = new Temporary(array()); |
||
954 | $scanner = $storage->getScanner(); |
||
955 | $storage->file_put_contents('foo.txt', 'bar'); |
||
956 | \OC\Files\Filesystem::mount($storage, array(), '/test/'); |
||
957 | $scanner->scan(''); |
||
958 | $view = new \OC\Files\View('/test/foo.txt'); |
||
959 | |||
960 | $this->assertEquals('bar', $view->file_get_contents('')); |
||
961 | $fh = tmpfile(); |
||
962 | fwrite($fh, 'foo'); |
||
963 | rewind($fh); |
||
964 | $view->file_put_contents('', $fh); |
||
965 | $this->assertEquals('foo', $view->file_get_contents('')); |
||
966 | } |
||
967 | |||
968 | /** |
||
969 | * @dataProvider tooLongPathDataProvider |
||
970 | * @expectedException \OCP\Files\InvalidPathException |
||
971 | */ |
||
972 | public function testTooLongPath($operation, $param0 = null) { |
||
973 | |||
974 | $longPath = ''; |
||
975 | // 4000 is the maximum path length in file_cache.path |
||
976 | $folderName = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789'; |
||
977 | $depth = (4000 / 57); |
||
978 | foreach (range(0, $depth + 1) as $i) { |
||
979 | $longPath .= '/' . $folderName; |
||
980 | } |
||
981 | |||
982 | $storage = new \OC\Files\Storage\Temporary(array()); |
||
983 | $this->tempStorage = $storage; // for later hard cleanup |
||
984 | \OC\Files\Filesystem::mount($storage, array(), '/'); |
||
985 | |||
986 | $rootView = new \OC\Files\View(''); |
||
987 | |||
988 | if ($param0 === '@0') { |
||
989 | $param0 = $longPath; |
||
990 | } |
||
991 | |||
992 | if ($operation === 'hash') { |
||
993 | $param0 = $longPath; |
||
994 | $longPath = 'md5'; |
||
995 | } |
||
996 | |||
997 | call_user_func(array($rootView, $operation), $longPath, $param0); |
||
998 | } |
||
999 | |||
1000 | public function tooLongPathDataProvider() { |
||
1001 | return array( |
||
1002 | array('getAbsolutePath'), |
||
1003 | array('getRelativePath'), |
||
1004 | array('getMountPoint'), |
||
1005 | array('resolvePath'), |
||
1006 | array('getLocalFile'), |
||
1007 | array('getLocalFolder'), |
||
1008 | array('mkdir'), |
||
1009 | array('rmdir'), |
||
1010 | array('opendir'), |
||
1011 | array('is_dir'), |
||
1012 | array('is_file'), |
||
1013 | array('stat'), |
||
1014 | array('filetype'), |
||
1015 | array('filesize'), |
||
1016 | array('readfile'), |
||
1017 | array('isCreatable'), |
||
1018 | array('isReadable'), |
||
1019 | array('isUpdatable'), |
||
1020 | array('isDeletable'), |
||
1021 | array('isSharable'), |
||
1022 | array('file_exists'), |
||
1023 | array('filemtime'), |
||
1024 | array('touch'), |
||
1025 | array('file_get_contents'), |
||
1026 | array('unlink'), |
||
1027 | array('deleteAll'), |
||
1028 | array('toTmpFile'), |
||
1029 | array('getMimeType'), |
||
1030 | array('free_space'), |
||
1031 | array('getFileInfo'), |
||
1032 | array('getDirectoryContent'), |
||
1033 | array('getOwner'), |
||
1034 | array('getETag'), |
||
1035 | array('file_put_contents', 'ipsum'), |
||
1036 | array('rename', '@0'), |
||
1037 | array('copy', '@0'), |
||
1038 | array('fopen', 'r'), |
||
1039 | array('fromTmpFile', '@0'), |
||
1040 | array('hash'), |
||
1041 | array('hasUpdated', 0), |
||
1042 | array('putFileInfo', array()), |
||
1043 | ); |
||
1044 | } |
||
1045 | |||
1046 | public function testRenameCrossStoragePreserveMtime() { |
||
1047 | $storage1 = new Temporary(array()); |
||
1048 | $storage2 = new Temporary(array()); |
||
1049 | $scanner1 = $storage1->getScanner(); |
||
1050 | $scanner2 = $storage2->getScanner(); |
||
1051 | $storage1->mkdir('sub'); |
||
1052 | $storage1->mkdir('foo'); |
||
1053 | $storage1->file_put_contents('foo.txt', 'asd'); |
||
1054 | $storage1->file_put_contents('foo/bar.txt', 'asd'); |
||
1055 | \OC\Files\Filesystem::mount($storage1, array(), '/test/'); |
||
1056 | \OC\Files\Filesystem::mount($storage2, array(), '/test/sub/storage'); |
||
1057 | |||
1058 | $view = new \OC\Files\View(''); |
||
1059 | $time = time() - 200; |
||
1060 | $view->touch('/test/foo.txt', $time); |
||
1061 | $view->touch('/test/foo', $time); |
||
1062 | $view->touch('/test/foo/bar.txt', $time); |
||
1063 | |||
1064 | $view->rename('/test/foo.txt', '/test/sub/storage/foo.txt'); |
||
1065 | |||
1066 | $this->assertEquals($time, $view->filemtime('/test/sub/storage/foo.txt')); |
||
1067 | |||
1068 | $view->rename('/test/foo', '/test/sub/storage/foo'); |
||
1069 | |||
1070 | $this->assertEquals($time, $view->filemtime('/test/sub/storage/foo/bar.txt')); |
||
1071 | } |
||
1072 | |||
1073 | public function testRenameFailDeleteTargetKeepSource() { |
||
1076 | |||
1077 | public function testCopyFailDeleteTargetKeepSource() { |
||
1080 | |||
1081 | private function doTestCopyRenameFail($operation) { |
||
1082 | $storage1 = new Temporary(array()); |
||
1083 | /** @var \PHPUnit_Framework_MockObject_MockObject | \OC\Files\Storage\Temporary $storage2 */ |
||
1084 | $storage2 = $this->getMockBuilder('\Test\Files\TemporaryNoCross') |
||
1085 | ->setConstructorArgs([[]]) |
||
1086 | ->setMethods(['fopen']) |
||
1087 | ->getMock(); |
||
1088 | |||
1089 | $storage2->expects($this->any()) |
||
1090 | ->method('fopen') |
||
1091 | ->will($this->returnCallback(function ($path, $mode) use ($storage2) { |
||
1092 | /** @var \PHPUnit_Framework_MockObject_MockObject | \OC\Files\Storage\Temporary $storage2 */ |
||
1093 | $source = fopen($storage2->getSourcePath($path), $mode); |
||
1094 | return \OC\Files\Stream\Quota::wrap($source, 9); |
||
1095 | })); |
||
1096 | |||
1097 | $storage1->mkdir('sub'); |
||
1098 | $storage1->file_put_contents('foo.txt', '0123456789ABCDEFGH'); |
||
1099 | $storage1->mkdir('dirtomove'); |
||
1100 | $storage1->file_put_contents('dirtomove/indir1.txt', '0123456'); // fits |
||
1101 | $storage1->file_put_contents('dirtomove/indir2.txt', '0123456789ABCDEFGH'); // doesn't fit |
||
1102 | $storage2->file_put_contents('existing.txt', '0123'); |
||
1103 | $storage1->getScanner()->scan(''); |
||
1104 | $storage2->getScanner()->scan(''); |
||
1105 | \OC\Files\Filesystem::mount($storage1, array(), '/test/'); |
||
1106 | \OC\Files\Filesystem::mount($storage2, array(), '/test/sub/storage'); |
||
1107 | |||
1108 | // move file |
||
1109 | $view = new \OC\Files\View(''); |
||
1110 | $this->assertTrue($storage1->file_exists('foo.txt')); |
||
1111 | $this->assertFalse($storage2->file_exists('foo.txt')); |
||
1112 | $this->assertFalse($view->$operation('/test/foo.txt', '/test/sub/storage/foo.txt')); |
||
1113 | $this->assertFalse($storage2->file_exists('foo.txt')); |
||
1114 | $this->assertFalse($storage2->getCache()->get('foo.txt')); |
||
1115 | $this->assertTrue($storage1->file_exists('foo.txt')); |
||
1116 | |||
1117 | // if target exists, it will be deleted too |
||
1118 | $this->assertFalse($view->$operation('/test/foo.txt', '/test/sub/storage/existing.txt')); |
||
1119 | $this->assertFalse($storage2->file_exists('existing.txt')); |
||
1120 | $this->assertFalse($storage2->getCache()->get('existing.txt')); |
||
1121 | $this->assertTrue($storage1->file_exists('foo.txt')); |
||
1122 | |||
1123 | // move folder |
||
1124 | $this->assertFalse($view->$operation('/test/dirtomove/', '/test/sub/storage/dirtomove/')); |
||
1125 | // since the move failed, the full source tree is kept |
||
1126 | $this->assertTrue($storage1->file_exists('dirtomove/indir1.txt')); |
||
1127 | $this->assertTrue($storage1->file_exists('dirtomove/indir2.txt')); |
||
1128 | // second file not moved/copied |
||
1129 | $this->assertFalse($storage2->file_exists('dirtomove/indir2.txt')); |
||
1130 | $this->assertFalse($storage2->getCache()->get('dirtomove/indir2.txt')); |
||
1131 | |||
1132 | } |
||
1133 | |||
1134 | public function testDeleteFailKeepCache() { |
||
1156 | |||
1157 | function directoryTraversalProvider() { |
||
1158 | return [ |
||
1159 | ['../test/'], |
||
1160 | ['..\\test\\my/../folder'], |
||
1161 | ['/test/my/../foo\\'], |
||
1162 | ]; |
||
1163 | } |
||
1164 | |||
1165 | /** |
||
1166 | * @dataProvider directoryTraversalProvider |
||
1167 | * @expectedException \Exception |
||
1168 | * @param string $root |
||
1169 | */ |
||
1170 | public function testConstructDirectoryTraversalException($root) { |
||
1173 | |||
1174 | public function testRenameOverWrite() { |
||
1175 | $storage = new Temporary(array()); |
||
1176 | $scanner = $storage->getScanner(); |
||
1177 | $storage->mkdir('sub'); |
||
1178 | $storage->mkdir('foo'); |
||
1179 | $storage->file_put_contents('foo.txt', 'asd'); |
||
1180 | $storage->file_put_contents('foo/bar.txt', 'asd'); |
||
1181 | $scanner->scan(''); |
||
1182 | \OC\Files\Filesystem::mount($storage, array(), '/test/'); |
||
1183 | $view = new \OC\Files\View(''); |
||
1184 | $this->assertTrue($view->rename('/test/foo.txt', '/test/foo/bar.txt')); |
||
1185 | } |
||
1186 | |||
1187 | public function testSetMountOptionsInStorage() { |
||
1188 | $mount = new MountPoint('\OC\Files\Storage\Temporary', '/asd/', [[]], \OC\Files\Filesystem::getLoader(), ['foo' => 'bar']); |
||
1189 | \OC\Files\Filesystem::getMountManager()->addMount($mount); |
||
1190 | /** @var \OC\Files\Storage\Common $storage */ |
||
1191 | $storage = $mount->getStorage(); |
||
1192 | $this->assertEquals($storage->getMountOption('foo'), 'bar'); |
||
1193 | } |
||
1194 | |||
1195 | public function testSetMountOptionsWatcherPolicy() { |
||
1196 | $mount = new MountPoint('\OC\Files\Storage\Temporary', '/asd/', [[]], \OC\Files\Filesystem::getLoader(), ['filesystem_check_changes' => Watcher::CHECK_NEVER]); |
||
1197 | \OC\Files\Filesystem::getMountManager()->addMount($mount); |
||
1198 | /** @var \OC\Files\Storage\Common $storage */ |
||
1199 | $storage = $mount->getStorage(); |
||
1200 | $watcher = $storage->getWatcher(); |
||
1201 | $this->assertEquals(Watcher::CHECK_NEVER, $watcher->getPolicy()); |
||
1202 | } |
||
1203 | |||
1204 | public function testGetAbsolutePathOnNull() { |
||
1208 | |||
1209 | public function testGetRelativePathOnNull() { |
||
1213 | |||
1214 | /** |
||
1215 | * @expectedException \InvalidArgumentException |
||
1216 | */ |
||
1217 | public function testNullAsRoot() { |
||
1220 | |||
1221 | /** |
||
1222 | * e.g. reading from a folder that's being renamed |
||
1223 | * |
||
1224 | * @expectedException \OCP\Lock\LockedException |
||
1225 | * |
||
1226 | * @dataProvider dataLockPaths |
||
1227 | * |
||
1228 | * @param string $rootPath |
||
1229 | * @param string $pathPrefix |
||
1230 | */ |
||
1231 | View Code Duplication | public function testReadFromWriteLockedPath($rootPath, $pathPrefix) { |
|
1232 | $rootPath = str_replace('{folder}', 'files', $rootPath); |
||
1233 | $pathPrefix = str_replace('{folder}', 'files', $pathPrefix); |
||
1234 | |||
1235 | $view = new \OC\Files\View($rootPath); |
||
1236 | $storage = new Temporary(array()); |
||
1237 | \OC\Files\Filesystem::mount($storage, [], '/'); |
||
1238 | $this->assertTrue($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE)); |
||
1239 | $view->lockFile($pathPrefix . '/foo/bar/asd', ILockingProvider::LOCK_SHARED); |
||
1240 | } |
||
1241 | |||
1242 | /** |
||
1243 | * Reading from a files_encryption folder that's being renamed |
||
1244 | * |
||
1245 | * @dataProvider dataLockPaths |
||
1246 | * |
||
1247 | * @param string $rootPath |
||
1248 | * @param string $pathPrefix |
||
1249 | */ |
||
1250 | View Code Duplication | public function testReadFromWriteUnlockablePath($rootPath, $pathPrefix) { |
|
1251 | $rootPath = str_replace('{folder}', 'files_encryption', $rootPath); |
||
1252 | $pathPrefix = str_replace('{folder}', 'files_encryption', $pathPrefix); |
||
1253 | |||
1254 | $view = new \OC\Files\View($rootPath); |
||
1255 | $storage = new Temporary(array()); |
||
1256 | \OC\Files\Filesystem::mount($storage, [], '/'); |
||
1257 | $this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE)); |
||
1258 | $this->assertFalse($view->lockFile($pathPrefix . '/foo/bar/asd', ILockingProvider::LOCK_SHARED)); |
||
1259 | } |
||
1260 | |||
1261 | /** |
||
1262 | * e.g. writing a file that's being downloaded |
||
1263 | * |
||
1264 | * @expectedException \OCP\Lock\LockedException |
||
1265 | * |
||
1266 | * @dataProvider dataLockPaths |
||
1267 | * |
||
1268 | * @param string $rootPath |
||
1269 | * @param string $pathPrefix |
||
1270 | */ |
||
1271 | View Code Duplication | public function testWriteToReadLockedFile($rootPath, $pathPrefix) { |
|
1272 | $rootPath = str_replace('{folder}', 'files', $rootPath); |
||
1273 | $pathPrefix = str_replace('{folder}', 'files', $pathPrefix); |
||
1274 | |||
1275 | $view = new \OC\Files\View($rootPath); |
||
1276 | $storage = new Temporary(array()); |
||
1277 | \OC\Files\Filesystem::mount($storage, [], '/'); |
||
1278 | $this->assertTrue($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_SHARED)); |
||
1279 | $view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE); |
||
1280 | } |
||
1281 | |||
1282 | /** |
||
1283 | * Writing a file that's being downloaded |
||
1284 | * |
||
1285 | * @dataProvider dataLockPaths |
||
1286 | * |
||
1287 | * @param string $rootPath |
||
1288 | * @param string $pathPrefix |
||
1289 | */ |
||
1290 | View Code Duplication | public function testWriteToReadUnlockableFile($rootPath, $pathPrefix) { |
|
1291 | $rootPath = str_replace('{folder}', 'files_encryption', $rootPath); |
||
1292 | $pathPrefix = str_replace('{folder}', 'files_encryption', $pathPrefix); |
||
1293 | |||
1294 | $view = new \OC\Files\View($rootPath); |
||
1295 | $storage = new Temporary(array()); |
||
1296 | \OC\Files\Filesystem::mount($storage, [], '/'); |
||
1297 | $this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_SHARED)); |
||
1298 | $this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE)); |
||
1299 | } |
||
1300 | |||
1301 | /** |
||
1302 | * Test that locks are on mount point paths instead of mount root |
||
1303 | */ |
||
1304 | View Code Duplication | public function testLockLocalMountPointPathInsteadOfStorageRoot() { |
|
1305 | $lockingProvider = \OC::$server->getLockingProvider(); |
||
1306 | $view = new \OC\Files\View('/testuser/files/'); |
||
1307 | $storage = new Temporary([]); |
||
1308 | \OC\Files\Filesystem::mount($storage, [], '/'); |
||
1309 | $mountedStorage = new Temporary([]); |
||
1310 | \OC\Files\Filesystem::mount($mountedStorage, [], '/testuser/files/mountpoint'); |
||
1311 | |||
1312 | $this->assertTrue( |
||
1313 | $view->lockFile('/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, true), |
||
1314 | 'Can lock mount point' |
||
1315 | ); |
||
1316 | |||
1317 | // no exception here because storage root was not locked |
||
1318 | $mountedStorage->acquireLock('', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider); |
||
1319 | |||
1320 | $thrown = false; |
||
1321 | try { |
||
1322 | $storage->acquireLock('/testuser/files/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider); |
||
1323 | } catch (\OCP\Lock\LockedException $e) { |
||
1324 | $thrown = true; |
||
1325 | } |
||
1326 | $this->assertTrue($thrown, 'Mount point path was locked on root storage'); |
||
1327 | |||
1328 | $lockingProvider->releaseAll(); |
||
1329 | } |
||
1330 | |||
1331 | /** |
||
1332 | * Test that locks are on mount point paths and also mount root when requested |
||
1333 | */ |
||
1334 | View Code Duplication | public function testLockStorageRootButNotLocalMountPoint() { |
|
1335 | $lockingProvider = \OC::$server->getLockingProvider(); |
||
1336 | $view = new \OC\Files\View('/testuser/files/'); |
||
1337 | $storage = new Temporary([]); |
||
1338 | \OC\Files\Filesystem::mount($storage, [], '/'); |
||
1339 | $mountedStorage = new Temporary([]); |
||
1340 | \OC\Files\Filesystem::mount($mountedStorage, [], '/testuser/files/mountpoint'); |
||
1341 | |||
1342 | $this->assertTrue( |
||
1343 | $view->lockFile('/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, false), |
||
1344 | 'Can lock mount point' |
||
1345 | ); |
||
1346 | |||
1347 | $thrown = false; |
||
1348 | try { |
||
1349 | $mountedStorage->acquireLock('', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider); |
||
1350 | } catch (\OCP\Lock\LockedException $e) { |
||
1351 | $thrown = true; |
||
1352 | } |
||
1353 | $this->assertTrue($thrown, 'Mount point storage root was locked on original storage'); |
||
1354 | |||
1355 | // local mount point was not locked |
||
1356 | $storage->acquireLock('/testuser/files/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider); |
||
1357 | |||
1358 | $lockingProvider->releaseAll(); |
||
1359 | } |
||
1360 | |||
1361 | /** |
||
1362 | * Test that locks are on mount point paths and also mount root when requested |
||
1363 | */ |
||
1364 | public function testLockMountPointPathFailReleasesBoth() { |
||
1365 | $lockingProvider = \OC::$server->getLockingProvider(); |
||
1366 | $view = new \OC\Files\View('/testuser/files/'); |
||
1367 | $storage = new Temporary([]); |
||
1368 | \OC\Files\Filesystem::mount($storage, [], '/'); |
||
1369 | $mountedStorage = new Temporary([]); |
||
1370 | \OC\Files\Filesystem::mount($mountedStorage, [], '/testuser/files/mountpoint.txt'); |
||
1371 | |||
1372 | // this would happen if someone is writing on the mount point |
||
1373 | $mountedStorage->acquireLock('', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider); |
||
1374 | |||
1375 | $thrown = false; |
||
1376 | try { |
||
1377 | // this actually acquires two locks, one on the mount point and one on the storage root, |
||
1378 | // but the one on the storage root will fail |
||
1379 | $view->lockFile('/mountpoint.txt', ILockingProvider::LOCK_SHARED); |
||
1380 | } catch (\OCP\Lock\LockedException $e) { |
||
1381 | $thrown = true; |
||
1382 | } |
||
1383 | $this->assertTrue($thrown, 'Cannot acquire shared lock because storage root is already locked'); |
||
1384 | |||
1385 | // from here we expect that the lock on the local mount point was released properly |
||
1386 | // so acquiring an exclusive lock will succeed |
||
1387 | $storage->acquireLock('/testuser/files/mountpoint.txt', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider); |
||
1388 | |||
1389 | $lockingProvider->releaseAll(); |
||
1390 | } |
||
1391 | |||
1392 | View Code Duplication | public function dataLockPaths() { |
|
1393 | return [ |
||
1394 | ['/testuser/{folder}', ''], |
||
1395 | ['/testuser', '/{folder}'], |
||
1396 | ['', '/testuser/{folder}'], |
||
1397 | ]; |
||
1398 | } |
||
1399 | |||
1400 | public function pathRelativeToFilesProvider() { |
||
1401 | return [ |
||
1402 | ['admin/files', ''], |
||
1403 | ['admin/files/x', 'x'], |
||
1404 | ['/admin/files', ''], |
||
1405 | ['/admin/files/sub', 'sub'], |
||
1406 | ['/admin/files/sub/', 'sub'], |
||
1407 | ['/admin/files/sub/sub2', 'sub/sub2'], |
||
1408 | ['//admin//files/sub//sub2', 'sub/sub2'], |
||
1409 | ]; |
||
1410 | } |
||
1411 | |||
1412 | /** |
||
1413 | * @dataProvider pathRelativeToFilesProvider |
||
1414 | */ |
||
1415 | public function testGetPathRelativeToFiles($path, $expectedPath) { |
||
1419 | |||
1420 | public function pathRelativeToFilesProviderExceptionCases() { |
||
1421 | return [ |
||
1422 | [''], |
||
1423 | ['x'], |
||
1424 | ['files'], |
||
1425 | ['/files'], |
||
1426 | ['/admin/files_versions/abc'], |
||
1427 | ]; |
||
1428 | } |
||
1429 | |||
1430 | /** |
||
1431 | * @dataProvider pathRelativeToFilesProviderExceptionCases |
||
1432 | * @expectedException \InvalidArgumentException |
||
1433 | */ |
||
1434 | public function testGetPathRelativeToFilesWithInvalidArgument($path) { |
||
1438 | |||
1439 | public function testChangeLock() { |
||
1440 | $view = new \OC\Files\View('/testuser/files/'); |
||
1441 | $storage = new Temporary(array()); |
||
1442 | \OC\Files\Filesystem::mount($storage, [], '/'); |
||
1443 | |||
1444 | $view->lockFile('/test/sub', ILockingProvider::LOCK_SHARED); |
||
1445 | $this->assertTrue($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_SHARED)); |
||
1446 | $this->assertFalse($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_EXCLUSIVE)); |
||
1447 | |||
1448 | $view->changeLock('//test/sub', ILockingProvider::LOCK_EXCLUSIVE); |
||
1449 | $this->assertTrue($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_EXCLUSIVE)); |
||
1450 | |||
1451 | $view->changeLock('test/sub', ILockingProvider::LOCK_SHARED); |
||
1452 | $this->assertTrue($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_SHARED)); |
||
1453 | |||
1454 | $view->unlockFile('/test/sub/', ILockingProvider::LOCK_SHARED); |
||
1455 | |||
1456 | $this->assertFalse($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_SHARED)); |
||
1457 | $this->assertFalse($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_EXCLUSIVE)); |
||
1458 | |||
1459 | } |
||
1460 | |||
1461 | public function hookPathProvider() { |
||
1462 | return [ |
||
1463 | ['/foo/files', '/foo', true], |
||
1464 | ['/foo/files/bar', '/foo', true], |
||
1465 | ['/foo', '/foo', false], |
||
1466 | ['/foo', '/files/foo', true], |
||
1467 | ['/foo', 'filesfoo', false], |
||
1468 | ['', '/foo/files', true], |
||
1469 | ['', '/foo/files/bar.txt', true] |
||
1470 | ]; |
||
1471 | } |
||
1472 | |||
1473 | /** |
||
1474 | * @dataProvider hookPathProvider |
||
1475 | * @param $root |
||
1476 | * @param $path |
||
1477 | * @param $shouldEmit |
||
1478 | */ |
||
1479 | public function testHookPaths($root, $path, $shouldEmit) { |
||
1480 | $filesystemReflection = new \ReflectionClass('\OC\Files\Filesystem'); |
||
1481 | $defaultRootValue = $filesystemReflection->getProperty('defaultInstance'); |
||
1482 | $defaultRootValue->setAccessible(true); |
||
1483 | $oldRoot = $defaultRootValue->getValue(); |
||
1484 | $defaultView = new \OC\Files\View('/foo/files'); |
||
1485 | $defaultRootValue->setValue($defaultView); |
||
1486 | $view = new \OC\Files\View($root); |
||
1487 | $result = \Test_Helper::invokePrivate($view, 'shouldEmitHooks', [$path]); |
||
1488 | $defaultRootValue->setValue($oldRoot); |
||
1489 | $this->assertEquals($shouldEmit, $result); |
||
1490 | } |
||
1491 | |||
1492 | /** |
||
1493 | * Create test movable mount points |
||
1494 | * |
||
1495 | * @param array $mountPoints array of mount point locations |
||
1496 | * @return array array of MountPoint objects |
||
1497 | */ |
||
1498 | private function createTestMovableMountPoints($mountPoints) { |
||
1522 | |||
1523 | /** |
||
1524 | * Test mount point move |
||
1525 | */ |
||
1526 | public function testMountPointMove() { |
||
1547 | /** |
||
1548 | * Test that moving a mount point into another is forbidden |
||
1549 | */ |
||
1550 | public function testMoveMountPointIntoAnother() { |
||
1569 | /** |
||
1570 | * Test that moving a mount point into a shared folder is forbidden |
||
1571 | */ |
||
1572 | public function testMoveMountPointIntoSharedFolder() { |
||
1598 | |||
1599 | public function basicOperationProviderForLocks() { |
||
1708 | |||
1709 | /** |
||
1710 | * Test whether locks are set before and after the operation |
||
1711 | * |
||
1712 | * @dataProvider basicOperationProviderForLocks |
||
1713 | * |
||
1714 | * @param string $operation operation name on the view |
||
1715 | * @param array $operationArgs arguments for the operation |
||
1716 | * @param string $lockedPath path of the locked item to check |
||
1717 | * @param string $hookType hook type |
||
1718 | * @param int $expectedLockBefore expected lock during pre hooks |
||
1719 | * @param int $expectedLockduring expected lock during operation |
||
1720 | * @param int $expectedLockAfter expected lock during post hooks |
||
1721 | * @param int $expectedStrayLock expected lock after returning, should |
||
1722 | * be null (unlock) for most operations |
||
1723 | */ |
||
1724 | public function testLockBasicOperation( |
||
1776 | |||
1777 | /** |
||
1778 | * Test locks for file_put_content with stream. |
||
1779 | * This code path uses $storage->fopen instead |
||
1780 | */ |
||
1781 | public function testLockFilePutContentWithStream() { |
||
1815 | |||
1816 | /** |
||
1817 | * Test locks for fopen with fclose at the end |
||
1818 | */ |
||
1819 | public function testLockFopen() { |
||
1857 | |||
1858 | /** |
||
1859 | * Test locks for fopen with fclose at the end |
||
1860 | * |
||
1861 | * @dataProvider basicOperationProviderForLocks |
||
1862 | * |
||
1863 | * @param string $operation operation name on the view |
||
1864 | * @param array $operationArgs arguments for the operation |
||
1865 | * @param string $path path of the locked item to check |
||
1866 | */ |
||
1867 | public function testLockBasicOperationUnlocksAfterException( |
||
1905 | |||
1906 | /** |
||
1907 | * Test locks for fopen with fclose at the end |
||
1908 | * |
||
1909 | * @dataProvider basicOperationProviderForLocks |
||
1910 | * |
||
1911 | * @param string $operation operation name on the view |
||
1912 | * @param array $operationArgs arguments for the operation |
||
1913 | * @param string $path path of the locked item to check |
||
1914 | * @param string $hookType hook type |
||
1915 | */ |
||
1916 | public function testLockBasicOperationUnlocksAfterCancelledHook( |
||
1942 | |||
1943 | public function lockFileRenameOrCopyDataProvider() { |
||
1949 | |||
1950 | /** |
||
1951 | * Test locks for rename or copy operation |
||
1952 | * |
||
1953 | * @dataProvider lockFileRenameOrCopyDataProvider |
||
1954 | * |
||
1955 | * @param string $operation operation to be done on the view |
||
1956 | * @param int $expectedLockTypeSourceDuring expected lock type on source file during |
||
1957 | * the operation |
||
1958 | */ |
||
1959 | public function testLockFileRename($operation, $expectedLockTypeSourceDuring) { |
||
2003 | |||
2004 | /** |
||
2005 | * simulate a failed copy operation. |
||
2006 | * We expect that we catch the exception, free the lock and re-throw it. |
||
2007 | * |
||
2008 | * @expectedException \Exception |
||
2009 | */ |
||
2010 | public function testLockFileCopyException() { |
||
2046 | |||
2047 | /** |
||
2048 | * Test rename operation: unlock first path when second path was locked |
||
2049 | */ |
||
2050 | public function testLockFileRenameUnlockOnException() { |
||
2079 | |||
2080 | public function lockFileRenameOrCopyCrossStorageDataProvider() { |
||
2086 | |||
2087 | /** |
||
2088 | * Test locks for rename or copy operation cross-storage |
||
2089 | * |
||
2090 | * @dataProvider lockFileRenameOrCopyCrossStorageDataProvider |
||
2091 | * |
||
2092 | * @param string $viewOperation operation to be done on the view |
||
2093 | * @param string $storageOperation operation to be mocked on the storage |
||
2094 | * @param int $expectedLockTypeSourceDuring expected lock type on source file during |
||
2095 | * the operation |
||
2096 | */ |
||
2097 | public function testLockFileRenameCrossStorage($viewOperation, $storageOperation, $expectedLockTypeSourceDuring) { |
||
2147 | |||
2148 | /** |
||
2149 | * Test locks when moving a mount point |
||
2150 | */ |
||
2151 | public function testLockMoveMountPoint() { |
||
2208 | |||
2209 | /** |
||
2210 | * Connect hook callbacks for hook type |
||
2211 | * |
||
2212 | * @param string $hookType hook type or null for none |
||
2213 | * @param \OC\Files\View $view view to check the lock on |
||
2214 | * @param string $path path for which to check the lock |
||
2215 | * @param int $lockTypePre variable to receive lock type that was active in the pre-hook |
||
2216 | * @param int $lockTypePost variable to receive lock type that was active in the post-hook |
||
2217 | * @param bool $onMountPoint true to check the mount point instead of the |
||
2218 | * mounted storage |
||
2219 | */ |
||
2220 | private function connectMockHooks($hookType, $view, $path, &$lockTypePre, &$lockTypePost, $onMountPoint = false) { |
||
2259 | |||
2260 | /** |
||
2261 | * Returns the file lock type |
||
2262 | * |
||
2263 | * @param \OC\Files\View $view view |
||
2264 | * @param string $path path |
||
2265 | * @param bool $onMountPoint true to check the mount point instead of the |
||
2266 | * mounted storage |
||
2267 | * |
||
2268 | * @return int lock type or null if file was not locked |
||
2269 | */ |
||
2270 | private function getFileLockType(\OC\Files\View $view, $path, $onMountPoint = false) { |
||
2278 | } |
||
2279 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.