Completed
Push — stable8 ( 420dab...a42074 )
by
unknown
10:01
created

View   F

Complexity

Total Complexity 71

Size/Duplication

Total Lines 1044
Duplicated Lines 8.91 %

Coupling/Cohesion

Components 1
Dependencies 17

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 93
loc 1044
rs 1.3183
c 1
b 0
f 0
wmc 71
lcom 1
cbo 17

54 Methods

Rating   Name   Duplication   Size   Complexity  
A hookPathProvider() 0 9 1
A testHookPaths() 0 12 1
A setUp() 0 16 1
A tearDown() 0 17 4
B testCacheAPI() 0 79 1
A testGetPath() 0 22 1
A testMountPointOverwrite() 11 11 1
A testCacheIncompleteFolder() 13 13 1
A testAutoScan() 0 17 1
B testSearch() 0 46 4
A testWatcher() 0 17 1
A testCopyBetweenStorageNoCross() 0 5 1
A testCopyBetweenStorageCross() 0 5 1
A testCopyBetweenStorageCrossNonLocal() 0 5 1
A copyBetweenStorages() 0 18 1
A testMoveBetweenStorageNoCross() 0 5 1
A testMoveBetweenStorageCross() 0 5 1
A testMoveBetweenStorageCrossNonLocal() 0 5 1
A moveBetweenStorages() 13 13 1
A testUnlink() 0 19 1
A testUnlinkRootMustFail() 15 15 1
A testTouch() 0 20 1
A testViewHooks() 0 18 1
A dummyHook() 0 3 1
A testSearchNotOutsideView() 0 12 1
A getTestStorage() 19 19 2
A testViewHooksIfRootStartsTheSame() 0 14 1
A dummyHookWrite() 0 3 1
A dummyHookUpdate() 0 3 1
A dummyHookCreate() 0 3 1
B testEditNoCreateHook() 0 29 1
A testResolvePath() 0 15 1
A resolvePathTestProvider() 0 14 1
B testUTF8Names() 0 29 4
B xtestLongPath() 0 53 5
A testTouchNotSupported() 0 16 1
B testWatcherEtagCrossStorage() 0 29 1
A testGetAbsolutePath() 0 4 1
A testPartFileInfo() 0 13 1
A absolutePathProvider() 11 11 1
A testGetRelativePath() 0 6 1
A relativePathProvider() 11 11 1
A testFileView() 0 15 1
B testTooLongPath() 0 27 4
B tooLongPathDataProvider() 0 45 1
B testRenameCrossStoragePreserveMtime() 0 26 1
A testRenameFailDeleteTargetKeepSource() 0 3 1
A testCopyFailDeleteTargetKeepSource() 0 3 1
A doTestCopyRenameFail() 0 53 1
A testDeleteFailKeepCache() 0 22 1
A testRenameOverWrite() 0 12 1
A testGetAbsolutePathOnNull() 0 4 1
A testGetRelativePathOnNull() 0 4 1
A testNullAsRoot() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

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 Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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
2
/**
3
 * Copyright (c) 2012 Robin Appelman <[email protected]>
4
 * This file is licensed under the Affero General Public License version 3 or
5
 * later.
6
 * See the COPYING-README file. */
7
8
namespace Test\Files;
9
10
use OC\Files\Cache\Watcher;
11
use OC\Files\Storage\Temporary;
12
13
class TemporaryNoTouch extends \OC\Files\Storage\Temporary {
14
	public function touch($path, $mtime = null) {
15
		return false;
16
	}
17
}
18
19
class TemporaryNoCross extends \OC\Files\Storage\Temporary {
20
	public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
21
		return Common::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
22
	}
23
24
	public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
25
		return Common::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
26
	}
