1
0

FolderTest.php 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace Test\Files\Node;
  8. use OC\Files\Cache\Cache;
  9. use OC\Files\Cache\CacheEntry;
  10. use OC\Files\Config\CachedMountInfo;
  11. use OC\Files\FileInfo;
  12. use OC\Files\Mount\Manager;
  13. use OC\Files\Mount\MountPoint;
  14. use OC\Files\Node\File;
  15. use OC\Files\Node\Folder;
  16. use OC\Files\Node\Node;
  17. use OC\Files\Node\Root;
  18. use OC\Files\Search\SearchBinaryOperator;
  19. use OC\Files\Search\SearchComparison;
  20. use OC\Files\Search\SearchOrder;
  21. use OC\Files\Search\SearchQuery;
  22. use OC\Files\Storage\Temporary;
  23. use OC\Files\Storage\Wrapper\Jail;
  24. use OCP\Files\Cache\ICacheEntry;
  25. use OCP\Files\IRootFolder;
  26. use OCP\Files\Mount\IMountPoint;
  27. use OCP\Files\NotFoundException;
  28. use OCP\Files\Search\ISearchBinaryOperator;
  29. use OCP\Files\Search\ISearchComparison;
  30. use OCP\Files\Search\ISearchOrder;
  31. use OCP\Files\Storage\IStorage;
  32. use PHPUnit\Framework\MockObject\MockObject;
  33. /**
  34. * Class FolderTest
  35. *
  36. * @group DB
  37. *
  38. * @package Test\Files\Node
  39. */
  40. class FolderTest extends NodeTest {
  41. protected function createTestNode($root, $view, $path, array $data = [], $internalPath = '', $storage = null) {
  42. $view->expects($this->any())
  43. ->method('getRoot')
  44. ->willReturn('');
  45. if ($data || $internalPath || $storage) {
  46. return new Folder($root, $view, $path, $this->getFileInfo($data, $internalPath, $storage));
  47. } else {
  48. return new Folder($root, $view, $path);
  49. }
  50. }
  51. protected function getNodeClass() {
  52. return '\OC\Files\Node\Folder';
  53. }
  54. protected function getNonExistingNodeClass() {
  55. return '\OC\Files\Node\NonExistingFolder';
  56. }
  57. protected function getViewDeleteMethod() {
  58. return 'rmdir';
  59. }
  60. public function testGetDirectoryContent(): void {
  61. $manager = $this->createMock(Manager::class);
  62. /**
  63. * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view
  64. */
  65. $root = $this->getMockBuilder(Root::class)
  66. ->setConstructorArgs([$manager, $this->view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  67. ->getMock();
  68. $root->expects($this->any())
  69. ->method('getUser')
  70. ->willReturn($this->user);
  71. $this->view->expects($this->any())
  72. ->method('getDirectoryContent')
  73. ->with('/bar/foo')
  74. ->willReturn([
  75. new FileInfo('/bar/foo/asd', null, 'foo/asd', ['fileid' => 2, 'path' => '/bar/foo/asd', 'name' => 'asd', 'size' => 100, 'mtime' => 50, 'mimetype' => 'text/plain'], null),
  76. new FileInfo('/bar/foo/qwerty', null, 'foo/qwerty', ['fileid' => 3, 'path' => '/bar/foo/qwerty', 'name' => 'qwerty', 'size' => 200, 'mtime' => 55, 'mimetype' => 'httpd/unix-directory'], null),
  77. ]);
  78. $this->view->method('getFileInfo')
  79. ->willReturn($this->createMock(FileInfo::class));
  80. $this->view->method('getRelativePath')
  81. ->willReturn('/bar/foo');
  82. $node = new Folder($root, $this->view, '/bar/foo');
  83. $children = $node->getDirectoryListing();
  84. $this->assertEquals(2, count($children));
  85. $this->assertInstanceOf('\OC\Files\Node\File', $children[0]);
  86. $this->assertInstanceOf('\OC\Files\Node\Folder', $children[1]);
  87. $this->assertEquals('asd', $children[0]->getName());
  88. $this->assertEquals('qwerty', $children[1]->getName());
  89. $this->assertEquals(2, $children[0]->getId());
  90. $this->assertEquals(3, $children[1]->getId());
  91. }
  92. public function testGet(): void {
  93. $manager = $this->createMock(Manager::class);
  94. $view = $this->getRootViewMock();
  95. $root = $this->getMockBuilder(Root::class)
  96. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  97. ->getMock();
  98. $root->expects($this->any())
  99. ->method('getUser')
  100. ->willReturn($this->user);
  101. $node = new File($root, $view, '/bar/foo/asd');
  102. $root->method('get')
  103. ->with('/bar/foo/asd')
  104. ->willReturn($node);
  105. $parentNode = new Folder($root, $view, '/bar/foo');
  106. self::assertEquals($node, $parentNode->get('asd'));
  107. }
  108. public function testNodeExists(): void {
  109. $manager = $this->createMock(Manager::class);
  110. $view = $this->getRootViewMock();
  111. $root = $this->getMockBuilder(Root::class)
  112. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  113. ->getMock();
  114. $root->expects($this->any())
  115. ->method('getUser')
  116. ->willReturn($this->user);
  117. $child = new Folder($root, $view, '/bar/foo/asd');
  118. $root->method('get')
  119. ->with('/bar/foo/asd')
  120. ->willReturn($child);
  121. $node = new Folder($root, $view, '/bar/foo');
  122. $this->assertTrue($node->nodeExists('asd'));
  123. }
  124. public function testNodeExistsNotExists(): void {
  125. $manager = $this->createMock(Manager::class);
  126. $view = $this->getRootViewMock();
  127. $root = $this->getMockBuilder(Root::class)
  128. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  129. ->getMock();
  130. $root->expects($this->any())
  131. ->method('getUser')
  132. ->willReturn($this->user);
  133. $root->method('get')
  134. ->with('/bar/foo/asd')
  135. ->will($this->throwException(new NotFoundException()));
  136. $node = new Folder($root, $view, '/bar/foo');
  137. $this->assertFalse($node->nodeExists('asd'));
  138. }
  139. public function testNewFolder(): void {
  140. $manager = $this->createMock(Manager::class);
  141. $view = $this->getRootViewMock();
  142. $root = $this->getMockBuilder(Root::class)
  143. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  144. ->getMock();
  145. $root->expects($this->any())
  146. ->method('getUser')
  147. ->willReturn($this->user);
  148. $view->method('getFileInfo')
  149. ->with('/bar/foo')
  150. ->willReturn($this->getFileInfo(['permissions' => \OCP\Constants::PERMISSION_ALL]));
  151. $view->method('mkdir')
  152. ->with('/bar/foo/asd')
  153. ->willReturn(true);
  154. $node = new Folder($root, $view, '/bar/foo');
  155. $child = new Folder($root, $view, '/bar/foo/asd', null, $node);
  156. $result = $node->newFolder('asd');
  157. $this->assertEquals($child, $result);
  158. }
  159. public function testNewFolderDeepParent(): void {
  160. $manager = $this->createMock(Manager::class);
  161. $view = $this->getRootViewMock();
  162. $root = $this->getMockBuilder(Root::class)
  163. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  164. ->getMock();
  165. $root->expects($this->any())
  166. ->method('getUser')
  167. ->willReturn($this->user);
  168. $view->method('getFileInfo')
  169. ->with('/foobar')
  170. ->willReturn($this->getFileInfo(['permissions' => \OCP\Constants::PERMISSION_ALL]));
  171. $view->method('mkdir')
  172. ->with('/foobar/asd/sdf')
  173. ->willReturn(true);
  174. $node = new Folder($root, $view, '/foobar');
  175. $child = new Folder($root, $view, '/foobar/asd/sdf', null, null);
  176. $result = $node->newFolder('asd/sdf');
  177. $this->assertEquals($child, $result);
  178. }
  179. public function testNewFolderNotPermitted(): void {
  180. $this->expectException(\OCP\Files\NotPermittedException::class);
  181. $manager = $this->createMock(Manager::class);
  182. $view = $this->getRootViewMock();
  183. $root = $this->getMockBuilder(Root::class)
  184. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  185. ->getMock();
  186. $root->method('getUser')
  187. ->willReturn($this->user);
  188. $view->method('getFileInfo')
  189. ->with('/bar/foo')
  190. ->willReturn($this->getFileInfo(['permissions' => \OCP\Constants::PERMISSION_READ]));
  191. $node = new Folder($root, $view, '/bar/foo');
  192. $node->newFolder('asd');
  193. }
  194. public function testNewFile(): void {
  195. $manager = $this->createMock(Manager::class);
  196. $view = $this->getRootViewMock();
  197. $root = $this->getMockBuilder(Root::class)
  198. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  199. ->getMock();
  200. $root->expects($this->any())
  201. ->method('getUser')
  202. ->willReturn($this->user);
  203. $view->method('getFileInfo')
  204. ->with('/bar/foo')
  205. ->willReturn($this->getFileInfo(['permissions' => \OCP\Constants::PERMISSION_ALL]));
  206. $view->method('touch')
  207. ->with('/bar/foo/asd')
  208. ->willReturn(true);
  209. $node = new Folder($root, $view, '/bar/foo');
  210. $child = new \OC\Files\Node\File($root, $view, '/bar/foo/asd', null, $node);
  211. $result = $node->newFile('asd');
  212. $this->assertEquals($child, $result);
  213. }
  214. public function testNewFileNotPermitted(): void {
  215. $this->expectException(\OCP\Files\NotPermittedException::class);
  216. $manager = $this->createMock(Manager::class);
  217. $view = $this->getRootViewMock();
  218. $root = $this->getMockBuilder(Root::class)
  219. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  220. ->getMock();
  221. $root->method('getUser')
  222. ->willReturn($this->user);
  223. $view->method('getFileInfo')
  224. ->with('/bar/foo')
  225. ->willReturn($this->getFileInfo(['permissions' => \OCP\Constants::PERMISSION_READ]));
  226. $node = new Folder($root, $view, '/bar/foo');
  227. $node->newFile('asd');
  228. }
  229. public function testGetFreeSpace(): void {
  230. $manager = $this->createMock(Manager::class);
  231. $view = $this->getRootViewMock();
  232. $root = $this->getMockBuilder(Root::class)
  233. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  234. ->getMock();
  235. $root->method('getUser')
  236. ->willReturn($this->user);
  237. $view->method('free_space')
  238. ->with('/bar/foo')
  239. ->willReturn(100);
  240. $node = new Folder($root, $view, '/bar/foo');
  241. $this->assertEquals(100, $node->getFreeSpace());
  242. }
  243. public function testSearch(): void {
  244. $manager = $this->createMock(Manager::class);
  245. $view = $this->getRootViewMock();
  246. $root = $this->getMockBuilder(Root::class)
  247. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  248. ->getMock();
  249. $root->method('getUser')
  250. ->willReturn($this->user);
  251. /** @var Storage\IStorage&MockObject $storage */
  252. $storage = $this->createMock(IStorage::class);
  253. $storage->method('getId')->willReturn('test::1');
  254. $cache = new Cache($storage);
  255. $storage->method('getCache')
  256. ->willReturn($cache);
  257. $storage->expects($this->atLeastOnce())
  258. ->method('getOwner')
  259. ->with('qwerty')
  260. ->willReturn(false);
  261. $mount = $this->createMock(IMountPoint::class);
  262. $mount->expects($this->atLeastOnce())
  263. ->method('getStorage')
  264. ->willReturn($storage);
  265. $mount->expects($this->atLeastOnce())
  266. ->method('getInternalPath')
  267. ->willReturn('foo');
  268. $cache->insert('', ['size' => 0, 'mtime' => 0, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  269. $cache->insert('foo', ['size' => 200, 'mtime' => 55, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  270. $cache->insert('foo/qwerty', ['size' => 200, 'mtime' => 55, 'mimetype' => 'text/plain']);
  271. $root->method('getMountsIn')
  272. ->with('/bar/foo')
  273. ->willReturn([]);
  274. $root->method('getMount')
  275. ->with('/bar/foo')
  276. ->willReturn($mount);
  277. $node = new Folder($root, $view, '/bar/foo');
  278. $result = $node->search('qw');
  279. $cache->clear();
  280. $this->assertEquals(1, count($result));
  281. $this->assertEquals('/bar/foo/qwerty', $result[0]->getPath());
  282. }
  283. public function testSearchInRoot(): void {
  284. $manager = $this->createMock(Manager::class);
  285. $view = $this->getRootViewMock();
  286. $root = $this->getMockBuilder(Root::class)
  287. ->setMethods(['getUser', 'getMountsIn', 'getMount'])
  288. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  289. ->getMock();
  290. $root->expects($this->any())
  291. ->method('getUser')
  292. ->willReturn($this->user);
  293. /** @var \PHPUnit\Framework\MockObject\MockObject|Storage $storage */
  294. $storage = $this->createMock(IStorage::class);
  295. $storage->method('getId')->willReturn('test::2');
  296. $cache = new Cache($storage);
  297. $mount = $this->createMock(IMountPoint::class);
  298. $mount->method('getStorage')
  299. ->willReturn($storage);
  300. $mount->method('getInternalPath')
  301. ->willReturn('files');
  302. $storage->method('getCache')
  303. ->willReturn($cache);
  304. $storage->method('getOwner')
  305. ->willReturn('owner');
  306. $cache->insert('', ['size' => 0, 'mtime' => 0, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  307. $cache->insert('files', ['size' => 200, 'mtime' => 55, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  308. $cache->insert('files/foo', ['size' => 200, 'mtime' => 55, 'mimetype' => 'text/plain']);
  309. $root->method('getMountsIn')
  310. ->with('')
  311. ->willReturn([]);
  312. $root->method('getMount')
  313. ->with('')
  314. ->willReturn($mount);
  315. $result = $root->search('foo');
  316. $cache->clear();
  317. $this->assertEquals(1, count($result));
  318. $this->assertEquals('/foo', $result[0]->getPath());
  319. }
  320. public function testSearchInStorageRoot(): void {
  321. $manager = $this->createMock(Manager::class);
  322. $view = $this->getRootViewMock();
  323. $root = $this->getMockBuilder(Root::class)
  324. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  325. ->getMock();
  326. $root->method('getUser')
  327. ->willReturn($this->user);
  328. $storage = $this->createMock(IStorage::class);
  329. $storage->method('getId')->willReturn('test::1');
  330. $cache = new Cache($storage);
  331. $mount = $this->createMock(IMountPoint::class);
  332. $mount->method('getStorage')
  333. ->willReturn($storage);
  334. $mount->method('getInternalPath')
  335. ->willReturn('');
  336. $storage->method('getCache')
  337. ->willReturn($cache);
  338. $storage->method('getOwner')
  339. ->willReturn('owner');
  340. $cache->insert('', ['size' => 0, 'mtime' => 0, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  341. $cache->insert('foo', ['size' => 200, 'mtime' => 55, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  342. $cache->insert('foo/qwerty', ['size' => 200, 'mtime' => 55, 'mimetype' => 'text/plain']);
  343. $root->method('getMountsIn')
  344. ->with('/bar')
  345. ->willReturn([]);
  346. $root->method('getMount')
  347. ->with('/bar')
  348. ->willReturn($mount);
  349. $node = new Folder($root, $view, '/bar');
  350. $result = $node->search('qw');
  351. $cache->clear();
  352. $this->assertEquals(1, count($result));
  353. $this->assertEquals('/bar/foo/qwerty', $result[0]->getPath());
  354. }
  355. public function testSearchSubStorages(): void {
  356. $manager = $this->createMock(Manager::class);
  357. $view = $this->getRootViewMock();
  358. $root = $this->getMockBuilder(Root::class)
  359. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  360. ->getMock();
  361. $root->expects($this->any())
  362. ->method('getUser')
  363. ->willReturn($this->user);
  364. $storage = $this->createMock(IStorage::class);
  365. $storage->method('getId')->willReturn('test::1');
  366. $cache = new Cache($storage);
  367. $subStorage = $this->createMock(IStorage::class);
  368. $subStorage->method('getId')->willReturn('test::2');
  369. $subCache = new Cache($subStorage);
  370. $subMount = $this->getMockBuilder(MountPoint::class)->setConstructorArgs([Temporary::class, ''])->getMock();
  371. $mount = $this->createMock(IMountPoint::class);
  372. $mount->method('getStorage')
  373. ->willReturn($storage);
  374. $mount->method('getInternalPath')
  375. ->willReturn('foo');
  376. $subMount->method('getStorage')
  377. ->willReturn($subStorage);
  378. $subMount->method('getMountPoint')
  379. ->willReturn('/bar/foo/bar/');
  380. $storage->method('getCache')
  381. ->willReturn($cache);
  382. $storage->method('getOwner')
  383. ->willReturn('owner');
  384. $subStorage->method('getCache')
  385. ->willReturn($subCache);
  386. $subStorage->method('getOwner')
  387. ->willReturn('owner');
  388. $cache->insert('', ['size' => 0, 'mtime' => 0, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  389. $cache->insert('foo', ['size' => 200, 'mtime' => 55, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  390. $cache->insert('foo/qwerty', ['size' => 200, 'mtime' => 55, 'mimetype' => 'text/plain']);
  391. $subCache->insert('', ['size' => 0, 'mtime' => 0, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  392. $subCache->insert('asd', ['size' => 200, 'mtime' => 55, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  393. $subCache->insert('asd/qwerty', ['size' => 200, 'mtime' => 55, 'mimetype' => 'text/plain']);
  394. $root->method('getMountsIn')
  395. ->with('/bar/foo')
  396. ->willReturn([$subMount]);
  397. $root->method('getMount')
  398. ->with('/bar/foo')
  399. ->willReturn($mount);
  400. $node = new Folder($root, $view, '/bar/foo');
  401. $result = $node->search('qw');
  402. $cache->clear();
  403. $subCache->clear();
  404. $this->assertEquals(2, count($result));
  405. }
  406. public function testIsSubNode(): void {
  407. $rootFolderMock = $this->createMock(IRootFolder::class);
  408. $file = new Node($rootFolderMock, $this->view, '/foo/bar');
  409. $folder = new Folder($rootFolderMock, $this->view, '/foo');
  410. $this->assertTrue($folder->isSubNode($file));
  411. $this->assertFalse($folder->isSubNode($folder));
  412. $file = new Node($rootFolderMock, $this->view, '/foobar');
  413. $this->assertFalse($folder->isSubNode($file));
  414. }
  415. public function testGetById(): void {
  416. $manager = $this->createMock(Manager::class);
  417. $view = $this->getRootViewMock();
  418. $root = $this->getMockBuilder(Root::class)
  419. ->setMethods(['getMountsIn', 'getMount'])
  420. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  421. ->getMock();
  422. $storage = $this->createMock(\OC\Files\Storage\Storage::class);
  423. $mount = new MountPoint($storage, '/bar');
  424. $storage->method('getId')->willReturn('');
  425. $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock();
  426. $fileInfo = new CacheEntry(['path' => 'foo/qwerty', 'mimetype' => 'text/plain'], null);
  427. $storage->method('getCache')
  428. ->willReturn($cache);
  429. $storage->method('getOwner')
  430. ->willReturn('owner');
  431. $this->userMountCache->expects($this->any())
  432. ->method('getMountsForFileId')
  433. ->with(1)
  434. ->willReturn([new CachedMountInfo(
  435. $this->user,
  436. 1,
  437. 0,
  438. '/bar/',
  439. 'test',
  440. 1,
  441. ''
  442. )]);
  443. $cache->method('get')
  444. ->with(1)
  445. ->willReturn($fileInfo);
  446. $root->method('getMountsIn')
  447. ->with('/bar/foo')
  448. ->willReturn([]);
  449. $manager->method('getMountsByMountProvider')
  450. ->willReturn([$mount]);
  451. $node = new Folder($root, $view, '/bar/foo');
  452. $result = $node->getById(1);
  453. $this->assertEquals(1, count($result));
  454. $this->assertEquals('/bar/foo/qwerty', $result[0]->getPath());
  455. }
  456. public function testGetByIdMountRoot(): void {
  457. $manager = $this->createMock(Manager::class);
  458. $view = $this->getRootViewMock();
  459. $root = $this->getMockBuilder(Root::class)
  460. ->setMethods(['getMountsIn', 'getMount'])
  461. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  462. ->getMock();
  463. $storage = $this->createMock(\OC\Files\Storage\Storage::class);
  464. $mount = new MountPoint($storage, '/bar');
  465. $storage->method('getId')->willReturn('');
  466. $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock();
  467. $fileInfo = new CacheEntry(['path' => '', 'mimetype' => 'text/plain'], null);
  468. $storage->method('getCache')
  469. ->willReturn($cache);
  470. $storage->method('getOwner')
  471. ->willReturn('owner');
  472. $this->userMountCache->expects($this->any())
  473. ->method('getMountsForFileId')
  474. ->with(1)
  475. ->willReturn([new CachedMountInfo(
  476. $this->user,
  477. 1,
  478. 0,
  479. '/bar/',
  480. 'test',
  481. 1,
  482. ''
  483. )]);
  484. $cache->method('get')
  485. ->with(1)
  486. ->willReturn($fileInfo);
  487. $manager->method('getMountsByMountProvider')
  488. ->willReturn([$mount]);
  489. $node = new Folder($root, $view, '/bar');
  490. $result = $node->getById(1);
  491. $this->assertEquals(1, count($result));
  492. $this->assertEquals('/bar', $result[0]->getPath());
  493. }
  494. public function testGetByIdOutsideFolder(): void {
  495. $manager = $this->createMock(Manager::class);
  496. $view = $this->getRootViewMock();
  497. $root = $this->getMockBuilder(Root::class)
  498. ->setMethods(['getMountsIn', 'getMount'])
  499. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  500. ->getMock();
  501. $storage = $this->createMock(\OC\Files\Storage\Storage::class);
  502. $mount = new MountPoint($storage, '/bar');
  503. $storage->method('getId')->willReturn('');
  504. $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock();
  505. $fileInfo = new CacheEntry(['path' => 'foobar', 'mimetype' => 'text/plain'], null);
  506. $storage->method('getCache')
  507. ->willReturn($cache);
  508. $storage->method('getOwner')
  509. ->willReturn('owner');
  510. $this->userMountCache->expects($this->any())
  511. ->method('getMountsForFileId')
  512. ->with(1)
  513. ->willReturn([new CachedMountInfo(
  514. $this->user,
  515. 1,
  516. 0,
  517. '/bar/',
  518. 'test',
  519. 1,
  520. ''
  521. )]);
  522. $cache->method('get')
  523. ->with(1)
  524. ->willReturn($fileInfo);
  525. $manager->method('getMountsByMountProvider')
  526. ->willReturn([$mount]);
  527. $node = new Folder($root, $view, '/bar/foo');
  528. $result = $node->getById(1);
  529. $this->assertEquals(0, count($result));
  530. }
  531. public function testGetByIdMultipleStorages(): void {
  532. $manager = $this->createMock(Manager::class);
  533. $view = $this->getRootViewMock();
  534. $root = $this->getMockBuilder(Root::class)
  535. ->setMethods(['getMountsIn', 'getMount'])
  536. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  537. ->getMock();
  538. $storage = $this->createMock(\OC\Files\Storage\Storage::class);
  539. $mount1 = new MountPoint($storage, '/bar');
  540. $mount2 = new MountPoint($storage, '/bar/foo/asd');
  541. $storage->method('getId')->willReturn('');
  542. $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock();
  543. $fileInfo = new CacheEntry(['path' => 'foo/qwerty', 'mimetype' => 'text/plain'], null);
  544. $storage->method('getCache')
  545. ->willReturn($cache);
  546. $storage->method('getOwner')
  547. ->willReturn('owner');
  548. $this->userMountCache->method('getMountsForFileId')
  549. ->with(1)
  550. ->willReturn([
  551. new CachedMountInfo(
  552. $this->user,
  553. 1,
  554. 0,
  555. '/bar/',
  556. 'test',
  557. 1,
  558. ''
  559. ),
  560. ]);
  561. $cache->method('get')
  562. ->with(1)
  563. ->willReturn($fileInfo);
  564. $manager->method('getMountsByMountProvider')
  565. ->willReturn([$mount1, $mount2]);
  566. $node = new Folder($root, $view, '/bar/foo');
  567. $result = $node->getById(1);
  568. $this->assertEquals(2, count($result));
  569. $this->assertEquals('/bar/foo/qwerty', $result[0]->getPath());
  570. $this->assertEquals('/bar/foo/asd/foo/qwerty', $result[1]->getPath());
  571. }
  572. public function uniqueNameProvider() {
  573. return [
  574. // input, existing, expected
  575. ['foo', [], 'foo'],
  576. ['foo', ['foo'], 'foo (2)'],
  577. ['foo', ['foo', 'foo (2)'], 'foo (3)'],
  578. ];
  579. }
  580. /**
  581. * @dataProvider uniqueNameProvider
  582. */
  583. public function testGetUniqueName($name, $existingFiles, $expected): void {
  584. $manager = $this->createMock(Manager::class);
  585. $folderPath = '/bar/foo';
  586. $view = $this->getRootViewMock();
  587. $root = $this->getMockBuilder(Root::class)
  588. ->setMethods(['getUser', 'getMountsIn', 'getMount'])
  589. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  590. ->getMock();
  591. $view->expects($this->any())
  592. ->method('file_exists')
  593. ->willReturnCallback(function ($path) use ($existingFiles, $folderPath) {
  594. foreach ($existingFiles as $existing) {
  595. if ($folderPath . '/' . $existing === $path) {
  596. return true;
  597. }
  598. }
  599. return false;
  600. });
  601. $node = new Folder($root, $view, $folderPath);
  602. $this->assertEquals($expected, $node->getNonExistingName($name));
  603. }
  604. public function testRecent(): void {
  605. $manager = $this->createMock(Manager::class);
  606. $folderPath = '/bar/foo';
  607. $view = $this->getRootViewMock();
  608. /** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\Node\Root $root */
  609. $root = $this->getMockBuilder(Root::class)
  610. ->setMethods(['getUser', 'getMountsIn', 'getMount'])
  611. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  612. ->getMock();
  613. /** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\FileInfo $folderInfo */
  614. $folderInfo = $this->getMockBuilder(FileInfo::class)
  615. ->disableOriginalConstructor()->getMock();
  616. $baseTime = time();
  617. $storage = new Temporary();
  618. $mount = new MountPoint($storage, '');
  619. $folderInfo->expects($this->any())
  620. ->method('getMountPoint')
  621. ->willReturn($mount);
  622. $root->method('getMount')
  623. ->willReturn($mount);
  624. $root->method('getMountsIn')
  625. ->willReturn([]);
  626. $cache = $storage->getCache();
  627. $cache->insert('', ['size' => 0, 'mtime' => 0, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  628. $cache->insert('bar', ['size' => 0, 'mtime' => 0, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  629. $cache->insert('bar/foo', ['size' => 0, 'mtime' => 0, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  630. $cache->insert('bar/asd', ['size' => 0, 'mtime' => 0, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  631. $id1 = $cache->put('bar/foo/inside.txt', [
  632. 'storage_mtime' => $baseTime,
  633. 'mtime' => $baseTime,
  634. 'mimetype' => 'text/plain',
  635. 'size' => 3,
  636. 'permissions' => \OCP\Constants::PERMISSION_ALL,
  637. ]);
  638. $id2 = $cache->put('bar/foo/old.txt', [
  639. 'storage_mtime' => $baseTime - 100,
  640. 'mtime' => $baseTime - 100,
  641. 'mimetype' => 'text/plain',
  642. 'size' => 3,
  643. 'permissions' => \OCP\Constants::PERMISSION_READ,
  644. ]);
  645. $cache->put('bar/asd/outside.txt', [
  646. 'storage_mtime' => $baseTime,
  647. 'mtime' => $baseTime,
  648. 'mimetype' => 'text/plain',
  649. 'size' => 3,
  650. ]);
  651. $id3 = $cache->put('bar/foo/older.txt', [
  652. 'storage_mtime' => $baseTime - 600,
  653. 'mtime' => $baseTime - 600,
  654. 'mimetype' => 'text/plain',
  655. 'size' => 3,
  656. 'permissions' => \OCP\Constants::PERMISSION_ALL,
  657. ]);
  658. $node = new Folder($root, $view, $folderPath, $folderInfo);
  659. $nodes = $node->getRecent(5);
  660. $ids = array_map(function (Node $node) {
  661. return (int)$node->getId();
  662. }, $nodes);
  663. $this->assertEquals([$id1, $id2, $id3], $ids);
  664. }
  665. public function testRecentFolder(): void {
  666. $manager = $this->createMock(Manager::class);
  667. $folderPath = '/bar/foo';
  668. $view = $this->getRootViewMock();
  669. /** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\Node\Root $root */
  670. $root = $this->getMockBuilder(Root::class)
  671. ->setMethods(['getUser', 'getMountsIn', 'getMount'])
  672. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  673. ->getMock();
  674. /** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\FileInfo $folderInfo */
  675. $folderInfo = $this->getMockBuilder(FileInfo::class)
  676. ->disableOriginalConstructor()->getMock();
  677. $baseTime = time();
  678. $storage = new Temporary();
  679. $mount = new MountPoint($storage, '');
  680. $folderInfo->expects($this->any())
  681. ->method('getMountPoint')
  682. ->willReturn($mount);
  683. $root->method('getMount')
  684. ->willReturn($mount);
  685. $root->method('getMountsIn')
  686. ->willReturn([]);
  687. $cache = $storage->getCache();
  688. $cache->insert('', ['size' => 0, 'mtime' => 0, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  689. $cache->insert('bar', ['size' => 0, 'mtime' => 0, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  690. $cache->insert('bar/foo', ['size' => 0, 'mtime' => 0, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  691. $id1 = $cache->put('bar/foo/folder', [
  692. 'storage_mtime' => $baseTime,
  693. 'mtime' => $baseTime,
  694. 'mimetype' => \OCP\Files\FileInfo::MIMETYPE_FOLDER,
  695. 'size' => 3,
  696. 'permissions' => 0,
  697. ]);
  698. $id2 = $cache->put('bar/foo/folder/bar.txt', [
  699. 'storage_mtime' => $baseTime,
  700. 'mtime' => $baseTime,
  701. 'mimetype' => 'text/plain',
  702. 'size' => 3,
  703. 'parent' => $id1,
  704. 'permissions' => \OCP\Constants::PERMISSION_ALL,
  705. ]);
  706. $id3 = $cache->put('bar/foo/folder/asd.txt', [
  707. 'storage_mtime' => $baseTime - 100,
  708. 'mtime' => $baseTime - 100,
  709. 'mimetype' => 'text/plain',
  710. 'size' => 3,
  711. 'parent' => $id1,
  712. 'permissions' => \OCP\Constants::PERMISSION_ALL,
  713. ]);
  714. $node = new Folder($root, $view, $folderPath, $folderInfo);
  715. $nodes = $node->getRecent(5);
  716. $ids = array_map(function (Node $node) {
  717. return (int)$node->getId();
  718. }, $nodes);
  719. $this->assertEquals([$id2, $id3], $ids);
  720. $this->assertEquals($baseTime, $nodes[0]->getMTime());
  721. $this->assertEquals($baseTime - 100, $nodes[1]->getMTime());
  722. }
  723. public function testRecentJail(): void {
  724. $manager = $this->createMock(Manager::class);
  725. $folderPath = '/bar/foo';
  726. $view = $this->getRootViewMock();
  727. /** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\Node\Root $root */
  728. $root = $this->getMockBuilder(Root::class)
  729. ->setMethods(['getUser', 'getMountsIn', 'getMount'])
  730. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  731. ->getMock();
  732. /** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\FileInfo $folderInfo */
  733. $folderInfo = $this->getMockBuilder(FileInfo::class)
  734. ->disableOriginalConstructor()->getMock();
  735. $baseTime = time();
  736. $storage = new Temporary();
  737. $jail = new Jail([
  738. 'storage' => $storage,
  739. 'root' => 'folder',
  740. ]);
  741. $mount = new MountPoint($jail, '/bar/foo');
  742. $folderInfo->expects($this->any())
  743. ->method('getMountPoint')
  744. ->willReturn($mount);
  745. $root->method('getMount')
  746. ->willReturn($mount);
  747. $root->method('getMountsIn')
  748. ->willReturn([]);
  749. $cache = $storage->getCache();
  750. $cache->insert('', ['size' => 0, 'mtime' => 0, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  751. $cache->insert('folder', ['size' => 0, 'mtime' => 0, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  752. $id1 = $cache->put('folder/inside.txt', [
  753. 'storage_mtime' => $baseTime,
  754. 'mtime' => $baseTime,
  755. 'mimetype' => 'text/plain',
  756. 'size' => 3,
  757. 'permissions' => \OCP\Constants::PERMISSION_ALL,
  758. ]);
  759. $cache->put('outside.txt', [
  760. 'storage_mtime' => $baseTime - 100,
  761. 'mtime' => $baseTime - 100,
  762. 'mimetype' => 'text/plain',
  763. 'size' => 3,
  764. ]);
  765. $node = new Folder($root, $view, $folderPath, $folderInfo);
  766. $nodes = $node->getRecent(5);
  767. $ids = array_map(function (Node $node) {
  768. return (int)$node->getId();
  769. }, $nodes);
  770. $this->assertEquals([$id1], $ids);
  771. }
  772. public function offsetLimitProvider() {
  773. return [
  774. [0, 10, ['/bar/foo/foo1', '/bar/foo/foo2', '/bar/foo/foo3', '/bar/foo/foo4', '/bar/foo/sub1/foo5', '/bar/foo/sub1/foo6', '/bar/foo/sub2/foo7', '/bar/foo/sub2/foo8'], []],
  775. [0, 5, ['/bar/foo/foo1', '/bar/foo/foo2', '/bar/foo/foo3', '/bar/foo/foo4', '/bar/foo/sub1/foo5'], []],
  776. [0, 2, ['/bar/foo/foo1', '/bar/foo/foo2'], []],
  777. [3, 2, ['/bar/foo/foo4', '/bar/foo/sub1/foo5'], []],
  778. [3, 5, ['/bar/foo/foo4', '/bar/foo/sub1/foo5', '/bar/foo/sub1/foo6', '/bar/foo/sub2/foo7', '/bar/foo/sub2/foo8'], []],
  779. [5, 2, ['/bar/foo/sub1/foo6', '/bar/foo/sub2/foo7'], []],
  780. [6, 2, ['/bar/foo/sub2/foo7', '/bar/foo/sub2/foo8'], []],
  781. [7, 2, ['/bar/foo/sub2/foo8'], []],
  782. [10, 2, [], []],
  783. [0, 5, ['/bar/foo/sub2/foo7', '/bar/foo/foo1', '/bar/foo/sub1/foo5', '/bar/foo/foo2', '/bar/foo/foo3'], [new SearchOrder(ISearchOrder::DIRECTION_ASCENDING, 'mtime')]],
  784. [3, 2, ['/bar/foo/foo2', '/bar/foo/foo3'], [new SearchOrder(ISearchOrder::DIRECTION_ASCENDING, 'mtime')]],
  785. [0, 5, ['/bar/foo/sub1/foo5', '/bar/foo/sub1/foo6', '/bar/foo/sub2/foo7', '/bar/foo/foo1', '/bar/foo/foo2'], [
  786. new SearchOrder(ISearchOrder::DIRECTION_DESCENDING, 'size'),
  787. new SearchOrder(ISearchOrder::DIRECTION_ASCENDING, 'mtime')
  788. ]],
  789. ];
  790. }
  791. /**
  792. * @dataProvider offsetLimitProvider
  793. * @param int $offset
  794. * @param int $limit
  795. * @param string[] $expectedPaths
  796. * @param ISearchOrder[] $ordering
  797. * @throws NotFoundException
  798. * @throws \OCP\Files\InvalidPathException
  799. */
  800. public function testSearchSubStoragesLimitOffset(int $offset, int $limit, array $expectedPaths, array $ordering): void {
  801. if (!$ordering) {
  802. $ordering = [new SearchOrder(ISearchOrder::DIRECTION_ASCENDING, 'fileid')];
  803. }
  804. $manager = $this->createMock(Manager::class);
  805. $view = $this->getRootViewMock();
  806. $root = $this->getMockBuilder(Root::class)
  807. ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager, $this->eventDispatcher, $this->cacheFactory])
  808. ->getMock();
  809. $root->expects($this->any())
  810. ->method('getUser')
  811. ->willReturn($this->user);
  812. $storage = $this->createMock(IStorage::class);
  813. $storage->method('getId')->willReturn('test::1');
  814. $cache = new Cache($storage);
  815. $subStorage1 = $this->createMock(IStorage::class);
  816. $subStorage1->method('getId')->willReturn('test::2');
  817. $subCache1 = new Cache($subStorage1);
  818. $subMount1 = $this->getMockBuilder(MountPoint::class)->setConstructorArgs([Temporary::class, ''])->getMock();
  819. $subStorage2 = $this->createMock(IStorage::class);
  820. $subStorage2->method('getId')->willReturn('test::3');
  821. $subCache2 = new Cache($subStorage2);
  822. $subMount2 = $this->getMockBuilder(MountPoint::class)->setConstructorArgs([Temporary::class, ''])->getMock();
  823. $mount = $this->createMock(IMountPoint::class);
  824. $mount->method('getStorage')
  825. ->willReturn($storage);
  826. $mount->method('getInternalPath')
  827. ->willReturn('foo');
  828. $subMount1->method('getStorage')
  829. ->willReturn($subStorage1);
  830. $subMount1->method('getMountPoint')
  831. ->willReturn('/bar/foo/sub1/');
  832. $storage->method('getCache')
  833. ->willReturn($cache);
  834. $storage->method('getOwner')
  835. ->willReturn('owner');
  836. $subStorage1->method('getCache')
  837. ->willReturn($subCache1);
  838. $subStorage1->method('getOwner')
  839. ->willReturn('owner');
  840. $subMount2->method('getStorage')
  841. ->willReturn($subStorage2);
  842. $subMount2->method('getMountPoint')
  843. ->willReturn('/bar/foo/sub2/');
  844. $subStorage2->method('getCache')
  845. ->willReturn($subCache2);
  846. $subStorage2->method('getOwner')
  847. ->willReturn('owner');
  848. $cache->insert('', ['size' => 0, 'mtime' => 10, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  849. $cache->insert('foo', ['size' => 0, 'mtime' => 10, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  850. $cache->insert('foo/foo1', ['size' => 200, 'mtime' => 10, 'mimetype' => 'text/plain']);
  851. $cache->insert('foo/foo2', ['size' => 200, 'mtime' => 20, 'mimetype' => 'text/plain']);
  852. $cache->insert('foo/foo3', ['size' => 200, 'mtime' => 30, 'mimetype' => 'text/plain']);
  853. $cache->insert('foo/foo4', ['size' => 200, 'mtime' => 40, 'mimetype' => 'text/plain']);
  854. $subCache1->insert('', ['size' => 0, 'mtime' => 10, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  855. $subCache1->insert('foo5', ['size' => 300, 'mtime' => 15, 'mimetype' => 'text/plain']);
  856. $subCache1->insert('foo6', ['size' => 300, 'mtime' => 50, 'mimetype' => 'text/plain']);
  857. $subCache2->insert('', ['size' => 0, 'mtime' => 10, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]);
  858. $subCache2->insert('foo7', ['size' => 200, 'mtime' => 5, 'mimetype' => 'text/plain']);
  859. $subCache2->insert('foo8', ['size' => 200, 'mtime' => 60, 'mimetype' => 'text/plain']);
  860. $root->method('getMountsIn')
  861. ->with('/bar/foo')
  862. ->willReturn([$subMount1, $subMount2]);
  863. $root->method('getMount')
  864. ->with('/bar/foo')
  865. ->willReturn($mount);
  866. $node = new Folder($root, $view, '/bar/foo');
  867. $comparison = new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', '%foo%');
  868. $operator = new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_AND, [
  869. $comparison,
  870. new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_NOT, [new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mimetype', ICacheEntry::DIRECTORY_MIMETYPE)]),
  871. ]);
  872. $query = new SearchQuery($operator, $limit, $offset, $ordering);
  873. $result = $node->search($query);
  874. $cache->clear();
  875. $subCache1->clear();
  876. $subCache2->clear();
  877. $ids = array_map(function (Node $info) {
  878. return $info->getPath();
  879. }, $result);
  880. $this->assertEquals($expectedPaths, $ids);
  881. }
  882. }