]> source.dussan.org Git - nextcloud-server.git/commitdiff
Provide an implementation of the fileapi for oc6 build on top of the old api
authorRobin Appelman <icewind@owncloud.com>
Sun, 1 Sep 2013 17:47:48 +0000 (19:47 +0200)
committerRobin Appelman <icewind@owncloud.com>
Sun, 1 Sep 2013 17:47:48 +0000 (19:47 +0200)
13 files changed:
lib/files/exceptions.php [new file with mode: 0644]
lib/files/node/file.php [new file with mode: 0644]
lib/files/node/folder.php [new file with mode: 0644]
lib/files/node/node.php [new file with mode: 0644]
lib/files/node/nonexistingfile.php [new file with mode: 0644]
lib/files/node/nonexistingfolder.php [new file with mode: 0644]
lib/files/node/root.php [new file with mode: 0644]
lib/files/view.php
tests/lib/files/node/file.php [new file with mode: 0644]
tests/lib/files/node/folder.php [new file with mode: 0644]
tests/lib/files/node/integration.php [new file with mode: 0644]
tests/lib/files/node/node.php [new file with mode: 0644]
tests/lib/files/node/root.php [new file with mode: 0644]

diff --git a/lib/files/exceptions.php b/lib/files/exceptions.php
new file mode 100644 (file)
index 0000000..8a3c40a
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\Files;
+
+class NotFoundException extends \Exception {
+}
+
+class NotPermittedException extends \Exception {
+}
+
+class AlreadyExistsException extends \Exception {
+}
+
+class NotEnoughSpaceException extends \Exception {
+}
diff --git a/lib/files/node/file.php b/lib/files/node/file.php
new file mode 100644 (file)
index 0000000..0ad5d68
--- /dev/null
@@ -0,0 +1,155 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\Files\Node;
+
+use OC\Files\NotPermittedException;
+
+class File extends Node {
+       /**
+        * @return string
+        * @throws \OC\Files\NotPermittedException
+        */
+       public function getContent() {
+               if ($this->checkPermissions(\OCP\PERMISSION_READ)) {
+                       /**
+                        * @var \OC\Files\Storage\Storage $storage;
+                        */
+                       return $this->view->file_get_contents($this->path);
+               } else {
+                       throw new NotPermittedException();
+               }
+       }
+
+       /**
+        * @param string $data
+        * @throws \OC\Files\NotPermittedException
+        */
+       public function putContent($data) {
+               if ($this->checkPermissions(\OCP\PERMISSION_UPDATE)) {
+                       $this->sendHooks(array('preWrite'));
+                       $this->view->file_put_contents($this->path, $data);
+                       $this->sendHooks(array('postWrite'));
+               } else {
+                       throw new NotPermittedException();
+               }
+       }
+
+       /**
+        * @return string
+        */
+       public function getMimeType() {
+               return $this->view->getMimeType($this->path);
+       }
+
+       /**
+        * @param string $mode
+        * @return resource
+        * @throws \OC\Files\NotPermittedException
+        */
+       public function fopen($mode) {
+               $preHooks = array();
+               $postHooks = array();
+               $requiredPermissions = \OCP\PERMISSION_READ;
+               switch ($mode) {
+                       case 'r+':
+                       case 'rb+':
+                       case 'w+':
+                       case 'wb+':
+                       case 'x+':
+                       case 'xb+':
+                       case 'a+':
+                       case 'ab+':
+                       case 'w':
+                       case 'wb':
+                       case 'x':
+                       case 'xb':
+                       case 'a':
+                       case 'ab':
+                               $preHooks[] = 'preWrite';
+                               $postHooks[] = 'postWrite';
+                               $requiredPermissions |= \OCP\PERMISSION_UPDATE;
+                               break;
+               }
+
+               if ($this->checkPermissions($requiredPermissions)) {
+                       $this->sendHooks($preHooks);
+                       $result = $this->view->fopen($this->path, $mode);
+                       $this->sendHooks($postHooks);
+                       return $result;
+               } else {
+                       throw new NotPermittedException();
+               }
+       }
+
+       public function delete() {
+               if ($this->checkPermissions(\OCP\PERMISSION_DELETE)) {
+                       $this->sendHooks(array('preDelete'));
+                       $this->view->unlink($this->path);
+                       $nonExisting = new NonExistingFile($this->root, $this->view, $this->path);
+                       $this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
+                       $this->exists = false;
+               } else {
+                       throw new NotPermittedException();
+               }
+       }
+
+       /**
+        * @param string $targetPath
+        * @throws \OC\Files\NotPermittedException
+        * @return \OC\Files\Node\Node
+        */
+       public function copy($targetPath) {
+               $targetPath = $this->normalizePath($targetPath);
+               $parent = $this->root->get(dirname($targetPath));
+               if ($parent instanceof Folder and $this->isValidPath($targetPath) and $parent->isCreatable()) {
+                       $nonExisting = new NonExistingFile($this->root, $this->view, $targetPath);
+                       $this->root->emit('\OC\Files', 'preCopy', array($this, $nonExisting));
+                       $this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
+                       $this->view->copy($this->path, $targetPath);
+                       $targetNode = $this->root->get($targetPath);
+                       $this->root->emit('\OC\Files', 'postCopy', array($this, $targetNode));
+                       $this->root->emit('\OC\Files', 'postWrite', array($targetNode));
+                       return $targetNode;
+               } else {
+                       throw new NotPermittedException();
+               }
+       }
+
+       /**
+        * @param string $targetPath
+        * @throws \OC\Files\NotPermittedException
+        * @return \OC\Files\Node\Node
+        */
+       public function move($targetPath) {
+               $targetPath = $this->normalizePath($targetPath);
+               $parent = $this->root->get(dirname($targetPath));
+               if ($parent instanceof Folder and $this->isValidPath($targetPath) and $parent->isCreatable()) {
+                       $nonExisting = new NonExistingFile($this->root, $this->view, $targetPath);
+                       $this->root->emit('\OC\Files', 'preRename', array($this, $nonExisting));
+                       $this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
+                       $this->view->rename($this->path, $targetPath);
+                       $targetNode = $this->root->get($targetPath);
+                       $this->root->emit('\OC\Files', 'postRename', array($this, $targetNode));
+                       $this->root->emit('\OC\Files', 'postWrite', array($targetNode));
+                       $this->path = $targetPath;
+                       return $targetNode;
+               } else {
+                       throw new NotPermittedException();
+               }
+       }
+
+       /**
+        * @param string $type
+        * @param bool $raw
+        * @return string
+        */
+       public function hash($type, $raw = false) {
+               return $this->view->hash($type, $this->path, $raw);
+       }
+}
diff --git a/lib/files/node/folder.php b/lib/files/node/folder.php
new file mode 100644 (file)
index 0000000..f710ae5
--- /dev/null
@@ -0,0 +1,382 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\Files\Node;
+
+use OC\Files\Cache\Cache;
+use OC\Files\Cache\Scanner;
+use OC\Files\NotFoundException;
+use OC\Files\NotPermittedException;
+
+class Folder extends Node {
+       /**
+        * @param string $path path relative to the folder
+        * @return string
+        * @throws \OC\Files\NotPermittedException
+        */
+       public function getFullPath($path) {
+               if (!$this->isValidPath($path)) {
+                       throw new NotPermittedException();
+               }
+               return $this->path . $this->normalizePath($path);
+       }
+
+       /**
+        * @param string $path
+        * @throws \OC\Files\NotFoundException
+        * @return string
+        */
+       public function getRelativePath($path) {
+               if ($this->path === '' or $this->path === '/') {
+                       return $this->normalizePath($path);
+               }
+               if (strpos($path, $this->path) !== 0) {
+                       throw new NotFoundException();
+               } else {
+                       $path = substr($path, strlen($this->path));
+                       if (strlen($path) === 0) {
+                               return '/';
+                       } else {
+                               return $this->normalizePath($path);
+                       }
+               }
+       }
+
+       /**
+        * check if a node is a (grand-)child of the folder
+        *
+        * @param \OC\Files\Node\Node $node
+        * @return bool
+        */
+       public function isSubNode($node) {
+               return strpos($node->getPath(), $this->path . '/') === 0;
+       }
+
+       /**
+        * get the content of this directory
+        *
+        * @throws \OC\Files\NotFoundException
+        * @return Node[]
+        */
+       public function getDirectoryListing() {
+               $result = array();
+
+               /**
+                * @var \OC\Files\Storage\Storage $storage
+                */
+               list($storage, $internalPath) = $this->view->resolvePath($this->path);
+               if ($storage) {
+                       $cache = $storage->getCache($internalPath);
+                       $permissionsCache = $storage->getPermissionsCache($internalPath);
+
+                       //trigger cache update check
+                       $this->view->getFileInfo($this->path);
+
+                       $files = $cache->getFolderContents($internalPath);
+                       $permissions = $permissionsCache->getDirectoryPermissions($this->getId(), $this->root->getUser()->getUID());
+               } else {
+                       $files = array();
+               }
+
+               //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders
+               $mounts = $this->root->getMountsIn($this->path);
+               $dirLength = strlen($this->path);
+               foreach ($mounts as $mount) {
+                       $subStorage = $mount->getStorage();
+                       if ($subStorage) {
+                               $subCache = $subStorage->getCache('');
+
+                               if ($subCache->getStatus('') === Cache::NOT_FOUND) {
+                                       $subScanner = $subStorage->getScanner('');
+                                       $subScanner->scanFile('');
+                               }
+
+                               $rootEntry = $subCache->get('');
+                               if ($rootEntry) {
+                                       $relativePath = trim(substr($mount->getMountPoint(), $dirLength), '/');
+                                       if ($pos = strpos($relativePath, '/')) {
+                                               //mountpoint inside subfolder add size to the correct folder
+                                               $entryName = substr($relativePath, 0, $pos);
+                                               foreach ($files as &$entry) {
+                                                       if ($entry['name'] === $entryName) {
+                                                               if ($rootEntry['size'] >= 0) {
+                                                                       $entry['size'] += $rootEntry['size'];
+                                                               } else {
+                                                                       $entry['size'] = -1;
+                                                               }
+                                                       }
+                                               }
+                                       } else { //mountpoint in this folder, add an entry for it
+                                               $rootEntry['name'] = $relativePath;
+                                               $rootEntry['storageObject'] = $subStorage;
+
+                                               //remove any existing entry with the same name
+                                               foreach ($files as $i => $file) {
+                                                       if ($file['name'] === $rootEntry['name']) {
+                                                               $files[$i] = null;
+                                                               break;
+                                                       }
+                                               }
+                                               $files[] = $rootEntry;
+                                       }
+                               }
+                       }
+               }
+
+               foreach ($files as $file) {
+                       if ($file) {
+                               if (isset($permissions[$file['fileid']])) {
+                                       $file['permissions'] = $permissions[$file['fileid']];
+                               }
+                               $node = $this->createNode($this->path . '/' . $file['name'], $file);
+                               $result[] = $node;
+                       }
+               }
+
+               return $result;
+       }
+
+       /**
+        * @param string $path
+        * @param array $info
+        * @return File|Folder
+        */
+       protected function createNode($path, $info = array()) {
+               if (!isset($info['mimetype'])) {
+                       $isDir = $this->view->is_dir($path);
+               } else {
+                       $isDir = $info['mimetype'] === 'httpd/unix-directory';
+               }
+               if ($isDir) {
+                       return new Folder($this->root, $this->view, $path);
+               } else {
+                       return new File($this->root, $this->view, $path);
+               }
+       }
+
+       /**
+        * Get the node at $path
+        *
+        * @param string $path
+        * @return \OC\Files\Node\Node
+        * @throws \OC\Files\NotFoundException
+        */
+       public function get($path) {
+               return $this->root->get($this->getFullPath($path));
+       }
+
+       /**
+        * @param string $path
+        * @return bool
+        */
+       public function nodeExists($path) {
+               try {
+                       $this->get($path);
+                       return true;
+               } catch (NotFoundException $e) {
+                       return false;
+               }
+       }
+
+       /**
+        * @param string $path
+        * @return Folder
+        * @throws NotPermittedException
+        */
+       public function newFolder($path) {
+               if ($this->checkPermissions(\OCP\PERMISSION_CREATE)) {
+                       $fullPath = $this->getFullPath($path);
+                       $nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath);
+                       $this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
+                       $this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
+                       $this->view->mkdir($fullPath);
+                       $node = new Folder($this->root, $this->view, $fullPath);
+                       $this->root->emit('\OC\Files', 'postWrite', array($node));
+                       $this->root->emit('\OC\Files', 'postCreate', array($node));
+                       return $node;
+               } else {
+                       throw new NotPermittedException();
+               }
+       }
+
+       /**
+        * @param string $path
+        * @return File
+        * @throws NotPermittedException
+        */
+       public function newFile($path) {
+               if ($this->checkPermissions(\OCP\PERMISSION_CREATE)) {
+                       $fullPath = $this->getFullPath($path);
+                       $nonExisting = new NonExistingFile($this->root, $this->view, $fullPath);
+                       $this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
+                       $this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
+                       $this->view->touch($fullPath);
+                       $node = new File($this->root, $this->view, $fullPath);
+                       $this->root->emit('\OC\Files', 'postWrite', array($node));
+                       $this->root->emit('\OC\Files', 'postCreate', array($node));
+                       return $node;
+               } else {
+                       throw new NotPermittedException();
+               }
+       }
+
+       /**
+        * search for files with the name matching $query
+        *
+        * @param string $query
+        * @return Node[]
+        */
+       public function search($query) {
+               return $this->searchCommon('%' . $query . '%', 'search');
+       }
+
+       /**
+        * search for files by mimetype
+        *
+        * @param string $mimetype
+        * @return Node[]
+        */
+       public function searchByMime($mimetype) {
+               return $this->searchCommon($mimetype, 'searchByMime');
+       }
+
+       /**
+        * @param string $query
+        * @param string $method
+        * @return Node[]
+        */
+       private function searchCommon($query, $method) {
+               $files = array();
+               $rootLength = strlen($this->path);
+               /**
+                * @var \OC\Files\Storage\Storage $storage
+                */
+               list($storage, $internalPath) = $this->view->resolvePath($this->path);
+               $internalRootLength = strlen($internalPath);
+
+               $cache = $storage->getCache('');
+
+               $results = $cache->$method($query);
+               foreach ($results as $result) {
+                       if ($internalRootLength === 0 or substr($result['path'], 0, $internalRootLength) === $internalPath) {
+                               $result['internalPath'] = $result['path'];
+                               $result['path'] = substr($result['path'], $internalRootLength);
+                               $result['storage'] = $storage;
+                               $files[] = $result;
+                       }
+               }
+
+               $mounts = $this->root->getMountsIn($this->path);
+               foreach ($mounts as $mount) {
+                       $storage = $mount->getStorage();
+                       if ($storage) {
+                               $cache = $storage->getCache('');
+
+                               $relativeMountPoint = substr($mount->getMountPoint(), $rootLength);
+                               $results = $cache->$method($query);
+                               foreach ($results as $result) {
+                                       $result['internalPath'] = $result['path'];
+                                       $result['path'] = $relativeMountPoint . $result['path'];
+                                       $result['storage'] = $storage;
+                                       $files[] = $result;
+                               }
+                       }
+               }
+
+               $result = array();
+               foreach ($files as $file) {
+                       $result[] = $this->createNode($this->normalizePath($this->path . '/' . $file['path']), $file);
+               }
+
+               return $result;
+       }
+
+       /**
+        * @param $id
+        * @return Node[]
+        */
+       public function getById($id) {
+               $nodes = $this->root->getById($id);
+               $result = array();
+               foreach ($nodes as $node) {
+                       $pathPart = substr($node->getPath(), 0, strlen($this->getPath()) + 1);
+                       if ($this->path === '/' or $pathPart === $this->getPath() . '/') {
+                               $result[] = $node;
+                       }
+               }
+               return $result;
+       }
+
+       public function getFreeSpace() {
+               return $this->view->free_space($this->path);
+       }
+
+       /**
+        * @return bool
+        */
+       public function isCreatable() {
+               return $this->checkPermissions(\OCP\PERMISSION_CREATE);
+       }
+
+       public function delete() {
+               if ($this->checkPermissions(\OCP\PERMISSION_DELETE)) {
+                       $this->sendHooks(array('preDelete'));
+                       $this->view->rmdir($this->path);
+                       $nonExisting = new NonExistingFolder($this->root, $this->view, $this->path);
+                       $this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
+                       $this->exists = false;
+               } else {
+                       throw new NotPermittedException();
+               }
+       }
+
+       /**
+        * @param string $targetPath
+        * @throws \OC\Files\NotPermittedException
+        * @return \OC\Files\Node\Node
+        */
+       public function copy($targetPath) {
+               $targetPath = $this->normalizePath($targetPath);
+               $parent = $this->root->get(dirname($targetPath));
+               if ($parent instanceof Folder and $this->isValidPath($targetPath) and $parent->isCreatable()) {
+                       $nonExisting = new NonExistingFolder($this->root, $this->view, $targetPath);
+                       $this->root->emit('\OC\Files', 'preCopy', array($this, $nonExisting));
+                       $this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
+                       $this->view->copy($this->path, $targetPath);
+                       $targetNode = $this->root->get($targetPath);
+                       $this->root->emit('\OC\Files', 'postCopy', array($this, $targetNode));
+                       $this->root->emit('\OC\Files', 'postWrite', array($targetNode));
+                       return $targetNode;
+               } else {
+                       throw new NotPermittedException();
+               }
+       }
+
+       /**
+        * @param string $targetPath
+        * @throws \OC\Files\NotPermittedException
+        * @return \OC\Files\Node\Node
+        */
+       public function move($targetPath) {
+               $targetPath = $this->normalizePath($targetPath);
+               $parent = $this->root->get(dirname($targetPath));
+               if ($parent instanceof Folder and $this->isValidPath($targetPath) and $parent->isCreatable()) {
+                       $nonExisting = new NonExistingFolder($this->root, $this->view, $targetPath);
+                       $this->root->emit('\OC\Files', 'preRename', array($this, $nonExisting));
+                       $this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
+                       $this->view->rename($this->path, $targetPath);
+                       $targetNode = $this->root->get($targetPath);
+                       $this->root->emit('\OC\Files', 'postRename', array($this, $targetNode));
+                       $this->root->emit('\OC\Files', 'postWrite', array($targetNode));
+                       $this->path = $targetPath;
+                       return $targetNode;
+               } else {
+                       throw new NotPermittedException();
+               }
+       }
+}
diff --git a/lib/files/node/node.php b/lib/files/node/node.php
new file mode 100644 (file)
index 0000000..a71f787
--- /dev/null
@@ -0,0 +1,247 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\Files\Node;
+
+use OC\Files\Cache\Cache;
+use OC\Files\Cache\Scanner;
+use OC\Files\NotFoundException;
+use OC\Files\NotPermittedException;
+
+require_once 'files/exceptions.php';
+
+class Node {
+       /**
+        * @var \OC\Files\View $view
+        */
+       protected $view;
+
+       /**
+        * @var \OC\Files\Node\Root $root
+        */
+       protected $root;
+
+       /**
+        * @var string $path
+        */
+       protected $path;
+
+       /**
+        * @param \OC\Files\View $view
+        * @param \OC\Files\Node\Root Root $root
+        * @param string $path
+        */
+       public function __construct($root, $view, $path) {
+               $this->view = $view;
+               $this->root = $root;
+               $this->path = $path;
+       }
+
+       /**
+        * @param string[] $hooks
+        */
+       protected function sendHooks($hooks) {
+               foreach ($hooks as $hook) {
+                       $this->root->emit('\OC\Files', $hook, array($this));
+               }
+       }
+
+       /**
+        * @param int $permissions
+        * @return bool
+        */
+       protected function checkPermissions($permissions) {
+               return ($this->getPermissions() & $permissions) == $permissions;
+       }
+
+       /**
+        * @param string $targetPath
+        * @throws \OC\Files\NotPermittedException
+        * @return \OC\Files\Node\Node
+        */
+       public function move($targetPath) {
+               return;
+       }
+
+       public function delete() {
+               return;
+       }
+
+       /**
+        * @param string $targetPath
+        * @return \OC\Files\Node\Node
+        */
+       public function copy($targetPath) {
+               return;
+       }
+
+       /**
+        * @param int $mtime
+        * @throws \OC\Files\NotPermittedException
+        */
+       public function touch($mtime = null) {
+               if ($this->checkPermissions(\OCP\PERMISSION_UPDATE)) {
+                       $this->sendHooks(array('preTouch'));
+                       $this->view->touch($this->path, $mtime);
+                       $this->sendHooks(array('postTouch'));
+               } else {
+                       throw new NotPermittedException();
+               }
+       }
+
+       /**
+        * @return \OC\Files\Storage\Storage
+        * @throws \OC\Files\NotFoundException
+        */
+       public function getStorage() {
+               list($storage,) = $this->view->resolvePath($this->path);
+               return $storage;
+       }
+
+       /**
+        * @return string
+        */
+       public function getPath() {
+               return $this->path;
+       }
+
+       /**
+        * @return string
+        */
+       public function getInternalPath() {
+               list(, $internalPath) = $this->view->resolvePath($this->path);
+               return $internalPath;
+       }
+
+       /**
+        * @return int
+        */
+       public function getId() {
+               $info = $this->view->getFileInfo($this->path);
+               return $info['fileid'];
+       }
+
+       /**
+        * @return array
+        */
+       public function stat() {
+               return $this->view->stat($this->path);
+       }
+
+       /**
+        * @return int
+        */
+       public function getMTime() {
+               return $this->view->filemtime($this->path);
+       }
+
+       /**
+        * @return int
+        */
+       public function getSize() {
+               return $this->view->filesize($this->path);
+       }
+
+       /**
+        * @return string
+        */
+       public function getEtag() {
+               $info = $this->view->getFileInfo($this->path);
+               return $info['etag'];
+       }
+
+       /**
+        * @return int
+        */
+       public function getPermissions() {
+               $info = $this->view->getFileInfo($this->path);
+               return $info['permissions'];
+       }
+
+       /**
+        * @return bool
+        */
+       public function isReadable() {
+               return $this->checkPermissions(\OCP\PERMISSION_READ);
+       }
+
+       /**
+        * @return bool
+        */
+       public function isUpdateable() {
+               return $this->checkPermissions(\OCP\PERMISSION_UPDATE);
+       }
+
+       /**
+        * @return bool
+        */
+       public function isDeletable() {
+               return $this->checkPermissions(\OCP\PERMISSION_DELETE);
+       }
+
+       /**
+        * @return bool
+        */
+       public function isShareable() {
+               return $this->checkPermissions(\OCP\PERMISSION_SHARE);
+       }
+
+       /**
+        * @return Node
+        */
+       public function getParent() {
+               return $this->root->get(dirname($this->path));
+       }
+
+       /**
+        * @return string
+        */
+       public function getName() {
+               return basename($this->path);
+       }
+
+       /**
+        * @param string $path
+        * @return string
+        */
+       protected function normalizePath($path) {
+               if ($path === '' or $path === '/') {
+                       return '/';
+               }
+               //no windows style slashes
+               $path = str_replace('\\', '/', $path);
+               //add leading slash
+               if ($path[0] !== '/') {
+                       $path = '/' . $path;
+               }
+               //remove duplicate slashes
+               while (strpos($path, '//') !== false) {
+                       $path = str_replace('//', '/', $path);
+               }
+               //remove trailing slash
+               $path = rtrim($path, '/');
+
+               return $path;
+       }
+
+       /**
+        * check if the requested path is valid
+        *
+        * @param string $path
+        * @return bool
+        */
+       public function isValidPath($path) {
+               if (!$path || $path[0] !== '/') {
+                       $path = '/' . $path;
+               }
+               if (strstr($path, '/../') || strrchr($path, '/') === '/..') {
+                       return false;
+               }
+               return true;
+       }
+}
diff --git a/lib/files/node/nonexistingfile.php b/lib/files/node/nonexistingfile.php
new file mode 100644 (file)
index 0000000..6f18450
--- /dev/null
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\Files\Node;
+
+use OC\Files\NotFoundException;
+
+class NonExistingFile extends File {
+       /**
+        * @param string $newPath
+        * @throws \OC\Files\NotFoundException
+        */
+       public function rename($newPath) {
+               throw new NotFoundException();
+       }
+
+       public function delete() {
+               throw new NotFoundException();
+       }
+
+       public function copy($newPath) {
+               throw new NotFoundException();
+       }
+
+       public function touch($mtime = null) {
+               throw new NotFoundException();
+       }
+
+       public function getId() {
+               throw new NotFoundException();
+       }
+
+       public function stat() {
+               throw new NotFoundException();
+       }
+
+       public function getMTime() {
+               throw new NotFoundException();
+       }
+
+       public function getSize() {
+               throw new NotFoundException();
+       }
+
+       public function getEtag() {
+               throw new NotFoundException();
+       }
+
+       public function getPermissions() {
+               throw new NotFoundException();
+       }
+
+       public function isReadable() {
+               throw new NotFoundException();
+       }
+
+       public function isUpdateable() {
+               throw new NotFoundException();
+       }
+
+       public function isDeletable() {
+               throw new NotFoundException();
+       }
+
+       public function isShareable() {
+               throw new NotFoundException();
+       }
+
+       public function getContent() {
+               throw new NotFoundException();
+       }
+
+       public function putContent($data) {
+               throw new NotFoundException();
+       }
+
+       public function getMimeType() {
+               throw new NotFoundException();
+       }
+
+       public function fopen($mode) {
+               throw new NotFoundException();
+       }
+}
diff --git a/lib/files/node/nonexistingfolder.php b/lib/files/node/nonexistingfolder.php
new file mode 100644 (file)
index 0000000..0249a02
--- /dev/null
@@ -0,0 +1,113 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\Files\Node;
+
+use OC\Files\NotFoundException;
+
+class NonExistingFolder extends Folder {
+       /**
+        * @param string $newPath
+        * @throws \OC\Files\NotFoundException
+        */
+       public function rename($newPath) {
+               throw new NotFoundException();
+       }
+
+       public function delete() {
+               throw new NotFoundException();
+       }
+
+       public function copy($newPath) {
+               throw new NotFoundException();
+       }
+
+       public function touch($mtime = null) {
+               throw new NotFoundException();
+       }
+
+       public function getId() {
+               throw new NotFoundException();
+       }
+
+       public function stat() {
+               throw new NotFoundException();
+       }
+
+       public function getMTime() {
+               throw new NotFoundException();
+       }
+
+       public function getSize() {
+               throw new NotFoundException();
+       }
+
+       public function getEtag() {
+               throw new NotFoundException();
+       }
+
+       public function getPermissions() {
+               throw new NotFoundException();
+       }
+
+       public function isReadable() {
+               throw new NotFoundException();
+       }
+
+       public function isUpdateable() {
+               throw new NotFoundException();
+       }
+
+       public function isDeletable() {
+               throw new NotFoundException();
+       }
+
+       public function isShareable() {
+               throw new NotFoundException();
+       }
+
+       public function get($path) {
+               throw new NotFoundException();
+       }
+
+       public function getDirectoryListing() {
+               throw new NotFoundException();
+       }
+
+       public function nodeExists($path) {
+               return false;
+       }
+
+       public function newFolder($path) {
+               throw new NotFoundException();
+       }
+
+       public function newFile($path) {
+               throw new NotFoundException();
+       }
+
+       public function search($pattern) {
+               throw new NotFoundException();
+       }
+
+       public function searchByMime($mime) {
+               throw new NotFoundException();
+       }
+
+       public function getById($id) {
+               throw new NotFoundException();
+       }
+
+       public function getFreeSpace() {
+               throw new NotFoundException();
+       }
+
+       public function isCreatable() {
+               throw new NotFoundException();
+       }
+}
diff --git a/lib/files/node/root.php b/lib/files/node/root.php
new file mode 100644 (file)
index 0000000..f88d8c2
--- /dev/null
@@ -0,0 +1,337 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\Files\Node;
+
+use OC\Files\Cache\Cache;
+use OC\Files\Cache\Scanner;
+use OC\Files\Mount\Manager;
+use OC\Files\Mount\Mount;
+use OC\Files\NotFoundException;
+use OC\Files\NotPermittedException;
+use OC\Hooks\Emitter;
+use OC\Hooks\PublicEmitter;
+
+/**
+ * Class Root
+ *
+ * Hooks available in scope \OC\Files
+ * - preWrite(\OC\Files\Node\Node $node)
+ * - postWrite(\OC\Files\Node\Node $node)
+ * - preCreate(\OC\Files\Node\Node $node)
+ * - postCreate(\OC\Files\Node\Node $node)
+ * - preDelete(\OC\Files\Node\Node $node)
+ * - postDelete(\OC\Files\Node\Node $node)
+ * - preTouch(\OC\Files\Node\Node $node, int $mtime)
+ * - postTouch(\OC\Files\Node\Node $node)
+ * - preCopy(\OC\Files\Node\Node $source, \OC\Files\Node\Node $target)
+ * - postCopy(\OC\Files\Node\Node $source, \OC\Files\Node\Node $target)
+ * - preRename(\OC\Files\Node\Node $source, \OC\Files\Node\Node $target)
+ * - postRename(\OC\Files\Node\Node $source, \OC\Files\Node\Node $target)
+ *
+ * @package OC\Files\Node
+ */
+class Root extends Folder implements Emitter {
+
+       /**
+        * @var \OC\Files\Mount\Manager $mountManager
+        */
+       private $mountManager;
+
+       /**
+        * @var \OC\Hooks\PublicEmitter
+        */
+       private $emitter;
+
+       /**
+        * @var \OC\User\User $user
+        */
+       private $user;
+
+       /**
+        * @param \OC\Files\Mount\Manager $manager
+        * @param \OC\Files\View $view
+        * @param \OC\User\User $user
+        */
+       public function __construct($manager, $view, $user) {
+               parent::__construct($this, $view, '');
+               $this->mountManager = $manager;
+               $this->user = $user;
+               $this->emitter = new PublicEmitter();
+       }
+
+       /**
+        * Get the user for which the filesystem is setup
+        *
+        * @return \OC\User\User
+        */
+       public function getUser() {
+               return $this->user;
+       }
+
+       /**
+        * @param string $scope
+        * @param string $method
+        * @param callable $callback
+        */
+       public function listen($scope, $method, $callback) {
+               $this->emitter->listen($scope, $method, $callback);
+       }
+
+       /**
+        * @param string $scope optional
+        * @param string $method optional
+        * @param callable $callback optional
+        */
+       public function removeListener($scope = null, $method = null, $callback = null) {
+               $this->emitter->removeListener($scope, $method, $callback);
+       }
+
+       /**
+        * @param string $scope
+        * @param string $method
+        * @param array $arguments
+        */
+       public function emit($scope, $method, $arguments = array()) {
+               $this->emitter->emit($scope, $method, $arguments);
+       }
+
+       /**
+        * @param \OC\Files\Storage\Storage $storage
+        * @param string $mountPoint
+        * @param array $arguments
+        */
+       public function mount($storage, $mountPoint, $arguments = array()) {
+               $mount = new Mount($storage, $mountPoint, $arguments);
+               $this->mountManager->addMount($mount);
+       }
+
+       /**
+        * @param string $mountPoint
+        * @return \OC\Files\Mount\Mount
+        */
+       public function getMount($mountPoint) {
+               return $this->mountManager->find($mountPoint);
+       }
+
+       /**
+        * @param string $mountPoint
+        * @return \OC\Files\Mount\Mount[]
+        */
+       public function getMountsIn($mountPoint) {
+               return $this->mountManager->findIn($mountPoint);
+       }
+
+       /**
+        * @param string $storageId
+        * @return \OC\Files\Mount\Mount[]
+        */
+       public function getMountByStorageId($storageId) {
+               return $this->mountManager->findByStorageId($storageId);
+       }
+
+       /**
+        * @param int $numericId
+        * @return Mount[]
+        */
+       public function getMountByNumericStorageId($numericId) {
+               return $this->mountManager->findByNumericId($numericId);
+       }
+
+       /**
+        * @param \OC\Files\Mount\Mount $mount
+        */
+       public function unMount($mount) {
+               $this->mountManager->remove($mount);
+       }
+
+       /**
+        * @param string $path
+        * @throws \OC\Files\NotFoundException
+        * @throws \OC\Files\NotPermittedException
+        * @return Node
+        */
+       public function get($path) {
+               $path = $this->normalizePath($path);
+               if ($this->isValidPath($path)) {
+                       $fullPath = $this->getFullPath($path);
+                       if ($this->view->file_exists($fullPath)) {
+                               return $this->createNode($fullPath);
+                       } else {
+                               throw new NotFoundException();
+                       }
+               } else {
+                       throw new NotPermittedException();
+               }
+       }
+
+       /**
+        * search file by id
+        *
+        * An array is returned because in the case where a single storage is mounted in different places the same file
+        * can exist in different places
+        *
+        * @param int $id
+        * @throws \OC\Files\NotFoundException
+        * @return Node[]
+        */
+       public function getById($id) {
+               $result = Cache::getById($id);
+               if (is_null($result)) {
+                       throw new NotFoundException();
+               } else {
+                       list($storageId, $internalPath) = $result;
+                       $nodes = array();
+                       $mounts = $this->mountManager->findByStorageId($storageId);
+                       foreach ($mounts as $mount) {
+                               $nodes[] = $this->get($mount->getMountPoint() . $internalPath);
+                       }
+                       return $nodes;
+               }
+
+       }
+
+       //most operations cant be done on the root
+
+       /**
+        * @param string $targetPath
+        * @throws \OC\Files\NotPermittedException
+        * @return \OC\Files\Node\Node
+        */
+       public function rename($targetPath) {
+               throw new NotPermittedException();
+       }
+
+       public function delete() {
+               throw new NotPermittedException();
+       }
+
+       /**
+        * @param string $targetPath
+        * @throws \OC\Files\NotPermittedException
+        * @return \OC\Files\Node\Node
+        */
+       public function copy($targetPath) {
+               throw new NotPermittedException();
+       }
+
+       /**
+        * @param int $mtime
+        * @throws \OC\Files\NotPermittedException
+        */
+       public function touch($mtime = null) {
+               throw new NotPermittedException();
+       }
+
+       /**
+        * @return \OC\Files\Storage\Storage
+        * @throws \OC\Files\NotFoundException
+        */
+       public function getStorage() {
+               throw new NotFoundException();
+       }
+
+       /**
+        * @return string
+        */
+       public function getPath() {
+               return '/';
+       }
+
+       /**
+        * @return string
+        */
+       public function getInternalPath() {
+               return '';
+       }
+
+       /**
+        * @return int
+        */
+       public function getId() {
+               return null;
+       }
+
+       /**
+        * @return array
+        */
+       public function stat() {
+               return null;
+       }
+
+       /**
+        * @return int
+        */
+       public function getMTime() {
+               return null;
+       }
+
+       /**
+        * @return int
+        */
+       public function getSize() {
+               return null;
+       }
+
+       /**
+        * @return string
+        */
+       public function getEtag() {
+               return null;
+       }
+
+       /**
+        * @return int
+        */
+       public function getPermissions() {
+               return \OCP\PERMISSION_CREATE;
+       }
+
+       /**
+        * @return bool
+        */
+       public function isReadable() {
+               return false;
+       }
+
+       /**
+        * @return bool
+        */
+       public function isUpdateable() {
+               return false;
+       }
+
+       /**
+        * @return bool
+        */
+       public function isDeletable() {
+               return false;
+       }
+
+       /**
+        * @return bool
+        */
+       public function isShareable() {
+               return false;
+       }
+
+       /**
+        * @return Node
+        * @throws \OC\Files\NotFoundException
+        */
+       public function getParent() {
+               throw new NotFoundException();
+       }
+
+       /**
+        * @return string
+        */
+       public function getName() {
+               return '';
+       }
+}
index 8aee12bf6fe2b157e490a40beb2697383032e6ae..3a1fdd415b3e2013bb8f92f72c2b10fc84e44c36 100644 (file)
@@ -30,7 +30,7 @@ class View {
        private $internal_path_cache = array();
        private $storage_cache = array();
 
-       public function __construct($root) {
+       public function __construct($root = '') {
                $this->fakeRoot = $root;
        }
 
diff --git a/tests/lib/files/node/file.php b/tests/lib/files/node/file.php
new file mode 100644 (file)
index 0000000..7071063
--- /dev/null
@@ -0,0 +1,664 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\Files\Node;
+
+use OC\Files\NotFoundException;
+use OC\Files\NotPermittedException;
+use OC\Files\View;
+
+class File extends \PHPUnit_Framework_TestCase {
+       private $user;
+
+       public function setUp() {
+               $this->user = new \OC\User\User('', new \OC_User_Dummy);
+       }
+
+       public function testDelete() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->exactly(2))
+                       ->method('emit')
+                       ->will($this->returnValue(true));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL)));
+
+               $view->expects($this->once())
+                       ->method('unlink')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(true));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $node->delete();
+       }
+
+       public function testDeleteHooks() {
+               $test = $this;
+               $hooksRun = 0;
+               /**
+                * @param \OC\Files\Node\File $node
+                */
+               $preListener = function ($node) use (&$test, &$hooksRun) {
+                       $test->assertInstanceOf('\OC\Files\Node\File', $node);
+                       $test->assertEquals('foo', $node->getInternalPath());
+                       $test->assertEquals('/bar/foo', $node->getPath());
+                       $test->assertEquals(1, $node->getId());
+                       $hooksRun++;
+               };
+
+               /**
+                * @param \OC\Files\Node\File $node
+                */
+               $postListener = function ($node) use (&$test, &$hooksRun) {
+                       $test->assertInstanceOf('\OC\Files\Node\NonExistingFile', $node);
+                       $test->assertEquals('foo', $node->getInternalPath());
+                       $test->assertEquals('/bar/foo', $node->getPath());
+                       $hooksRun++;
+               };
+
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = new \OC\Files\Node\Root($manager, $view, $this->user);
+               $root->listen('\OC\Files', 'preDelete', $preListener);
+               $root->listen('\OC\Files', 'postDelete', $postListener);
+
+               $view->expects($this->any())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL, 'fileid' => 1)));
+
+               $view->expects($this->once())
+                       ->method('unlink')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(true));
+
+               $view->expects($this->any())
+                       ->method('resolvePath')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array(null, 'foo')));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $node->delete();
+               $this->assertEquals(2, $hooksRun);
+       }
+
+       /**
+        * @expectedException \OC\Files\NotPermittedException
+        */
+       public function testDeleteNotPermitted() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ)));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $node->delete();
+       }
+
+       public function testGetContent() {
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = new \OC\Files\Node\Root($manager, $view, $this->user);
+
+               $hook = function ($file) {
+                       throw new \Exception('Hooks are not supposed to be called');
+               };
+
+               $root->listen('\OC\Files', 'preWrite', $hook);
+               $root->listen('\OC\Files', 'postWrite', $hook);
+
+               $view->expects($this->once())
+                       ->method('file_get_contents')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue('bar'));
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ)));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $this->assertEquals('bar', $node->getContent());
+       }
+
+       /**
+        * @expectedException \OC\Files\NotPermittedException
+        */
+       public function testGetContentNotPermitted() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => 0)));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $node->getContent();
+       }
+
+       public function testPutContent() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL)));
+
+               $view->expects($this->once())
+                       ->method('file_put_contents')
+                       ->with('/bar/foo', 'bar')
+                       ->will($this->returnValue(true));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $node->putContent('bar');
+       }
+
+       /**
+        * @expectedException \OC\Files\NotPermittedException
+        */
+       public function testPutContentNotPermitted() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ)));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $node->putContent('bar');
+       }
+
+       public function testGetMimeType() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+
+               $view->expects($this->once())
+                       ->method('getMimeType')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue('text/plain'));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $this->assertEquals('text/plain', $node->getMimeType());
+       }
+
+       public function testFOpenRead() {
+               $stream = fopen('php://memory', 'w+');
+               fwrite($stream, 'bar');
+               rewind($stream);
+
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = new \OC\Files\Node\Root($manager, $view, $this->user);
+
+               $hook = function ($file) {
+                       throw new \Exception('Hooks are not supposed to be called');
+               };
+
+               $root->listen('\OC\Files', 'preWrite', $hook);
+               $root->listen('\OC\Files', 'postWrite', $hook);
+
+               $view->expects($this->once())
+                       ->method('fopen')
+                       ->with('/bar/foo', 'r')
+                       ->will($this->returnValue($stream));
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL)));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $fh = $node->fopen('r');
+               $this->assertEquals($stream, $fh);
+               $this->assertEquals('bar', fread($fh, 3));
+       }
+
+       public function testFOpenWrite() {
+               $stream = fopen('php://memory', 'w+');
+
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = new \OC\Files\Node\Root($manager, new $view, $this->user);
+
+               $hooksCalled = 0;
+               $hook = function ($file) use (&$hooksCalled) {
+                       $hooksCalled++;
+               };
+
+               $root->listen('\OC\Files', 'preWrite', $hook);
+               $root->listen('\OC\Files', 'postWrite', $hook);
+
+               $view->expects($this->once())
+                       ->method('fopen')
+                       ->with('/bar/foo', 'w')
+                       ->will($this->returnValue($stream));
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL)));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $fh = $node->fopen('w');
+               $this->assertEquals($stream, $fh);
+               fwrite($fh, 'bar');
+               rewind($fh);
+               $this->assertEquals('bar', fread($stream, 3));
+               $this->assertEquals(2, $hooksCalled);
+       }
+
+       /**
+        * @expectedException \OC\Files\NotPermittedException
+        */
+       public function testFOpenReadNotPermitted() {
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = new \OC\Files\Node\Root($manager, $view, $this->user);
+
+               $hook = function ($file) {
+                       throw new \Exception('Hooks are not supposed to be called');
+               };
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => 0)));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $node->fopen('r');
+       }
+
+       /**
+        * @expectedException \OC\Files\NotPermittedException
+        */
+       public function testFOpenReadWriteNoReadPermissions() {
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = new \OC\Files\Node\Root($manager, $view, $this->user);
+
+               $hook = function () {
+                       throw new \Exception('Hooks are not supposed to be called');
+               };
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_UPDATE)));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $node->fopen('w');
+       }
+
+       /**
+        * @expectedException \OC\Files\NotPermittedException
+        */
+       public function testFOpenReadWriteNoWritePermissions() {
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = new \OC\Files\Node\Root($manager, new $view, $this->user);
+
+               $hook = function () {
+                       throw new \Exception('Hooks are not supposed to be called');
+               };
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ)));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $node->fopen('w');
+       }
+
+       public function testCopySameStorage() {
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+
+               $view->expects($this->any())
+                       ->method('copy')
+                       ->with('/bar/foo', '/bar/asd');
+
+               $view->expects($this->any())
+                       ->method('getFileInfo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL, 'fileid' => 3)));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $parentNode = new \OC\Files\Node\Folder($root, $view, '/bar');
+               $newNode = new \OC\Files\Node\File($root, $view, '/bar/asd');
+
+               $root->expects($this->exactly(2))
+                       ->method('get')
+                       ->will($this->returnValueMap(array(
+                               array('/bar/asd', $newNode),
+                               array('/bar', $parentNode)
+                       )));
+
+               $target = $node->copy('/bar/asd');
+               $this->assertInstanceOf('\OC\Files\Node\File', $target);
+               $this->assertEquals(3, $target->getId());
+       }
+
+       /**
+        * @expectedException \OC\Files\NotPermittedException
+        */
+       public function testCopyNotPermitted() {
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               /**
+                * @var \OC\Files\Storage\Storage | \PHPUnit_Framework_MockObject_MockObject $storage
+                */
+               $storage = $this->getMock('\OC\Files\Storage\Storage');
+
+               $root->expects($this->never())
+                       ->method('getMount');
+
+               $storage->expects($this->never())
+                       ->method('copy');
+
+               $view->expects($this->any())
+                       ->method('getFileInfo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ, 'fileid' => 3)));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $parentNode = new \OC\Files\Node\Folder($root, $view, '/bar');
+
+               $root->expects($this->once())
+                       ->method('get')
+                       ->will($this->returnValueMap(array(
+                               array('/bar', $parentNode)
+                       )));
+
+               $node->copy('/bar/asd');
+       }
+
+       /**
+        * @expectedException \OC\Files\NotFoundException
+        */
+       public function testCopyNoParent() {
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+
+               $view->expects($this->never())
+                       ->method('copy');
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+
+               $root->expects($this->once())
+                       ->method('get')
+                       ->with('/bar/asd')
+                       ->will($this->throwException(new NotFoundException()));
+
+               $node->copy('/bar/asd/foo');
+       }
+
+       /**
+        * @expectedException \OC\Files\NotPermittedException
+        */
+       public function testCopyParentIsFile() {
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+
+               $view->expects($this->never())
+                       ->method('copy');
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $parentNode = new \OC\Files\Node\File($root, $view, '/bar');
+
+               $root->expects($this->once())
+                       ->method('get')
+                       ->will($this->returnValueMap(array(
+                               array('/bar', $parentNode)
+                       )));
+
+               $node->copy('/bar/asd');
+       }
+
+       public function testMoveSameStorage() {
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+
+               $view->expects($this->any())
+                       ->method('rename')
+                       ->with('/bar/foo', '/bar/asd');
+
+               $view->expects($this->any())
+                       ->method('getFileInfo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL, 'fileid' => 1)));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $parentNode = new \OC\Files\Node\Folder($root, $view, '/bar');
+
+               $root->expects($this->any())
+                       ->method('get')
+                       ->will($this->returnValueMap(array(array('/bar', $parentNode), array('/bar/asd', $node))));
+
+               $target = $node->move('/bar/asd');
+               $this->assertInstanceOf('\OC\Files\Node\File', $target);
+               $this->assertEquals(1, $target->getId());
+               $this->assertEquals('/bar/asd', $node->getPath());
+       }
+
+       /**
+        * @expectedException \OC\Files\NotPermittedException
+        */
+       public function testMoveNotPermitted() {
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+
+               $view->expects($this->any())
+                       ->method('getFileInfo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ)));
+
+               $view->expects($this->never())
+                       ->method('rename');
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $parentNode = new \OC\Files\Node\Folder($root, $view, '/bar');
+
+               $root->expects($this->once())
+                       ->method('get')
+                       ->with('/bar')
+                       ->will($this->returnValue($parentNode));
+
+               $node->move('/bar/asd');
+       }
+
+       /**
+        * @expectedException \OC\Files\NotFoundException
+        */
+       public function testMoveNoParent() {
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               /**
+                * @var \OC\Files\Storage\Storage | \PHPUnit_Framework_MockObject_MockObject $storage
+                */
+               $storage = $this->getMock('\OC\Files\Storage\Storage');
+
+               $storage->expects($this->never())
+                       ->method('rename');
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $parentNode = new \OC\Files\Node\Folder($root, $view, '/bar');
+
+               $root->expects($this->once())
+                       ->method('get')
+                       ->with('/bar')
+                       ->will($this->throwException(new NotFoundException()));
+
+               $node->move('/bar/asd');
+       }
+
+       /**
+        * @expectedException \OC\Files\NotPermittedException
+        */
+       public function testMoveParentIsFile() {
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+
+               $view->expects($this->never())
+                       ->method('rename');
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $parentNode = new \OC\Files\Node\File($root, $view, '/bar');
+
+               $root->expects($this->once())
+                       ->method('get')
+                       ->with('/bar')
+                       ->will($this->returnValue($parentNode));
+
+               $node->move('/bar/asd');
+       }
+}
diff --git a/tests/lib/files/node/folder.php b/tests/lib/files/node/folder.php
new file mode 100644 (file)
index 0000000..691aa61
--- /dev/null
@@ -0,0 +1,479 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\Files\Node;
+
+use OC\Files\Cache\Cache;
+use OC\Files\Node\Node;
+use OC\Files\NotFoundException;
+use OC\Files\NotPermittedException;
+use OC\Files\View;
+
+class Folder extends \PHPUnit_Framework_TestCase {
+       private $user;
+
+       public function setUp() {
+               $this->user = new \OC\User\User('', new \OC_User_Dummy);
+       }
+
+       public function testDelete() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+               $root->expects($this->exactly(2))
+                       ->method('emit')
+                       ->will($this->returnValue(true));
+
+               $view->expects($this->any())
+                       ->method('getFileInfo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL)));
+
+               $view->expects($this->once())
+                       ->method('rmdir')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(true));
+
+               $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo');
+               $node->delete();
+       }
+
+       public function testDeleteHooks() {
+               $test = $this;
+               $hooksRun = 0;
+               /**
+                * @param \OC\Files\Node\File $node
+                */
+               $preListener = function ($node) use (&$test, &$hooksRun) {
+                       $test->assertInstanceOf('\OC\Files\Node\Folder', $node);
+                       $test->assertEquals('foo', $node->getInternalPath());
+                       $test->assertEquals('/bar/foo', $node->getPath());
+                       $hooksRun++;
+               };
+
+               /**
+                * @param \OC\Files\Node\File $node
+                */
+               $postListener = function ($node) use (&$test, &$hooksRun) {
+                       $test->assertInstanceOf('\OC\Files\Node\NonExistingFolder', $node);
+                       $test->assertEquals('foo', $node->getInternalPath());
+                       $test->assertEquals('/bar/foo', $node->getPath());
+                       $hooksRun++;
+               };
+
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = new \OC\Files\Node\Root($manager, $view, $this->user);
+               $root->listen('\OC\Files', 'preDelete', $preListener);
+               $root->listen('\OC\Files', 'postDelete', $postListener);
+
+               $view->expects($this->any())
+                       ->method('getFileInfo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL, 'fileid' => 1)));
+
+               $view->expects($this->once())
+                       ->method('rmdir')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(true));
+
+               $view->expects($this->any())
+                       ->method('resolvePath')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array(null, 'foo')));
+
+               $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo');
+               $node->delete();
+               $this->assertEquals(2, $hooksRun);
+       }
+
+       /**
+        * @expectedException \OC\Files\NotPermittedException
+        */
+       public function testDeleteNotPermitted() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ)));
+
+               $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo');
+               $node->delete();
+       }
+
+       public function testGetDirectoryContent() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               /**
+                * @var \OC\Files\Storage\Storage | \PHPUnit_Framework_MockObject_MockObject $storage
+                */
+               $storage = $this->getMock('\OC\Files\Storage\Storage');
+
+               $cache = $this->getMock('\OC\Files\Cache\Cache', array(), array(''));
+               $cache->expects($this->any())
+                       ->method('getStatus')
+                       ->with('foo')
+                       ->will($this->returnValue(Cache::COMPLETE));
+
+               $cache->expects($this->once())
+                       ->method('getFolderContents')
+                       ->with('foo')
+                       ->will($this->returnValue(array(
+                               array('fileid' => 2, 'path' => '/bar/foo/asd', 'name' => 'asd', 'size' => 100, 'mtime' => 50, 'mimetype' => 'text/plain'),
+                               array('fileid' => 3, 'path' => '/bar/foo/qwerty', 'name' => 'qwerty', 'size' => 200, 'mtime' => 55, 'mimetype' => 'httpd/unix-directory')
+                       )));
+
+               $permissionsCache = $this->getMock('\OC\Files\Cache\Permissions', array(), array('/'));
+               $permissionsCache->expects($this->once())
+                       ->method('getDirectoryPermissions')
+                       ->will($this->returnValue(array(2 => \OCP\PERMISSION_ALL)));
+
+               $root->expects($this->once())
+                       ->method('getMountsIn')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array()));
+
+               $storage->expects($this->any())
+                       ->method('getPermissionsCache')
+                       ->will($this->returnValue($permissionsCache));
+               $storage->expects($this->any())
+                       ->method('getCache')
+                       ->will($this->returnValue($cache));
+
+               $view->expects($this->any())
+                       ->method('resolvePath')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array($storage, 'foo')));
+
+               $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo');
+               $children = $node->getDirectoryListing();
+               $this->assertEquals(2, count($children));
+               $this->assertInstanceOf('\OC\Files\Node\File', $children[0]);
+               $this->assertInstanceOf('\OC\Files\Node\Folder', $children[1]);
+               $this->assertEquals('asd', $children[0]->getName());
+               $this->assertEquals('qwerty', $children[1]->getName());
+       }
+
+       public function testGet() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $root->expects($this->once())
+                       ->method('get')
+                       ->with('/bar/foo/asd');
+
+               $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo');
+               $node->get('asd');
+       }
+
+       public function testNodeExists() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $child = new \OC\Files\Node\Folder($root, $view, '/bar/foo/asd');
+
+               $root->expects($this->once())
+                       ->method('get')
+                       ->with('/bar/foo/asd')
+                       ->will($this->returnValue($child));
+
+               $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo');
+               $this->assertTrue($node->nodeExists('asd'));
+       }
+
+       public function testNodeExistsNotExists() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $root->expects($this->once())
+                       ->method('get')
+                       ->with('/bar/foo/asd')
+                       ->will($this->throwException(new NotFoundException()));
+
+               $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo');
+               $this->assertFalse($node->nodeExists('asd'));
+       }
+
+       public function testNewFolder() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL)));
+
+               $view->expects($this->once())
+                       ->method('mkdir')
+                       ->with('/bar/foo/asd')
+                       ->will($this->returnValue(true));
+
+               $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo');
+               $child = new \OC\Files\Node\Folder($root, $view, '/bar/foo/asd');
+               $result = $node->newFolder('asd');
+               $this->assertEquals($child, $result);
+       }
+
+       /**
+        * @expectedException \OC\Files\NotPermittedException
+        */
+       public function testNewFolderNotPermitted() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ)));
+
+               $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo');
+               $node->newFolder('asd');
+       }
+
+       public function testNewFile() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL)));
+
+               $view->expects($this->once())
+                       ->method('touch')
+                       ->with('/bar/foo/asd')
+                       ->will($this->returnValue(true));
+
+               $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo');
+               $child = new \OC\Files\Node\File($root, $view, '/bar/foo/asd');
+               $result = $node->newFile('asd');
+               $this->assertEquals($child, $result);
+       }
+
+       /**
+        * @expectedException \OC\Files\NotPermittedException
+        */
+       public function testNewFileNotPermitted() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ)));
+
+               $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo');
+               $node->newFile('asd');
+       }
+
+       public function testGetFreeSpace() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $view->expects($this->once())
+                       ->method('free_space')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(100));
+
+               $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo');
+               $this->assertEquals(100, $node->getFreeSpace());
+       }
+
+       public function testSearch() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+               $storage = $this->getMock('\OC\Files\Storage\Storage');
+               $cache = $this->getMock('\OC\Files\Cache\Cache', array(), array(''));
+
+               $storage->expects($this->once())
+                       ->method('getCache')
+                       ->will($this->returnValue($cache));
+
+               $cache->expects($this->once())
+                       ->method('search')
+                       ->with('%qw%')
+                       ->will($this->returnValue(array(
+                               array('fileid' => 3, 'path' => 'foo/qwerty', 'name' => 'qwerty', 'size' => 200, 'mtime' => 55, 'mimetype' => 'text/plain')
+                       )));
+
+               $root->expects($this->once())
+                       ->method('getMountsIn')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array()));
+
+               $view->expects($this->once())
+                       ->method('resolvePath')
+                       ->will($this->returnValue(array($storage, 'foo')));
+
+               $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo');
+               $result = $node->search('qw');
+               $this->assertEquals(1, count($result));
+               $this->assertEquals('/bar/foo/qwerty', $result[0]->getPath());
+       }
+
+       public function testSearchSubStorages() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+               $storage = $this->getMock('\OC\Files\Storage\Storage');
+               $cache = $this->getMock('\OC\Files\Cache\Cache', array(), array(''));
+               $subCache = $this->getMock('\OC\Files\Cache\Cache', array(), array(''));
+               $subStorage = $this->getMock('\OC\Files\Storage\Storage');
+               $subMount = $this->getMock('\OC\Files\Mount\Mount', array(), array(null, ''));
+
+               $subMount->expects($this->once())
+                       ->method('getStorage')
+                       ->will($this->returnValue($subStorage));
+
+               $subMount->expects($this->once())
+                       ->method('getMountPoint')
+                       ->will($this->returnValue('/bar/foo/bar/'));
+
+               $storage->expects($this->once())
+                       ->method('getCache')
+                       ->will($this->returnValue($cache));
+
+               $subStorage->expects($this->once())
+                       ->method('getCache')
+                       ->will($this->returnValue($subCache));
+
+               $cache->expects($this->once())
+                       ->method('search')
+                       ->with('%qw%')
+                       ->will($this->returnValue(array(
+                               array('fileid' => 3, 'path' => 'foo/qwerty', 'name' => 'qwerty', 'size' => 200, 'mtime' => 55, 'mimetype' => 'text/plain')
+                       )));
+
+               $subCache->expects($this->once())
+                       ->method('search')
+                       ->with('%qw%')
+                       ->will($this->returnValue(array(
+                               array('fileid' => 4, 'path' => 'asd/qweasd', 'name' => 'qweasd', 'size' => 200, 'mtime' => 55, 'mimetype' => 'text/plain')
+                       )));
+
+               $root->expects($this->once())
+                       ->method('getMountsIn')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array($subMount)));
+
+               $view->expects($this->once())
+                       ->method('resolvePath')
+                       ->will($this->returnValue(array($storage, 'foo')));
+
+
+               $node = new \OC\Files\Node\Folder($root, $view, '/bar/foo');
+               $result = $node->search('qw');
+               $this->assertEquals(2, count($result));
+       }
+
+       public function testIsSubNode() {
+               $file = new Node(null, null, '/foo/bar');
+               $folder = new \OC\Files\Node\Folder(null, null, '/foo');
+               $this->assertTrue($folder->isSubNode($file));
+               $this->assertFalse($folder->isSubNode($folder));
+
+               $file = new Node(null, null, '/foobar');
+               $this->assertFalse($folder->isSubNode($file));
+       }
+}
diff --git a/tests/lib/files/node/integration.php b/tests/lib/files/node/integration.php
new file mode 100644 (file)
index 0000000..c99b6f9
--- /dev/null
@@ -0,0 +1,121 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\Files\Node;
+
+use OC\Files\Cache\Cache;
+use OC\Files\Mount\Manager;
+use OC\Files\Node\Root;
+use OC\Files\NotFoundException;
+use OC\Files\NotPermittedException;
+use OC\Files\Storage\Temporary;
+use OC\Files\View;
+use OC\User\User;
+
+class IntegrationTests extends \PHPUnit_Framework_TestCase {
+       /**
+        * @var \OC\Files\Node\Root $root
+        */
+       private $root;
+
+       /**
+        * @var \OC\Files\Storage\Storage[]
+        */
+       private $storages;
+
+       /**
+        * @var \OC\Files\View $view
+        */
+       private $view;
+
+       public function setUp() {
+               \OC\Files\Filesystem::init('', '');
+               \OC\Files\Filesystem::clearMounts();
+               $manager = \OC\Files\Filesystem::getMountManager();
+
+               \OC_Hook::clear('OC_Filesystem');
+
+               \OC_Hook::connect('OC_Filesystem', 'post_write', '\OC\Files\Cache\Updater', 'writeHook');
+               \OC_Hook::connect('OC_Filesystem', 'post_delete', '\OC\Files\Cache\Updater', 'deleteHook');
+               \OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Updater', 'renameHook');
+               \OC_Hook::connect('OC_Filesystem', 'post_touch', '\OC\Files\Cache\Updater', 'touchHook');
+
+               $user = new User('', new \OC_User_Dummy);
+               $this->view = new View();
+               $this->root = new Root($manager, $this->view, $user);
+               $storage = new Temporary(array());
+               $subStorage = new Temporary(array());
+               $this->storages[] = $storage;
+               $this->storages[] = $subStorage;
+               $this->root->mount($storage, '/');
+               $this->root->mount($subStorage, '/substorage/');
+       }
+
+       public function tearDown() {
+               foreach ($this->storages as $storage) {
+                       $storage->getCache()->clear();
+               }
+               \OC\Files\Filesystem::clearMounts();
+       }
+
+       public function testBasicFile() {
+               $file = $this->root->newFile('/foo.txt');
+               $this->assertCount(2, $this->root->getDirectoryListing());
+               $this->assertTrue($this->root->nodeExists('/foo.txt'));
+               $id = $file->getId();
+               $this->assertInstanceOf('\OC\Files\Node\File', $file);
+               $file->putContent('qwerty');
+               $this->assertEquals('text/plain', $file->getMimeType());
+               $this->assertEquals('qwerty', $file->getContent());
+               $this->assertFalse($this->root->nodeExists('/bar.txt'));
+               $file->move('/bar.txt');
+               $this->assertFalse($this->root->nodeExists('/foo.txt'));
+               $this->assertTrue($this->root->nodeExists('/bar.txt'));
+               $this->assertEquals('bar.txt', $file->getName());
+               $this->assertEquals('bar.txt', $file->getInternalPath());
+
+               $file->move('/substorage/bar.txt');
+               $this->assertNotEquals($id, $file->getId());
+               $this->assertEquals('qwerty', $file->getContent());
+       }
+
+       public function testBasicFolder() {
+               $folder = $this->root->newFolder('/foo');
+               $this->assertTrue($this->root->nodeExists('/foo'));
+               $file = $folder->newFile('/bar');
+               $this->assertTrue($this->root->nodeExists('/foo/bar'));
+               $file->putContent('qwerty');
+
+               $listing = $folder->getDirectoryListing();
+               $this->assertEquals(1, count($listing));
+               $this->assertEquals($file->getId(), $listing[0]->getId());
+               $this->assertEquals($file->getStorage(), $listing[0]->getStorage());
+
+
+               $rootListing = $this->root->getDirectoryListing();
+               $this->assertEquals(2, count($rootListing));
+
+               $folder->move('/asd');
+               /**
+                * @var \OC\Files\Node\File $file
+                */
+               $file = $folder->get('/bar');
+               $this->assertInstanceOf('\OC\Files\Node\File', $file);
+               $this->assertFalse($this->root->nodeExists('/foo/bar'));
+               $this->assertTrue($this->root->nodeExists('/asd/bar'));
+               $this->assertEquals('qwerty', $file->getContent());
+               $folder->move('/substorage/foo');
+               /**
+                * @var \OC\Files\Node\File $file
+                */
+               $file = $folder->get('/bar');
+               $this->assertInstanceOf('\OC\Files\Node\File', $file);
+               $this->assertTrue($this->root->nodeExists('/substorage/foo/bar'));
+               $this->assertEquals('qwerty', $file->getContent());
+       }
+}
diff --git a/tests/lib/files/node/node.php b/tests/lib/files/node/node.php
new file mode 100644 (file)
index 0000000..aa9d2a3
--- /dev/null
@@ -0,0 +1,330 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\Files\Node;
+
+class Node extends \PHPUnit_Framework_TestCase {
+       private $user;
+
+       public function setUp() {
+               $this->user = new \OC\User\User('', new \OC_User_Dummy);
+       }
+
+       public function testStat() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $stat = array(
+                       'fileid' => 1,
+                       'size' => 100,
+                       'etag' => 'qwerty',
+                       'mtime' => 50,
+                       'permissions' => 0
+               );
+
+               $view->expects($this->once())
+                       ->method('stat')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue($stat));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $this->assertEquals($stat, $node->stat());
+       }
+
+       public function testGetId() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $stat = array(
+                       'fileid' => 1,
+                       'size' => 100,
+                       'etag' => 'qwerty',
+                       'mtime' => 50
+               );
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue($stat));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $this->assertEquals(1, $node->getId());
+       }
+
+       public function testGetSize() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $view->expects($this->once())
+                       ->method('filesize')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(100));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $this->assertEquals(100, $node->getSize());
+       }
+
+       public function testGetEtag() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $stat = array(
+                       'fileid' => 1,
+                       'size' => 100,
+                       'etag' => 'qwerty',
+                       'mtime' => 50
+               );
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue($stat));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $this->assertEquals('qwerty', $node->getEtag());
+       }
+
+       public function testGetMTime() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+               /**
+                * @var \OC\Files\Storage\Storage | \PHPUnit_Framework_MockObject_MockObject $storage
+                */
+               $storage = $this->getMock('\OC\Files\Storage\Storage');
+
+               $view->expects($this->once())
+                       ->method('filemtime')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(50));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $this->assertEquals(50, $node->getMTime());
+       }
+
+       public function testGetStorage() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+               /**
+                * @var \OC\Files\Storage\Storage | \PHPUnit_Framework_MockObject_MockObject $storage
+                */
+               $storage = $this->getMock('\OC\Files\Storage\Storage');
+
+               $view->expects($this->once())
+                       ->method('resolvePath')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array($storage, 'foo')));
+
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $this->assertEquals($storage, $node->getStorage());
+       }
+
+       public function testGetPath() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $this->assertEquals('/bar/foo', $node->getPath());
+       }
+
+       public function testGetInternalPath() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+               /**
+                * @var \OC\Files\Storage\Storage | \PHPUnit_Framework_MockObject_MockObject $storage
+                */
+               $storage = $this->getMock('\OC\Files\Storage\Storage');
+
+               $view->expects($this->once())
+                       ->method('resolvePath')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array($storage, 'foo')));
+
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $this->assertEquals('foo', $node->getInternalPath());
+       }
+
+       public function testGetName() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $node = new \OC\Files\Node\File($root, $view, '/bar/foo');
+               $this->assertEquals('foo', $node->getName());
+       }
+
+       public function testTouchSetMTime() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $view->expects($this->once())
+                       ->method('touch')
+                       ->with('/bar/foo', 100)
+                       ->will($this->returnValue(true));
+
+               $view->expects($this->once())
+                       ->method('filemtime')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(100));
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL)));
+
+               $node = new \OC\Files\Node\Node($root, $view, '/bar/foo');
+               $node->touch(100);
+               $this->assertEquals(100, $node->getMTime());
+       }
+
+       public function testTouchHooks() {
+               $test = $this;
+               $hooksRun = 0;
+               /**
+                * @param \OC\Files\Node\File $node
+                */
+               $preListener = function ($node) use (&$test, &$hooksRun) {
+                       $test->assertEquals('foo', $node->getInternalPath());
+                       $test->assertEquals('/bar/foo', $node->getPath());
+                       $hooksRun++;
+               };
+
+               /**
+                * @param \OC\Files\Node\File $node
+                */
+               $postListener = function ($node) use (&$test, &$hooksRun) {
+                       $test->assertEquals('foo', $node->getInternalPath());
+                       $test->assertEquals('/bar/foo', $node->getPath());
+                       $hooksRun++;
+               };
+
+               /**
+                * @var \OC\Files\Mount\Manager $manager
+                */
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = new \OC\Files\Node\Root($manager, $view, $this->user);
+               $root->listen('\OC\Files', 'preTouch', $preListener);
+               $root->listen('\OC\Files', 'postTouch', $postListener);
+
+               $view->expects($this->once())
+                       ->method('touch')
+                       ->with('/bar/foo', 100)
+                       ->will($this->returnValue(true));
+
+               $view->expects($this->any())
+                       ->method('resolvePath')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array(null, 'foo')));
+
+               $view->expects($this->any())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_ALL)));
+
+               $node = new \OC\Files\Node\Node($root, $view, '/bar/foo');
+               $node->touch(100);
+               $this->assertEquals(2, $hooksRun);
+       }
+
+       /**
+        * @expectedException \OC\Files\NotPermittedException
+        */
+       public function testTouchNotPermitted() {
+               $manager = $this->getMock('\OC\Files\Mount\Manager');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = $this->getMock('\OC\Files\Node\Root', array(), array($manager, $view, $this->user));
+               $root->expects($this->any())
+                       ->method('getUser')
+                       ->will($this->returnValue($this->user));
+
+               $view->expects($this->any())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('permissions' => \OCP\PERMISSION_READ)));
+
+               $node = new \OC\Files\Node\Node($root, $view, '/bar/foo');
+               $node->touch(100);
+       }
+}
diff --git a/tests/lib/files/node/root.php b/tests/lib/files/node/root.php
new file mode 100644 (file)
index 0000000..0b356ec
--- /dev/null
@@ -0,0 +1,106 @@
+<?php
+/**
+ * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\Files\Node;
+
+use OC\Files\Cache\Cache;
+use OC\Files\NotPermittedException;
+use OC\Files\Mount\Manager;
+
+class Root extends \PHPUnit_Framework_TestCase {
+       private $user;
+
+       public function setUp() {
+               $this->user = new \OC\User\User('', new \OC_User_Dummy);
+       }
+
+       public function testGet() {
+               $manager = new Manager();
+               /**
+                * @var \OC\Files\Storage\Storage $storage
+                */
+               $storage = $this->getMock('\OC\Files\Storage\Storage');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = new \OC\Files\Node\Root($manager, $view, $this->user);
+
+               $view->expects($this->once())
+                       ->method('getFileInfo')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(array('fileid' => 10, 'path' => 'bar/foo', 'name', 'mimetype' => 'text/plain')));
+
+               $view->expects($this->once())
+                       ->method('is_dir')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(false));
+
+               $view->expects($this->once())
+                       ->method('file_exists')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(true));
+
+               $root->mount($storage, '');
+               $node = $root->get('/bar/foo');
+               $this->assertEquals(10, $node->getId());
+               $this->assertInstanceOf('\OC\Files\Node\File', $node);
+       }
+
+       /**
+        * @expectedException \OC\Files\NotFoundException
+        */
+       public function testGetNotFound() {
+               $manager = new Manager();
+               /**
+                * @var \OC\Files\Storage\Storage $storage
+                */
+               $storage = $this->getMock('\OC\Files\Storage\Storage');
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = new \OC\Files\Node\Root($manager, $view, $this->user);
+
+               $view->expects($this->once())
+                       ->method('file_exists')
+                       ->with('/bar/foo')
+                       ->will($this->returnValue(false));
+
+               $root->mount($storage, '');
+               $root->get('/bar/foo');
+       }
+
+       /**
+        * @expectedException \OC\Files\NotPermittedException
+        */
+       public function testGetInvalidPath() {
+               $manager = new Manager();
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = new \OC\Files\Node\Root($manager, $view, $this->user);
+
+               $root->get('/../foo');
+       }
+
+       /**
+        * @expectedException \OC\Files\NotFoundException
+        */
+       public function testGetNoStorages() {
+               $manager = new Manager();
+               /**
+                * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
+                */
+               $view = $this->getMock('\OC\Files\View');
+               $root = new \OC\Files\Node\Root($manager, $view, $this->user);
+
+               $root->get('/bar/foo');
+       }
+}