27
}
28
29
class TemporaryNoLocal extends \OC\Files\Storage\Temporary {
30
	public function instanceOfStorage($className) {
31
		if ($className === '\OC\Files\Storage\Local') {
32
			return false;
33
		} else {
34
			return parent::instanceOfStorage($className);
35
		}
36
	}
37
}
38
39
class View extends \Test\TestCase {
40
	/**
41
	 * @var \OC\Files\Storage\Storage[] $storages
42
	 */
43
	private $storages = array();
44
	private $user;
45
46
	/** @var \OC\Files\Storage\Storage */
47
	private $tempStorage;
48
49
	/** @var \OC\Files\Storage\Storage */
50
	private $originalStorage;
51
52
	protected function setUp() {
53
		parent::setUp();
54
55
		\OC_User::clearBackends();
56
		\OC_User::useBackend(new \OC_User_Dummy());
57
58
		//login
59
		\OC_User::createUser('test', 'test');
60
		$this->user = \OC_User::getUser();
61
		\OC_User::setUserId('test');
62
63
		$this->originalStorage = \OC\Files\Filesystem::getStorage('/');
64
		\OC\Files\Filesystem::clearMounts();
65
66
		$this->tempStorage = null;
67
	}
68
69
	protected function tearDown() {
70
		\OC_User::setUserId($this->user);
71
		foreach ($this->storages as $storage) {
72
			$cache = $storage->getCache();
73
			$ids = $cache->getAll();
0 ignored issues
show
Unused Code introduced by
$ids is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
74
			$cache->clear();
75
		}
76
77
		if ($this->tempStorage && !\OC_Util::runningOnWindows()) {
78
			system('rm -rf ' . escapeshellarg($this->tempStorage->getDataDir()));
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface OC\Files\Storage\Storage as the method getDataDir() does only exist in the following implementations of said interface: OC\Files\Storage\Temporary, Test\Files\Cache\LongId, Test\Files\Mount\LongId, Test\Files\TemporaryNoCross, Test\Files\TemporaryNoLocal, Test\Files\TemporaryNoTouch.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
79
		}
80
81
		\OC\Files\Filesystem::clearMounts();
82
		\OC\Files\Filesystem::mount($this->originalStorage, array(), '/');
83
84
		parent::tearDown();
85
	}
86
87
	/**
88
	 * @medium
89
	 */
90
	public function testCacheAPI() {
91
		$storage1 = $this->getTestStorage();
92
		$storage2 = $this->getTestStorage();
93
		$storage3 = $this->getTestStorage();
94
		$root = $this->getUniqueID('/');
95
		\OC\Files\Filesystem::mount($storage1, array(), $root . '/');
96
		\OC\Files\Filesystem::mount($storage2, array(), $root . '/substorage');
97
		\OC\Files\Filesystem::mount($storage3, array(), $root . '/folder/anotherstorage');
98
		$textSize = strlen("dummy file data\n");
99
		$imageSize = filesize(\OC::$SERVERROOT . '/core/img/logo.png');
100
		$storageSize = $textSize * 2 + $imageSize;
101
102
		$storageInfo = $storage3->getCache()->get('');
103
		$this->assertEquals($storageSize, $storageInfo['size']);
104
105
		$rootView = new \OC\Files\View($root);
106
107
		$cachedData = $rootView->getFileInfo('/foo.txt');
108
		$this->assertEquals($textSize, $cachedData['size']);
109
		$this->assertEquals('text/plain', $cachedData['mimetype']);
110
		$this->assertNotEquals(-1, $cachedData['permissions']);
111
112
		$cachedData = $rootView->getFileInfo('/');
113
		$this->assertEquals($storageSize * 3, $cachedData['size']);
114
		$this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
115
116
		// get cached data excluding mount points
117
		$cachedData = $rootView->getFileInfo('/', false);
118
		$this->assertEquals($storageSize, $cachedData['size']);
119
		$this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
120
121
		$cachedData = $rootView->getFileInfo('/folder');
122
		$this->assertEquals($storageSize + $textSize, $cachedData['size']);
123
		$this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
124
125
		$folderData = $rootView->getDirectoryContent('/');
126
		/**
127
		 * expected entries:
128
		 * folder
129
		 * foo.png
130
		 * foo.txt
131
		 * substorage
132
		 */
133
		$this->assertEquals(4, count($folderData));
134
		$this->assertEquals('folder', $folderData[0]['name']);
135
		$this->assertEquals('foo.png', $folderData[1]['name']);
136
		$this->assertEquals('foo.txt', $folderData[2]['name']);
137
		$this->assertEquals('substorage', $folderData[3]['name']);
138
139
		$this->assertEquals($storageSize + $textSize, $folderData[0]['size']);
140
		$this->assertEquals($imageSize, $folderData[1]['size']);
141
		$this->assertEquals($textSize, $folderData[2]['size']);
142
		$this->assertEquals($storageSize, $folderData[3]['size']);
143
144
		$folderData = $rootView->getDirectoryContent('/substorage');
145
		/**
146
		 * expected entries:
147
		 * folder
148
		 * foo.png
149
		 * foo.txt
150
		 */
151
		$this->assertEquals(3, count($folderData));
152
		$this->assertEquals('folder', $folderData[0]['name']);
153
		$this->assertEquals('foo.png', $folderData[1]['name']);
154
		$this->assertEquals('foo.txt', $folderData[2]['name']);
155
156
		$folderView = new \OC\Files\View($root . '/folder');
157
		$this->assertEquals($rootView->getFileInfo('/folder'), $folderView->getFileInfo('/'));
158
159
		$cachedData = $rootView->getFileInfo('/foo.txt');
160
		$this->assertFalse($cachedData['encrypted']);
161
		$id = $rootView->putFileInfo('/foo.txt', array('encrypted' => true));
162
		$cachedData = $rootView->getFileInfo('/foo.txt');
163
		$this->assertTrue($cachedData['encrypted']);
164
		$this->assertEquals($cachedData['fileid'], $id);
165
166
		$this->assertFalse($rootView->getFileInfo('/non/existing'));
167
		$this->assertEquals(array(), $rootView->getDirectoryContent('/non/existing'));
168
	}
169
170
	/**
171
	 * @medium
172
	 */
173
	function testGetPath() {
174
		$storage1 = $this->getTestStorage();
175
		$storage2 = $this->getTestStorage();
176
		$storage3 = $this->getTestStorage();
177
		\OC\Files\Filesystem::mount($storage1, array(), '/');
178
		\OC\Files\Filesystem::mount($storage2, array(), '/substorage');
179
		\OC\Files\Filesystem::mount($storage3, array(), '/folder/anotherstorage');
180
181
		$rootView = new \OC\Files\View('');
182
183
		$cachedData = $rootView->getFileInfo('/foo.txt');
184
		$id1 = $cachedData['fileid'];
185
		$this->assertEquals('/foo.txt', $rootView->getPath($id1));
186
187
		$cachedData = $rootView->getFileInfo('/substorage/foo.txt');
188
		$id2 = $cachedData['fileid'];
189
		$this->assertEquals('/substorage/foo.txt', $rootView->getPath($id2));
190
191
		$folderView = new \OC\Files\View('/substorage');
192
		$this->assertEquals('/foo.txt', $folderView->getPath($id2));
193
		$this->assertNull($folderView->getPath($id1));
194
	}
195
196
	/**
197
	 * @medium
198
	 */
199 View Code Duplication
	function testMountPointOverwrite() {
200
		$storage1 = $this->getTestStorage(false);
201
		$storage2 = $this->getTestStorage();
202
		$storage1->mkdir('substorage');
203
		\OC\Files\Filesystem::mount($storage1, array(), '/');
204
		\OC\Files\Filesystem::mount($storage2, array(), '/substorage');
205
206
		$rootView = new \OC\Files\View('');
207
		$folderContent = $rootView->getDirectoryContent('/');
208
		$this->assertEquals(4, count($folderContent));
209
	}
210
211 View Code Duplication
	function testCacheIncompleteFolder() {
212
		$storage1 = $this->getTestStorage(false);
213
		\OC\Files\Filesystem::clearMounts();
214
		\OC\Files\Filesystem::mount($storage1, array(), '/incomplete');
215
		$rootView = new \OC\Files\View('/incomplete');
216
217
		$entries = $rootView->getDirectoryContent('/');
218
		$this->assertEquals(3, count($entries));
219
220
		// /folder will already be in the cache but not scanned
221
		$entries = $rootView->getDirectoryContent('/folder');
222
		$this->assertEquals(1, count($entries));
223
	}
224
225
	public function testAutoScan() {
226
		$storage1 = $this->getTestStorage(false);
227
		$storage2 = $this->getTestStorage(false);
228
		\OC\Files\Filesystem::mount($storage1, array(), '/');
229
		\OC\Files\Filesystem::mount($storage2, array(), '/substorage');
230
		$textSize = strlen("dummy file data\n");
231
232
		$rootView = new \OC\Files\View('');
233
234
		$cachedData = $rootView->getFileInfo('/');
235
		$this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
236
		$this->assertEquals(-1, $cachedData['size']);
237
238
		$folderData = $rootView->getDirectoryContent('/substorage/folder');
239
		$this->assertEquals('text/plain', $folderData[0]['mimetype']);
240
		$this->assertEquals($textSize, $folderData[0]['size']);
241
	}
242
243
	/**
244
	 * @medium
245
	 */
246
	function testSearch() {
247
		$storage1 = $this->getTestStorage();
248
		$storage2 = $this->getTestStorage();
249
		$storage3 = $this->getTestStorage();
250
		\OC\Files\Filesystem::mount($storage1, array(), '/');
251
		\OC\Files\Filesystem::mount($storage2, array(), '/substorage');
252
		\OC\Files\Filesystem::mount($storage3, array(), '/folder/anotherstorage');
253
254
		$rootView = new \OC\Files\View('');
255
256
		$results = $rootView->search('foo');
257
		$this->assertEquals(6, count($results));
258
		$paths = array();
259
		foreach ($results as $result) {
260
			$this->assertEquals($result['path'], \OC\Files\Filesystem::normalizePath($result['path']));
261
			$paths[] = $result['path'];
262
		}
263
		$this->assertContains('/foo.txt', $paths);
264
		$this->assertContains('/foo.png', $paths);
265
		$this->assertContains('/substorage/foo.txt', $paths);
266
		$this->assertContains('/substorage/foo.png', $paths);
267
		$this->assertContains('/folder/anotherstorage/foo.txt', $paths);
268
		$this->assertContains('/folder/anotherstorage/foo.png', $paths);
269
270
		$folderView = new \OC\Files\View('/folder');
271
		$results = $folderView->search('bar');
272
		$this->assertEquals(2, count($results));
273
		$paths = array();
274
		foreach ($results as $result) {
275
			$paths[] = $result['path'];
276
		}
277
		$this->assertContains('/anotherstorage/folder/bar.txt', $paths);
278
		$this->assertContains('/bar.txt', $paths);
279
280
		$results = $folderView->search('foo');
281
		$this->assertEquals(2, count($results));
282
		$paths = array();
283
		foreach ($results as $result) {
284
			$paths[] = $result['path'];
285
		}
286
		$this->assertContains('/anotherstorage/foo.txt', $paths);
287
		$this->assertContains('/anotherstorage/foo.png', $paths);
288
289
		$this->assertEquals(6, count($rootView->searchByMime('text')));
290
		$this->assertEquals(3, count($folderView->searchByMime('text')));
291
	}
292
293
	/**
294
	 * @medium
295
	 */
296
	function testWatcher() {
297
		$storage1 = $this->getTestStorage();
298
		\OC\Files\Filesystem::mount($storage1, array(), '/');
299
		$storage1->getWatcher()->setPolicy(Watcher::CHECK_ALWAYS);
300
301
		$rootView = new \OC\Files\View('');
302
303
		$cachedData = $rootView->getFileInfo('foo.txt');
304
		$this->assertEquals(16, $cachedData['size']);
305
306
		$rootView->putFileInfo('foo.txt', array('storage_mtime' => 10));
307
		$storage1->file_put_contents('foo.txt', 'foo');
308
		clearstatcache();
309
310
		$cachedData = $rootView->getFileInfo('foo.txt');
311
		$this->assertEquals(3, $cachedData['size']);
312
	}
313
314
	/**
315
	 * @medium
316
	 */
317
	function testCopyBetweenStorageNoCross() {
318
		$storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoCross');
319
		$storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoCross');
320
		$this->copyBetweenStorages($storage1, $storage2);
321
	}
322
323
	/**
324
	 * @medium
325
	 */
326
	function testCopyBetweenStorageCross() {
327
		$storage1 = $this->getTestStorage();
328
		$storage2 = $this->getTestStorage();
329
		$this->copyBetweenStorages($storage1, $storage2);
330
	}
331
332
	/**
333
	 * @medium
334
	 */
335
	function testCopyBetweenStorageCrossNonLocal() {
336
		$storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal');
337
		$storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal');
338
		$this->copyBetweenStorages($storage1, $storage2);
339
	}
340
341
	function copyBetweenStorages($storage1, $storage2) {
342
		\OC\Files\Filesystem::mount($storage1, array(), '/');
343
		\OC\Files\Filesystem::mount($storage2, array(), '/substorage');
344
345
		$rootView = new \OC\Files\View('');
346
		$rootView->mkdir('substorage/emptyfolder');
347
		$rootView->copy('substorage', 'anotherfolder');
348
		$this->assertTrue($rootView->is_dir('/anotherfolder'));
349
		$this->assertTrue($rootView->is_dir('/substorage'));
350
		$this->assertTrue($rootView->is_dir('/anotherfolder/emptyfolder'));
351
		$this->assertTrue($rootView->is_dir('/substorage/emptyfolder'));
352
		$this->assertTrue($rootView->file_exists('/anotherfolder/foo.txt'));
353
		$this->assertTrue($rootView->file_exists('/anotherfolder/foo.png'));
354
		$this->assertTrue($rootView->file_exists('/anotherfolder/folder/bar.txt'));
355
		$this->assertTrue($rootView->file_exists('/substorage/foo.txt'));
356
		$this->assertTrue($rootView->file_exists('/substorage/foo.png'));
357
		$this->assertTrue($rootView->file_exists('/substorage/folder/bar.txt'));
358
	}
359
360
	/**
361
	 * @medium
362
	 */
363
	function testMoveBetweenStorageNoCross() {
364
		$storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoCross');
365
		$storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoCross');
366
		$this->moveBetweenStorages($storage1, $storage2);
367
	}
368
369
	/**
370
	 * @medium
371
	 */
372
	function testMoveBetweenStorageCross() {
373
		$storage1 = $this->getTestStorage();
374
		$storage2 = $this->getTestStorage();
375
		$this->moveBetweenStorages($storage1, $storage2);
376
	}
377
378
	/**
379
	 * @medium
380
	 */
381
	function testMoveBetweenStorageCrossNonLocal() {
382
		$storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal');
383
		$storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal');
384
		$this->moveBetweenStorages($storage1, $storage2);
385
	}
386
387 View Code Duplication
	function moveBetweenStorages($storage1, $storage2) {
388
		\OC\Files\Filesystem::mount($storage1, array(), '/');
389
		\OC\Files\Filesystem::mount($storage2, array(), '/substorage');
390
391
		$rootView = new \OC\Files\View('');
392
		$rootView->rename('foo.txt', 'substorage/folder/foo.txt');
393
		$this->assertFalse($rootView->file_exists('foo.txt'));
394
		$this->assertTrue($rootView->file_exists('substorage/folder/foo.txt'));
395
		$rootView->rename('substorage/folder', 'anotherfolder');
396
		$this->assertFalse($rootView->is_dir('substorage/folder'));
397
		$this->assertTrue($rootView->file_exists('anotherfolder/foo.txt'));
398
		$this->assertTrue($rootView->file_exists('anotherfolder/bar.txt'));
399
	}
400
401
	/**
402
	 * @medium
403
	 */
404
	function testUnlink() {
405
		$storage1 = $this->getTestStorage();
406
		$storage2 = $this->getTestStorage();
407
		\OC\Files\Filesystem::mount($storage1, array(), '/');
408
		\OC\Files\Filesystem::mount($storage2, array(), '/substorage');
409
410
		$rootView = new \OC\Files\View('');
411
		$rootView->file_put_contents('/foo.txt', 'asd');
412
		$rootView->file_put_contents('/substorage/bar.txt', 'asd');
413
414
		$this->assertTrue($rootView->file_exists('foo.txt'));
415
		$this->assertTrue($rootView->file_exists('substorage/bar.txt'));
416
417
		$this->assertTrue($rootView->unlink('foo.txt'));
418
		$this->assertTrue($rootView->unlink('substorage/bar.txt'));
419
420
		$this->assertFalse($rootView->file_exists('foo.txt'));
421
		$this->assertFalse($rootView->file_exists('substorage/bar.txt'));
422
	}
423
424
	/**
425
	 * @medium
426
	 */
427 View Code Duplication
	function testUnlinkRootMustFail() {
428
		$storage1 = $this->getTestStorage();
429
		$storage2 = $this->getTestStorage();
430
		\OC\Files\Filesystem::mount($storage1, array(), '/');
431
		\OC\Files\Filesystem::mount($storage2, array(), '/substorage');
432
433
		$rootView = new \OC\Files\View('');
434
		$rootView->file_put_contents('/foo.txt', 'asd');
435
		$rootView->file_put_contents('/substorage/bar.txt', 'asd');
436
437
		$this->assertFalse($rootView->unlink(''));
438
		$this->assertFalse($rootView->unlink('/'));
439
		$this->assertFalse($rootView->unlink('substorage'));
440
		$this->assertFalse($rootView->unlink('/substorage'));
441
	}
442
443
	/**
444
	 * @medium
445
	 */
446
	function testTouch() {
447
		$storage = $this->getTestStorage(true, '\Test\Files\TemporaryNoTouch');
448
449
		\OC\Files\Filesystem::mount($storage, array(), '/');
450
451
		$rootView = new \OC\Files\View('');
452
		$oldCachedData = $rootView->getFileInfo('foo.txt');
453
454
		$rootView->touch('foo.txt', 500);
455
456
		$cachedData = $rootView->getFileInfo('foo.txt');
457
		$this->assertEquals(500, $cachedData['mtime']);
458
		$this->assertEquals($oldCachedData['storage_mtime'], $cachedData['storage_mtime']);
459
460
		$rootView->putFileInfo('foo.txt', array('storage_mtime' => 1000)); //make sure the watcher detects the change
461
		$rootView->file_put_contents('foo.txt', 'asd');
462
		$cachedData = $rootView->getFileInfo('foo.txt');
463
		$this->assertGreaterThanOrEqual($oldCachedData['mtime'], $cachedData['mtime']);
464
		$this->assertEquals($cachedData['storage_mtime'], $cachedData['mtime']);
465
	}
466
467
	/**
468
	 * @medium
469
	 */
470
	function testViewHooks() {
471
		$storage1 = $this->getTestStorage();
472
		$storage2 = $this->getTestStorage();
473
		$defaultRoot = \OC\Files\Filesystem::getRoot();
474
		\OC\Files\Filesystem::mount($storage1, array(), '/');
475
		\OC\Files\Filesystem::mount($storage2, array(), $defaultRoot . '/substorage');
476
		\OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook');
0 ignored issues
show
Documentation introduced by
$this is of type this<Test\Files\View>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
477
478
		$rootView = new \OC\Files\View('');
479
		$subView = new \OC\Files\View($defaultRoot . '/substorage');
480
		$this->hookPath = null;
481
482
		$rootView->file_put_contents('/foo.txt', 'asd');
483
		$this->assertNull($this->hookPath);
484
485
		$subView->file_put_contents('/foo.txt', 'asd');
486
		$this->assertEquals('/substorage/foo.txt', $this->hookPath);
487
	}
488
489
	private $hookPath;
490
491
	public function dummyHook($params) {
492
		$this->hookPath = $params['path'];
493
	}
494
495
	public function testSearchNotOutsideView() {
496
		$storage1 = $this->getTestStorage();
497
		\OC\Files\Filesystem::mount($storage1, array(), '/');
498
		$storage1->rename('folder', 'foo');
499
		$scanner = $storage1->getScanner();
500
		$scanner->scan('');
501
502
		$view = new \OC\Files\View('/foo');
503
504
		$result = $view->search('.txt');
505
		$this->assertCount(1, $result);
506
	}
507
508
	/**
509
	 * @param bool $scan
510
	 * @param string $class
511
	 * @return \OC\Files\Storage\Storage
512
	 */
513 View Code Duplication
	private function getTestStorage($scan = true, $class = '\OC\Files\Storage\Temporary') {
514
		/**
515
		 * @var \OC\Files\Storage\Storage $storage
516
		 */
517
		$storage = new $class(array());
518
		$textData = "dummy file data\n";
519
		$imgData = file_get_contents(\OC::$SERVERROOT . '/core/img/logo.png');
520
		$storage->mkdir('folder');
521
		$storage->file_put_contents('foo.txt', $textData);
522
		$storage->file_put_contents('foo.png', $imgData);
523
		$storage->file_put_contents('folder/bar.txt', $textData);
524
525
		if ($scan) {
526
			$scanner = $storage->getScanner();
527
			$scanner->scan('');
528
		}
529
		$this->storages[] = $storage;
530
		return $storage;
531
	}
532
533
	/**
534
	 * @medium
535
	 */
536
	function testViewHooksIfRootStartsTheSame() {
537
		$storage1 = $this->getTestStorage();
538
		$storage2 = $this->getTestStorage();
539
		$defaultRoot = \OC\Files\Filesystem::getRoot();
540
		\OC\Files\Filesystem::mount($storage1, array(), '/');
541
		\OC\Files\Filesystem::mount($storage2, array(), $defaultRoot . '_substorage');
542
		\OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook');
0 ignored issues
show
Documentation introduced by
$this is of type this<Test\Files\View>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
543
544
		$subView = new \OC\Files\View($defaultRoot . '_substorage');
545
		$this->hookPath = null;
546
547
		$subView->file_put_contents('/foo.txt', 'asd');
548
		$this->assertNull($this->hookPath);
549
	}
550
551
	private $hookWritePath;
552
	private $hookCreatePath;
553
	private $hookUpdatePath;
554
555
	public function dummyHookWrite($params) {
556
		$this->hookWritePath = $params['path'];
557
	}
558
559
	public function dummyHookUpdate($params) {
560
		$this->hookUpdatePath = $params['path'];
561
	}
562
563
	public function dummyHookCreate($params) {
564
		$this->hookCreatePath = $params['path'];
565
	}
566
567
	public function testEditNoCreateHook() {
568
		$storage1 = $this->getTestStorage();
569
		$storage2 = $this->getTestStorage();
570
		$defaultRoot = \OC\Files\Filesystem::getRoot();
571
		\OC\Files\Filesystem::mount($storage1, array(), '/');
572
		\OC\Files\Filesystem::mount($storage2, array(), $defaultRoot);
573
		\OC_Hook::connect('OC_Filesystem', 'post_create', $this, 'dummyHookCreate');
0 ignored issues
show
Documentation introduced by
$this is of type this<Test\Files\View>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
574
		\OC_Hook::connect('OC_Filesystem', 'post_update', $this, 'dummyHookUpdate');
0 ignored issues
show
Documentation introduced by
$this is of type this<Test\Files\View>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
575
		\OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHookWrite');
0 ignored issues
show
Documentation introduced by
$this is of type this<Test\Files\View>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
576
577
		$view = new \OC\Files\View($defaultRoot);
578
		$this->hookWritePath = $this->hookUpdatePath = $this->hookCreatePath = null;
579
580
		$view->file_put_contents('/asd.txt', 'foo');
581
		$this->assertEquals('/asd.txt', $this->hookCreatePath);
582
		$this->assertNull($this->hookUpdatePath);
583
		$this->assertEquals('/asd.txt', $this->hookWritePath);
584
585
		$this->hookWritePath = $this->hookUpdatePath = $this->hookCreatePath = null;
586
587
		$view->file_put_contents('/asd.txt', 'foo');
588
		$this->assertNull($this->hookCreatePath);
589
		$this->assertEquals('/asd.txt', $this->hookUpdatePath);
590
		$this->assertEquals('/asd.txt', $this->hookWritePath);
591
592
		\OC_Hook::clear('OC_Filesystem', 'post_create');
593
		\OC_Hook::clear('OC_Filesystem', 'post_update');
594
		\OC_Hook::clear('OC_Filesystem', 'post_write');
595
	}
596
597
	/**
598
	 * @dataProvider resolvePathTestProvider
599
	 */
600
	public function testResolvePath($expected, $pathToTest) {
601
		$storage1 = $this->getTestStorage();
602
		\OC\Files\Filesystem::mount($storage1, array(), '/');
603
604
		$view = new \OC\Files\View('');
605
606
		$result = $view->resolvePath($pathToTest);
607
		$this->assertEquals($expected, $result[1]);
608
609
		$exists = $view->file_exists($pathToTest);
610
		$this->assertTrue($exists);
611
612
		$exists = $view->file_exists($result[1]);
613
		$this->assertTrue($exists);
614
	}
615
616
	function resolvePathTestProvider() {
617
		return array(
618
			array('foo.txt', 'foo.txt'),
619
			array('foo.txt', '/foo.txt'),
620
			array('folder', 'folder'),
621
			array('folder', '/folder'),
622
			array('folder', 'folder/'),
623
			array('folder', '/folder/'),
624
			array('folder/bar.txt', 'folder/bar.txt'),
625
			array('folder/bar.txt', '/folder/bar.txt'),
626
			array('', ''),
627
			array('', '/'),
628
		);
629
	}
630
631
	public function testUTF8Names() {
632
		$names = array('虚', '和知しゃ和で', 'regular ascii', 'sɨˈrɪlɪk', 'ѨѬ', 'أنا أحب القراءة كثيرا');
633
634
		$storage = new \OC\Files\Storage\Temporary(array());
635
		\OC\Files\Filesystem::mount($storage, array(), '/');
636
637
		$rootView = new \OC\Files\View('');
638
		foreach ($names as $name) {
639
			$rootView->file_put_contents('/' . $name, 'dummy content');
640
		}
641
642
		$list = $rootView->getDirectoryContent('/');
643
644
		$this->assertCount(count($names), $list);
645
		foreach ($list as $item) {
646
			$this->assertContains($item['name'], $names);
647
		}
648
649
		$cache = $storage->getCache();
650
		$scanner = $storage->getScanner();
651
		$scanner->scan('');
652
653
		$list = $cache->getFolderContents('');
654
655
		$this->assertCount(count($names), $list);
656
		foreach ($list as $item) {
657
			$this->assertContains($item['name'], $names);
658
		}
659
	}
660
661
	public function xtestLongPath() {
662
663
		$storage = new \OC\Files\Storage\Temporary(array());
664
		\OC\Files\Filesystem::mount($storage, array(), '/');
665
666
		$rootView = new \OC\Files\View('');
667
668
		$longPath = '';
669
		$ds = DIRECTORY_SEPARATOR;
670
		/*
671
		 * 4096 is the maximum path length in file_cache.path in *nix
672
		 * 1024 is the max path length in mac
673
		 * 228 is the max path length in windows
674
		 */
675
		$folderName = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789';
676
		$tmpdirLength = strlen(\OC_Helper::tmpFolder());
677
		if (\OC_Util::runningOnWindows()) {
678
			$this->markTestSkipped('[Windows] ');
679
			$depth = ((260 - $tmpdirLength) / 57);
680
		} elseif (\OC_Util::runningOnMac()) {
681
			$depth = ((1024 - $tmpdirLength) / 57);
682
		} else {
683
			$depth = ((4000 - $tmpdirLength) / 57);
684
		}
685
		foreach (range(0, $depth - 1) as $i) {
686
			$longPath .= $ds . $folderName;
687
			$result = $rootView->mkdir($longPath);
688
			$this->assertTrue($result, "mkdir failed on $i - path length: " . strlen($longPath));
689
690
			$result = $rootView->file_put_contents($longPath . "{$ds}test.txt", 'lorem');
691
			$this->assertEquals(5, $result, "file_put_contents failed on $i");
692
693
			$this->assertTrue($rootView->file_exists($longPath));
694
			$this->assertTrue($rootView->file_exists($longPath . "{$ds}test.txt"));
695
		}
696
697
		$cache = $storage->getCache();
698
		$scanner = $storage->getScanner();
699
		$scanner->scan('');
700
701
		$longPath = $folderName;
702
		foreach (range(0, $depth - 1) as $i) {
703
			$cachedFolder = $cache->get($longPath);
704
			$this->assertTrue(is_array($cachedFolder), "No cache entry for folder at $i");
705
			$this->assertEquals($folderName, $cachedFolder['name'], "Wrong cache entry for folder at $i");
706
707
			$cachedFile = $cache->get($longPath . '/test.txt');
708
			$this->assertTrue(is_array($cachedFile), "No cache entry for file at $i");
709
			$this->assertEquals('test.txt', $cachedFile['name'], "Wrong cache entry for file at $i");
710
711
			$longPath .= $ds . $folderName;
712
		}
713
	}
714
715
	public function testTouchNotSupported() {
716
		$storage = new TemporaryNoTouch(array());
717
		$scanner = $storage->getScanner();
718
		\OC\Files\Filesystem::mount($storage, array(), '/test/');
719
		$past = time() - 100;
720
		$storage->file_put_contents('test', 'foobar');
721
		$scanner->scan('');
722
		$view = new \OC\Files\View('');
723
		$info = $view->getFileInfo('/test/test');
724
725
		$view->touch('/test/test', $past);
726
		$scanner->scanFile('test', \OC\Files\Cache\Scanner::REUSE_ETAG);
727
728
		$info2 = $view->getFileInfo('/test/test');
729
		$this->assertSame($info['etag'], $info2['etag']);
730
	}
731
732
	public function testWatcherEtagCrossStorage() {
733
		$storage1 = new Temporary(array());
734
		$storage2 = new Temporary(array());
735
		$scanner1 = $storage1->getScanner();
736
		$scanner2 = $storage2->getScanner();
737
		$storage1->mkdir('sub');
738
		\OC\Files\Filesystem::mount($storage1, array(), '/test/');
739
		\OC\Files\Filesystem::mount($storage2, array(), '/test/sub/storage');
740
741
		$past = time() - 100;
742
		$storage2->file_put_contents('test.txt', 'foobar');
743
		$scanner1->scan('');
744
		$scanner2->scan('');
745
		$view = new \OC\Files\View('');
746
747
		$storage2->getWatcher('')->setPolicy(Watcher::CHECK_ALWAYS);
748
749
		$oldFileInfo = $view->getFileInfo('/test/sub/storage/test.txt');
750
		$oldFolderInfo = $view->getFileInfo('/test');
751
752
		$storage2->getCache()->update($oldFileInfo->getId(), array(
753
			'storage_mtime' => $past
754
		));
755
756
		$view->getFileInfo('/test/sub/storage/test.txt');
757
		$newFolderInfo = $view->getFileInfo('/test');
758
759
		$this->assertNotEquals($newFolderInfo->getEtag(), $oldFolderInfo->getEtag());
760
	}
761
762
	/**
763
	 * @dataProvider absolutePathProvider
764
	 */
765
	public function testGetAbsolutePath($expectedPath, $relativePath) {
766
		$view = new \OC\Files\View('/files');
767
		$this->assertEquals($expectedPath, $view->getAbsolutePath($relativePath));
768
	}
769
770
	public function testPartFileInfo() {
771
		$storage = new Temporary(array());
772
		$scanner = $storage->getScanner();
773
		\OC\Files\Filesystem::mount($storage, array(), '/test/');
774
		$storage->file_put_contents('test.part', 'foobar');
775
		$scanner->scan('');
776
		$view = new \OC\Files\View('/test');
777
		$info = $view->getFileInfo('test.part');
778
779
		$this->assertInstanceOf('\OCP\Files\FileInfo', $info);
780
		$this->assertNull($info->getId());
781
		$this->assertEquals(6, $info->getSize());
782
	}
783
784 View Code Duplication
	function absolutePathProvider() {
785
		return array(
786
			array('/files/', ''),
787
			array('/files/0', '0'),
788
			array('/files/false', 'false'),
789
			array('/files/true', 'true'),
790
			array('/files/', '/'),
791
			array('/files/test', 'test'),
792
			array('/files/test', '/test'),
793
		);
794
	}
795
796
	/**
797
	 * @dataProvider relativePathProvider
798
	 */
799
	function testGetRelativePath($absolutePath, $expectedPath) {
800
		$view = new \OC\Files\View('/files');
801
		// simulate a external storage mount point which has a trailing slash
802
		$view->chroot('/files/');
803
		$this->assertEquals($expectedPath, $view->getRelativePath($absolutePath));
804
	}
805
806 View Code Duplication
	function relativePathProvider() {
807
		return array(
808
			array('/files/', '/'),
809
			array('/files', '/'),
810
			array('/files/0', '0'),
811
			array('/files/false', 'false'),
812
			array('/files/true', 'true'),
813
			array('/files/test', 'test'),
814
			array('/files/test/foo', 'test/foo'),
815
		);
816
	}
817
818
	public function testFileView() {
819
		$storage = new Temporary(array());
820
		$scanner = $storage->getScanner();
821
		$storage->file_put_contents('foo.txt', 'bar');
822
		\OC\Files\Filesystem::mount($storage, array(), '/test/');
823
		$scanner->scan('');
824
		$view = new \OC\Files\View('/test/foo.txt');
825
826
		$this->assertEquals('bar', $view->file_get_contents(''));
827
		$fh = tmpfile();
828
		fwrite($fh, 'foo');
829
		rewind($fh);
830
		$view->file_put_contents('', $fh);
831
		$this->assertEquals('foo', $view->file_get_contents(''));
832
	}
833
834
	/**
835
	 * @dataProvider tooLongPathDataProvider
836
	 * @expectedException \OCP\Files\InvalidPathException
837
	 */
838
	public function testTooLongPath($operation, $param0 = null) {
839
840
		$longPath = '';
841
		// 4000 is the maximum path length in file_cache.path
842
		$folderName = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789';
843
		$depth = (4000 / 57);
844
		foreach (range(0, $depth + 1) as $i) {
845
			$longPath .= '/' . $folderName;
846
		}
847
848
		$storage = new \OC\Files\Storage\Temporary(array());
849
		$this->tempStorage = $storage; // for later hard cleanup
850
		\OC\Files\Filesystem::mount($storage, array(), '/');
851
852
		$rootView = new \OC\Files\View('');
853
854
		if ($param0 === '@0') {
855
			$param0 = $longPath;
856
		}
857
858
		if ($operation === 'hash') {
859
			$param0 = $longPath;
860
			$longPath = 'md5';
861
		}
862
863
		call_user_func(array($rootView, $operation), $longPath, $param0);
864
	}
865
866
	public function tooLongPathDataProvider() {
867
		return array(
868
			array('getAbsolutePath'),
869
			array('getRelativePath'),
870
			array('getMountPoint'),
871
			array('resolvePath'),
872
			array('getLocalFile'),
873
			array('getLocalFolder'),
874
			array('mkdir'),
875
			array('rmdir'),
876
			array('opendir'),
877
			array('is_dir'),
878
			array('is_file'),
879
			array('stat'),
880
			array('filetype'),
881
			array('filesize'),
882
			array('readfile'),
883
			array('isCreatable'),
884
			array('isReadable'),
885
			array('isUpdatable'),
886
			array('isDeletable'),
887
			array('isSharable'),
888
			array('file_exists'),
889
			array('filemtime'),
890
			array('touch'),
891
			array('file_get_contents'),
892
			array('unlink'),
893
			array('deleteAll'),
894
			array('toTmpFile'),
895
			array('getMimeType'),
896
			array('free_space'),
897
			array('getFileInfo'),
898
			array('getDirectoryContent'),
899
			array('getOwner'),
900
			array('getETag'),
901
			array('file_put_contents', 'ipsum'),
902
			array('rename', '@0'),
903
			array('copy', '@0'),
904
			array('fopen', 'r'),
905
			array('fromTmpFile', '@0'),
906
			array('hash'),
907
			array('hasUpdated', 0),
908
			array('putFileInfo', array()),
909
		);
910
	}
911
912
	public function testRenameCrossStoragePreserveMtime() {
913
		$storage1 = new Temporary(array());
914
		$storage2 = new Temporary(array());
915
		$scanner1 = $storage1->getScanner();
0 ignored issues
show
Unused Code introduced by
$scanner1 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
916
		$scanner2 = $storage2->getScanner();
0 ignored issues
show
Unused Code introduced by
$scanner2 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
917
		$storage1->mkdir('sub');
918
		$storage1->mkdir('foo');
919
		$storage1->file_put_contents('foo.txt', 'asd');
920
		$storage1->file_put_contents('foo/bar.txt', 'asd');
921
		\OC\Files\Filesystem::mount($storage1, array(), '/test/');
922
		\OC\Files\Filesystem::mount($storage2, array(), '/test/sub/storage');
923
924
		$view = new \OC\Files\View('');
925
		$time = time() - 200;
926
		$view->touch('/test/foo.txt', $time);
927
		$view->touch('/test/foo', $time);
928
		$view->touch('/test/foo/bar.txt', $time);
929
930
		$view->rename('/test/foo.txt', '/test/sub/storage/foo.txt');
931
932
		$this->assertEquals($time, $view->filemtime('/test/sub/storage/foo.txt'));
933
934
		$view->rename('/test/foo', '/test/sub/storage/foo');
935
936
		$this->assertEquals($time, $view->filemtime('/test/sub/storage/foo/bar.txt'));
937
	}
938
939
	public function testRenameFailDeleteTargetKeepSource() {
940
		$this->doTestCopyRenameFail('rename');
941
	}
942
943
	public function testCopyFailDeleteTargetKeepSource() {
944
		$this->doTestCopyRenameFail('copy');
945
	}
946
947
	private function doTestCopyRenameFail($operation) {
948
		$storage1 = new Temporary(array());
949
		/** @var \PHPUnit_Framework_MockObject_MockObject | \OC\Files\Storage\Temporary $storage2 */
950
		$storage2 = $this->getMockBuilder('\Test\Files\TemporaryNoCross')
951
			->setConstructorArgs([[]])
952
			->setMethods(['fopen'])
953
			->getMock();
954
955
		$storage2->expects($this->any())
956
			->method('fopen')
957
			->will($this->returnCallback(function ($path, $mode) use ($storage2) {
958
				$source = fopen($storage2->getSourcePath($path), $mode);
959
				return \OC\Files\Stream\Quota::wrap($source, 9);
960
			}));
961
962
		$storage1->mkdir('sub');
963
		$storage1->file_put_contents('foo.txt', '0123456789ABCDEFGH');
964
		$storage1->mkdir('dirtomove');
965
		$storage1->file_put_contents('dirtomove/indir1.txt', '0123456'); // fits
966
		$storage1->file_put_contents('dirtomove/indir2.txt', '0123456789ABCDEFGH'); // doesn't fit 
967
		$storage2->file_put_contents('existing.txt', '0123');
968
		$storage1->getScanner()->scan('');
969
		$storage2->getScanner()->scan('');
970
		\OC\Files\Filesystem::mount($storage1, array(), '/test/');
971
		\OC\Files\Filesystem::mount($storage2, array(), '/test/sub/storage');
972
973
		// move file
974
		$view = new \OC\Files\View('');
975
		$this->assertTrue($storage1->file_exists('foo.txt'));
976
		$this->assertFalse($storage2->file_exists('foo.txt'));
977
		$this->assertFalse($view->$operation('/test/foo.txt', '/test/sub/storage/foo.txt'));
978
		$this->assertFalse($storage2->file_exists('foo.txt'));
979
		$this->assertFalse($storage2->getCache()->get('foo.txt'));
980
		$this->assertTrue($storage1->file_exists('foo.txt'));
981
982
		// if target exists, it will be deleted too
983
		$this->assertFalse($view->$operation('/test/foo.txt', '/test/sub/storage/existing.txt'));
984
		$this->assertFalse($storage2->file_exists('existing.txt'));
985
		$this->assertFalse($storage2->getCache()->get('existing.txt'));
986
		$this->assertTrue($storage1->file_exists('foo.txt'));
987
988
		// move folder
989
		$this->assertFalse($view->$operation('/test/dirtomove/', '/test/sub/storage/dirtomove/'));
990
		// since the move failed, the full source tree is kept
991
		$this->assertTrue($storage1->file_exists('dirtomove/indir1.txt'));
992
		// but the target file stays
993
		$this->assertTrue($storage2->file_exists('dirtomove/indir1.txt'));
994
		// second file not moved/copied
995
		$this->assertTrue($storage1->file_exists('dirtomove/indir2.txt'));
996
		$this->assertFalse($storage2->file_exists('dirtomove/indir2.txt'));
997
		$this->assertFalse($storage2->getCache()->get('dirtomove/indir2.txt'));
998
999
	}
1000
1001
	public function testDeleteFailKeepCache() {
1002
		/**
1003
		 * @var \PHPUnit_Framework_MockObject_MockObject | \OC\Files\Storage\Temporary $storage
1004
		 */
1005
		$storage = $this->getMockBuilder('\OC\Files\Storage\Temporary')
1006
			->setConstructorArgs(array(array()))
1007
			->setMethods(array('unlink'))
1008
			->getMock();
1009
		$storage->expects($this->once())
1010
			->method('unlink')
1011
			->will($this->returnValue(false));
1012
		$scanner = $storage->getScanner();
1013
		$cache = $storage->getCache();
1014
		$storage->file_put_contents('foo.txt', 'asd');
1015
		$scanner->scan('');
1016
		\OC\Files\Filesystem::mount($storage, array(), '/test/');
1017
1018
		$view = new \OC\Files\View('/test');
1019
1020
		$this->assertFalse($view->unlink('foo.txt'));
1021
		$this->assertTrue($cache->inCache('foo.txt'));
1022
	}
1023
1024
	public function testRenameOverWrite() {
1025
		$storage = new Temporary(array());
1026
		$scanner = $storage->getScanner();
1027
		$storage->mkdir('sub');
1028
		$storage->mkdir('foo');
1029
		$storage->file_put_contents('foo.txt', 'asd');
1030
		$storage->file_put_contents('foo/bar.txt', 'asd');
1031
		$scanner->scan('');
1032
		\OC\Files\Filesystem::mount($storage, array(), '/test/');
1033
		$view = new \OC\Files\View('');
1034
		$this->assertTrue($view->rename('/test/foo.txt', '/test/foo/bar.txt'));
1035
	}
1036
1037
	public function testGetAbsolutePathOnNull() {
1038
		$view = new \OC\Files\View();
1039
		$this->assertNull($view->getAbsolutePath(null));
1040
	}
1041
1042
	public function testGetRelativePathOnNull() {
1043
		$view = new \OC\Files\View();
1044
		$this->assertNull($view->getRelativePath(null));
1045
	}
1046
1047
	/**
1048
	 * @expectedException \InvalidArgumentException
1049
	 */
1050
	public function testNullAsRoot() {
1051
		new \OC\Files\View(null);
1052
	}
1053
1054
	public function hookPathProvider() {
1055
		return [
1056
			['/foo/files', '/foo', true],
1057
			['/foo/files/bar', '/foo', true],
1058
			['/foo', '/foo', false],
1059
			['/foo', '/files/foo', true],
1060
			['/foo', 'filesfoo', false]
1061
		];
1062
	}
1063
1064
	/**
1065
	 * @dataProvider hookPathProvider
1066
	 * @param $root
1067
	 * @param $path
1068
	 * @param $shouldEmit
1069
	 */
1070
	public function testHookPaths($root, $path, $shouldEmit) {
1071
		$filesystemReflection = new \ReflectionClass('\OC\Files\Filesystem');
1072
		$defaultRootValue = $filesystemReflection->getProperty('defaultInstance');
1073
		$defaultRootValue->setAccessible(true);
1074
		$oldRoot = $defaultRootValue->getValue();
1075
		$defaultView = new \OC\Files\View('/foo/files');
1076
		$defaultRootValue->setValue($defaultView);
1077
		$view = new \OC\Files\View($root);
1078
		$result = \Test_Helper::invokePrivate($view, 'shouldEmitHooks', [$path]);
1079
		$defaultRootValue->setValue($oldRoot);
1080
		$this->assertEquals($shouldEmit, $result);
1081
	}
1082
}
1083