Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Finish mock filesystem

Also, ported all filesystem tests to Jasmine.
  • Loading branch information...
commit fbb217765182b99180909923c197ded50ba424a6 1 parent 8c4a800
@kriskowal authored
Showing with 1,246 additions and 758 deletions.
  1. +59 −0 buffer-stream.js
  2. +1 −1  fs-boot.js
  3. +35 −41 fs-common.js
  4. +425 −139 fs-mock.js
  5. +1 −1  fs-root.js
  6. +32 −15 fs.js
  7. +0 −5 reader.js
  8. +9 −8 test/fs/boot-directory.js → spec/fs/boot-directory-spec.js
  9. +33 −0 spec/fs/issues/1-spec.js
  10. +56 −0 spec/fs/mock/copy-tree-spec.js
  11. 0  {test → spec}/fs/mock/dummy/hello.txt
  12. 0  {test/fs → spec/fs/mock}/fixtures/1234.txt
  13. +69 −0 spec/fs/mock/link-spec.js
  14. +48 −0 spec/fs/mock/make-tree-spec.js
  15. +66 −0 spec/fs/mock/merge-spec.js
  16. +59 −0 spec/fs/mock/move-spec.js
  17. +20 −0 spec/fs/mock/object-spec.js
  18. +26 −0 spec/fs/mock/range-spec.js
  19. +23 −0 spec/fs/mock/read-spec.js
  20. +37 −0 spec/fs/mock/remove-directory-spec.js
  21. +38 −0 spec/fs/mock/remove-tree-spec.js
  22. +32 −0 spec/fs/mock/root-spec.js
  23. +85 −0 spec/fs/mock/symbolic-link-spec.js
  24. +26 −0 spec/fs/mock/write-spec.js
  25. +23 −0 spec/fs/range-spec.js
  26. +1 −0  spec/fs/range-spec.txt
  27. +42 −0 spec/lib/jasmine-promise.js
  28. +0 −2  test/all.js
  29. +0 −17 test/fs/all.js
  30. +0 −25 test/fs/issues/1.js
  31. +0 −32 test/fs/lazy.js
  32. +0 −35 test/fs/mock/copy-tree.js
  33. +0 −34 test/fs/mock/make-tree.js
  34. +0 −51 test/fs/mock/merge.js
  35. +0 −37 test/fs/mock/move.js
  36. +0 −28 test/fs/mock/object.js
  37. +0 −35 test/fs/mock/read.js
  38. +0 −34 test/fs/mock/remove-directory.js
  39. +0 −34 test/fs/mock/remove-tree.js
  40. +0 −47 test/fs/mock/subtree.js
  41. +0 −35 test/fs/mock/write.js
  42. +0 −25 test/fs/partial.js
  43. +0 −52 test/fs/root.js
  44. +0 −25 test/issues/1.js
View
59 buffer-stream.js
@@ -0,0 +1,59 @@
+
+var Q = require("q");
+var Reader = require("./reader");
+
+module.exports = BufferStream;
+function BufferStream(chunks, charset) {
+ if (!(this instanceof BufferStream)) {
+ return new BufferStream(chunks, charset);
+ }
+ if (!chunks) {
+ chunks = [];
+ } else if (!Array.isArray(chunks)) {
+ chunks = [chunks];
+ }
+ this._charset = charset;
+ this._chunks = chunks;
+ this._close = Q.defer();
+ this.closed = this._close.promise;
+}
+
+BufferStream.prototype.forEach = function (write, thisp) {
+ var self = this;
+ var chunks = self._chunks;
+ return Q.fcall(function () {
+ chunks.splice(0, chunks.length).forEach(write, thisp);
+ });
+};
+
+BufferStream.prototype.read = function () {
+ var result;
+ result = Reader.join(this._chunks);
+ if (this._charset) {
+ result = result.toString(this._charset);
+ }
+ return Q.resolve(result);
+};
+
+BufferStream.prototype.write = function (chunk) {
+ if (this._charset) {
+ chunk = new Buffer(String(chunk), this._charset);
+ } else {
+ if (!(chunk instanceof Buffer)) {
+ throw new Error("Can't write strings to buffer stream without a charset: " + chunk);
+ }
+ }
+ this._chunks.push(chunk);
+ return Q.resolve();
+};
+
+BufferStream.prototype.close = function () {
+ this._close.resolve();
+ return Q.resolve();
+};
+
+BufferStream.prototype.destroy = function () {
+ this._close.resolve();
+ return Q.resolve();
+};
+
View
2  fs-boot.js
@@ -100,7 +100,7 @@ exports.split = function (path) {
* @returns {String} path
*/
exports.join = function () {
- if (arguments.length === 1 && typeof arguments[0] === "object")
+ if (arguments.length === 1 && Array.isArray(arguments[0]))
return exports.normal.apply(exports, arguments[0]);
return exports.normal.apply(exports, arguments);
};
View
76 fs-common.js
@@ -7,7 +7,6 @@ var MockFs = require("./fs-mock");
// TODO patternToRegExp
// TODO glob
// TODO match
-// TODO copyTree
var concat = function (arrays) {
return Array.prototype.concat.apply([], arrays);
@@ -35,12 +34,11 @@ exports.update = function (exports, workingDirectory) {
options.flags = "r" + (options.flags || "").replace(/r/g, "");
return Q.when(this.open(path, options), function (stream) {
return stream.read();
- }, function (reason) {
- var error = new Error("Can't read " + path + " because " + reason.message);
+ }, function (error) {
+ error.message = "Can't read " + path + " because " + error.message;
error.path = path;
error.flags = flags;
error.charset = charset;
- error.cause = reason;
throw error;
});
};
@@ -105,22 +103,22 @@ exports.update = function (exports, workingDirectory) {
exports.copyTree = function (source, target) {
var self = this;
- return Q.when(exports.stat(source), function (stat) {
+ return Q.when(self.stat(source), function (stat) {
if (stat.isFile()) {
- return exports.copy(source, target);
+ return self.copy(source, target);
} else if (stat.isDirectory()) {
- return Q.when(exports.makeDirectory(target), function () {
- return Q.when(exports.list(source), function (list) {
+ return Q.when(self.makeDirectory(target), function () {
+ return Q.when(self.list(source), function (list) {
return Q.all(list.map(function (child) {
- return exports.copyTree(
- exports.join(source, child),
- exports.join(target, child)
+ return self.copyTree(
+ self.join(source, child),
+ self.join(target, child)
);
}));
});
});
} else if (stat.isSymbolicLink()) {
- return exports.symbolicCopy(source, target);
+ return self.symbolicCopy(source, target);
}
});
};
@@ -214,6 +212,13 @@ exports.update = function (exports, workingDirectory) {
});
};
+ exports.symbolicCopy = function (source, target) {
+ var self = this;
+ return Q.when(self.relative(target, source), function (relative) {
+ return self.symbolicLink(target, relative, "file");
+ });
+ };
+
exports.exists = function (path) {
return Q.when(this.stat(path), function () {
return true;
@@ -238,6 +243,24 @@ exports.update = function (exports, workingDirectory) {
});
};
+ exports.isSymbolicLink = function (path) {
+ return Q.when(this.statLink(path), function (stat) {
+ return stat.isSymbolicLink();
+ }, function (reason) {
+ return false;
+ });
+ };
+
+ exports.lastModified = function (path) {
+ var self = this;
+ return self.stat(path).invoke('lastModified');
+ };
+
+ exports.lastAccessed = function (path) {
+ var self = this;
+ return self.stat(path).invoke('lastAccessed');
+ };
+
exports.absolute = function (path) {
if (this.isAbsolute(path))
return path;
@@ -377,34 +400,5 @@ exports.update = function (exports, workingDirectory) {
});
};
- var Stats = exports.Stats = function (nodeStat) {
- this.node = nodeStat;
- this.size = nodeStat.size;
- };
-
- var stats = [
- "isDirectory",
- "isFile",
- "isBlockDevice",
- "isCharacterDevice",
- "isSymbolicLink",
- "isFIFO",
- "isSocket"
- ];
-
- stats.forEach(function (name) {
- Stats.prototype[name] = function () {
- return this.node[name]();
- };
- });
-
- Stats.prototype.lastModified = function () {
- return new Date(this.node.mtime);
- };
-
- Stats.prototype.lastAccessed = function () {
- return new Date(this.node.atime);
- };
-
}
View
564 fs-mock.js
@@ -1,77 +1,79 @@
-(function (require, exports) {
var Q = require("q");
-var BOOT = require("./fs-boot");
-var FS = require("./fs");
-var COMMON = require("./fs-common");
+var Boot = require("./fs-boot");
+var Common = require("./fs-common");
+var BufferStream = require("./buffer-stream");
+var Reader = require("./reader");
+var Set = require("collections/set");
module.exports = MockFs;
function MockFs(files) {
- var fs = Object.create(BOOT);
- var root = {};
- var now = new Date();
+ if (!(this instanceof MockFs)) {
+ return new MockFs(files);
+ }
+ this._root = new DirectoryNode(this, "/");
function init() {
// construct a file tree
- Object.keys(files).forEach(function (path) {
- var content = files[path];
- find(root, path).set(content);
- });
}
- function find(at, path) {
- path = fs.absolute(path);
- if (path === "" || path === FS.ROOT) {
- return Node(function get() {
- return root;
- }, function set(content) {
- root = content;
- });
- }
- var parts = FS.split(path);
- var empty = parts.shift();
- if (empty !== "")
- throw new Error("assertion: first component of root should be empty");
- var i, ii;
- var manifest = function () {};
- for (i = 0, ii = parts.length - 1; i < ii; i++) {
- var part = parts[i];
- if (part === ".") {
- continue;
- } if (typeof at[part] !== "object") {
- manifest = (function (on, part, manifest) {
- var created = {};
- at = created;
- return function () {
- on[part] = created;
- manifest();
- };
- })(at, part, manifest);
+ Common.update(this, function () {
+ return workingDirectory;
+ });
+
+ var workingDirectory = this.ROOT;
+ if (files) {
+ this._init(files);
+ }
+}
+
+MockFs.prototype = Object.create(Boot);
+
+MockFs.prototype._init = function (files, tree) {
+ tree = tree || this.ROOT;
+ Object.keys(files).forEach(function (path) {
+ var content = files[path];
+ path = this.join(tree, path);
+ var directory = this.directory(path);
+ var base = this.base(path);
+ var directoryNode = this._root._walk(directory, true);
+ var fileNode = new FileNode(this);
+ if (!(content instanceof Buffer)) {
+ if (typeof content === "object") {
+ this._init(content, path);
+ return;
} else {
- at = at[part];
+ content = new Buffer(String(content), "utf-8");
}
}
- var leaf = parts[i];
- return Node(function get() {
- return at[leaf];
- }, function set(content) {
- manifest();
- at[leaf] = content;
- });
- }
+ directoryNode._entries[base] = fileNode;
+ fileNode._chunks = [content];
+ }, this);
+};
- fs.list = function (path) {
- path = String(path);
- return Q.when(fs.stat(path), function (stat) {
- if (!stat.isDirectory())
- throw new Error("Can't list non-directory " + path);
- var node = find(root, path).get();
- return Object.keys(node);
- });
- };
+MockFs.prototype.list = function (path) {
+ var self = this;
+ return Q.fcall(function () {
+ path = self.absolute(path);
+ var node = self._root._walk(path)._follow(path);
+ if (!node.isDirectory()) {
+ new Error("Can't list non-directory: " + JSON.stringify(path));
+ }
+ return Object.keys(node._entries).sort();
+ });
+};
- fs.open = function (path, flags, charset, options) {
+MockFs.prototype.open = function (path, flags, charset, options) {
+ var self = this;
+ return Q.fcall(function () {
+ path = self.absolute(path);
+ var directory = self.directory(path);
+ var base = self.base(path);
+ var node = self._root._walk(directory);
+ if (!node.isDirectory()) {
+ throw new Error("Can't find " + path + " because " + directory + " is not a directory");
+ }
if (typeof flags == "object") {
options = flags;
flags = options.flags;
@@ -79,71 +81,216 @@ function MockFs(files) {
} else {
options = options || {};
}
- var node = find(root, path);
- // TODO create an actual open file object, rather
- // than this rather primitive duck
flags = flags || "r";
var binary = flags.indexOf("b") >= 0;
- charset = charset || "utf-8";
- if (flags.indexOf("w") === -1) {
- return fs.stat(path).post("isFile")
- .then(function (isFile) {
- if (!isFile) {
- throw new Error("Can't open non-file " + path);
- }
- return {
- "read": function () {
- var content = node.get();
- if (!binary)
- content = content.toString(charset);
- return content;
- }
- };
- });
- } else {
- throw new Error("Can't open files for writing in read-only mock file system");
+ var write = flags.indexOf("w") >= 0;
+ if (!binary) {
+ charset = charset || "utf-8";
}
- };
+ if (write) {
+ if (!node._entries[base]) {
+ node._entries[base] = new FileNode(this);
+ }
+ var fileNode = node._entries[base]._follow(path);
+ if (!fileNode.isFile()) {
+ throw new Error("Can't write non-file " + path);
+ }
+ fileNode._lastModified = new Date();
+ fileNode._lastAccessed = new Date();
+ return new BufferStream(fileNode._chunks, charset);
+ } else { // read
+ if (!node._entries[base]) {
+ throw new Error("Can't read non-existant " + path);
+ }
+ var fileNode = node._entries[base]._follow(path);
+ if (!fileNode.isFile()) {
+ throw new Error("Can't read non-file " + path);
+ }
+ fileNode._lastAccessed = new Date();
+ if ("begin" in options && "end" in options) {
+ return new BufferStream(
+ [
+ Reader.join(fileNode._chunks)
+ .slice(options.begin, options.end)
+ ],
+ charset
+ );
+ } else {
+ return new BufferStream(fileNode._chunks, charset);
+ }
+ }
+ });
+};
- fs.stat = function (path) {
- var stat = find(root, path);
- if (stat.get() === undefined)
- return Q.reject(new Error("No such file: " + path));
- return Q.resolve(stat);
- };
+MockFs.prototype.remove = function (path) {
+ var self = this;
+ return Q.fcall(function () {
+ path = self.absolute(path);
+ var directory = self.directory(path);
+ var name = self.base(path);
+ var node = self._root._walk(directory);
+ if (!node.isDirectory()) {
+ throw new Error("Can't remove file from non-directory: " + path);
+ }
+ if (!node._entries[name]) {
+ throw new Error("Can't remove non-existant file: " + path);
+ }
+ if (node._entries[name].isDirectory()) {
+ throw new Error("Can't remove directory. Use removeDirectory: " + path);
+ }
+ delete node._entries[name];
+ });
+};
- fs.getNode = function (path) {
- path = path || "";
- return find(root, path).get();
- };
+MockFs.prototype.makeDirectory = function (path) {
+ var self = this;
+ return Q.fcall(function () {
+ path = self.absolute(path);
+ var directory = self.directory(path);
+ var name = self.base(path);
+ var node = self._root._walk(directory);
+ if (!node.isDirectory()) {
+ throw new Error("Can't make directory in non-directory: " + path);
+ }
+ if (node._entries[name]) {
+ throw new Error("Can't make directory. Entry exists: " + path);
+ }
+ node._entries[name] = new DirectoryNode(self);
+ });
+};
- fs.canonical = function (path) {
- return fs.normal(path);
- };
+MockFs.prototype.removeDirectory = function (path) {
+ var self = this;
+ return Q.fcall(function () {
+ path = self.absolute(path);
+ var directory = self.directory(path);
+ var name = self.base(path);
+ var node = self._root._walk(directory);
+ if (!node.isDirectory()) {
+ throw new Error("Can't remove directory from non-directory: " + path);
+ }
+ if (!node._entries[name]) {
+ throw new Error("Can't remove non-existant directory: " + path);
+ }
+ if (!node._entries[name].isDirectory()) {
+ throw new Error("Can't remove non-directory: " + path);
+ }
+ delete node._entries[name];
+ });
+};
- var Node = function (get, set) {
- var self = Object.create(Node.prototype);
- self.get = get;
- self.set = set;
- return self;
- };
+MockFs.prototype.stat = function (path) {
+ var self = this;
+ return Q.fcall(function () {
+ path = self.absolute(path);
+ return self._root._walk(path)._follow(path);
+ });
+};
- Node.prototype = Object.create(GenericNode.prototype);
+MockFs.prototype.statLink = function (path) {
+ var self = this;
+ return Q.fcall(function () {
+ path = self.absolute(path);
+ var node = self._root._walk(path);
+ if (!node.isSymbolicLink()) {
+ throw new Error("Path is not symbolic link: " + JSON.stringify(path));
+ }
+ return node;
+ });
+};
- Node.prototype.constructor = Node;
+MockFs.prototype.link = function (source, target) {
+ var self = this;
+ return Q.fcall(function () {
+ source = self.absolute(source);
+ target = self.absolute(target);
+ var sourceNode = self._root._walk(source)._follow(source);
+ if (!sourceNode.isFile()) {
+ throw new Error("Can't link non-file: " + source);
+ }
+ var directory = self.directory(target);
+ var base = self.base(target);
+ var targetNode = self._root._walk(directory)._follow(directory);
+ if (!targetNode.isDirectory()) {
+ throw new Error("Can't create link in non-directory: " + target);
+ }
+ if (targetNode._entries[base] && targetNode._entries[base].isDirectory()) {
+ throw new Error("Can't overwrite existing directory with hard link: " + target);
+ }
+ targetNode._entries[base] = sourceNode;
+ });
+};
- Node.prototype.lastModified = function () {
- return now;
- };
+MockFs.prototype.symbolicLink = function (target, relative, type) {
+ var self = this;
+ return Q.fcall(function () {
+ target = self.absolute(target);
+ var directory = self.directory(target);
+ var base = self.base(target);
+ var node = self._root._walk(directory);
+ if (node._entries[base] && node._entries[base].isDirectory()) {
+ throw new Error("Can't overwrite existing directory with symbolic link: " + target);
+ }
+ node._entries[base] = new LinkNode(self, relative);
+ });
+};
- COMMON.update(fs, function () {
- return fs.ROOT;
+MockFs.prototype.chown = function (path, owner) {
+ var self = this;
+ return Q.fcall(function () {
+ path = self.absolute(path);
+ self._root._walk(path)._follow(path)._owner = owner;
});
+};
- init();
+MockFs.prototype.chmod = function (path, mode) {
+ var self = this;
+ return Q.fcall(function () {
+ path = self.absolute(path);
+ self._root._walk(path)._follow(path)._mode = mode;
+ });
+};
- return fs;
-}
+MockFs.prototype.move = function (source, target) {
+ var self = this;
+ return Q.fcall(function () {
+ source = self.absolute(source);
+ target = self.absolute(target);
+ var sourceDirectory = self.directory(source);
+ var sourceDirectoryNode = self._root._walk(sourceDirectory)._follow(sourceDirectory);
+ var sourceName = self.base(source);
+ var sourceNode = sourceDirectoryNode._entries[sourceName]; // not followed
+ var targetDirectory = self.directory(target);
+ var targetDirectoryNode = self._root._walk(targetDirectory)._follow(targetDirectory);
+ var targetName = self.base(target);
+ if (targetDirectoryNode._entries[targetName] && targetDirectoryNode._entires[targetName].isDirectory()) {
+ // move the node into the directory
+ targetDirectoryNode = targetDirectoryNode._entries[targetName]._follow(target);
+ }
+ targetDirectoryNode._entries[targetName] = sourceNode;
+ delete sourceDirectoryNode._entries[sourceName];
+ });
+};
+
+MockFs.prototype.readLink = function (path) {
+ var self = this;
+ return Q.fcall(function () {
+ path = self.absolute(path);
+ var node = self._root._walk(path);
+ if (!self.isSymbolicLink()) {
+ throw new Error("Can't read non-symbolic link: " + path);
+ }
+ return node._link;
+ });
+};
+
+MockFs.prototype.canonical = function (path) {
+ var self = this;
+ return Q.fcall(function () {
+ path = self.absolute(path);
+ return self._root._canonical(path);
+ });
+};
MockFs.mock = mock;
function mock(fs, root) {
@@ -165,39 +312,178 @@ function mock(fs, root) {
});
}
-var GenericNode = function () {};
+function Node(fs) {
+ if (!fs)
+ throw new Error("FS required argument");
+ this._fs = fs;
+ this._accessed = this._modified = new Date();
+ this._mode = parseInt("0644", 8);
+ this._owner = null;
+}
+
+Node.prototype._walk = function (path, make, via) {
+ var parts = this._fs.split(path);
+ if (this._fs.isAbsolute(path)) {
+ parts.shift();
+ return this._fs._root._walkParts(parts, make, this._fs.ROOT);
+ } else {
+ return this._walkParts(parts, make, via || this._fs.ROOT);
+ }
+};
+
+Node.prototype._walkParts = function (parts, make, via) {
+ if (parts.length === 0) {
+ return this;
+ } else {
+ var part = parts.shift();
+ if (part === "") {
+ return this._walkParts(parts, make, this._fs.join(via, part));
+ } else {
+ throw new Error("Can't find " + JSON.stringify(this._fs.resolve(part, this._fs.join(parts))) + " via " + JSON.stringify(via));
+ }
+ }
+};
+
+Node.prototype._canonical = function (path) {
+ if (!this._fs.isAbsolute(path)) {
+ throw new Error("Path must be absolute for _canonical: " + path);
+ }
+ var parts = this._fs.split(path);
+ parts.shift();
+ var via = this._fs.ROOT;
+ return via + this._fs._root._canonicalParts(parts, via);
+};
+
+Node.prototype._canonicalParts = function (parts, via) {
+ if (parts.length === 0) {
+ return via;
+ }
+ return this._fs.join(via, this._fs.join(parts));
+};
+
+Node.prototype._follow = function () {
+ return this;
+};
+
+Node.prototype._touch = function () {
+ this._modified = new Date();
+};
+
+var stats = [
+ "isDirectory",
+ "isFile",
+ "isBlockDevice",
+ "isCharacterDevice",
+ "isSymbolicLink",
+ "isFIFO",
+ "isSocket"
+];
+
+stats.forEach(function (name) {
+ Node.prototype[name] = function () {
+ return false;
+ };
+});
+
+Node.prototype.lastAccessed = function () {
+ return this._accessed;
+};
+
+Node.prototype.lastModified = function () {
+ return this._modified;
+};
+
+function FileNode(fs) {
+ Node.call(this, fs);
+ this._chunks = [];
+}
+
+FileNode.prototype = Object.create(Node.prototype);
+
+FileNode.prototype.isFile = function () {
+ return true;
+};
+
+function DirectoryNode(fs) {
+ Node.call(this, fs);
+ this._entries = Object.create(null);
+ this._mode = parseInt("0755", 8);
+}
+
+DirectoryNode.prototype = Object.create(Node.prototype);
+
+DirectoryNode.prototype.isDirectory = function () {
+ return true;
+};
+
+DirectoryNode.prototype._walkParts = function (parts, make, via) {
+ via = via || this._fs.ROOT;
+ if (parts.length === 0) {
+ return this;
+ }
+ var part = parts.shift();
+ if (part === "") {
+ return this._walkParts(parts, make, this._fs.join(via, part));
+ }
+ if (!this._entries[part]) {
+ if (make) {
+ this._entries[part] = new DirectoryNode(this._fs);
+ } else {
+ throw new Error("Can't find " + JSON.stringify(this._fs.join(parts)) + " via " + JSON.stringify(via));
+ }
+ }
+ return this._entries[part]._walkParts(parts, make, this._fs.join(via, part));
+};
+
+DirectoryNode.prototype._canonicalParts = function (parts, via) {
+ if (parts.length === 0) {
+ return via;
+ }
+ var part = parts.shift();
+ if (part === "") {
+ return via;
+ }
+ if (via === this._fs.ROOT) {
+ via = "";
+ }
+ if (!this._entries[part]) {
+ return this._fs.join(via, part, this._fs.join(parts));
+ }
+ return this._entries[part]._canonicalParts(
+ parts,
+ this._fs.join(via, part)
+ );
+};
+
+function LinkNode(fs, link) {
+ Node.call(this, fs);
+ this._link = link;
+}
+
+LinkNode.prototype = Object.create(Node.prototype);
+
+LinkNode.prototype.isSymbolicLink = function () {
+ return true;
+};
-GenericNode.prototype.exists = function () {
- var node = this.get();
- return typeof node !== "undefined";
+LinkNode.prototype._follow = function (via, memo) {
+ memo = memo || Set();
+ if (memo.has(this)) {
+ throw new Error("Can't follow symbolic link cycle at " + JSON.stringify(via));
+ }
+ memo.add(this);
+ var link = this._fs.join(via, "..", this._link);
+ return this._walk(link, null, "<link>")._follow(link, memo);
};
-GenericNode.prototype.isFile = function () {
- var node = this.get();
- return typeof node !== "undefined" && (
- typeof node !== "object" ||
- node.constructor !== Object
+LinkNode.prototype._canonicalParts = function (parts, via) {
+ return this._fs.relativeFromDirectory(this._fs.ROOT,
+ this._fs._root._canonical(
+ this._fs.absolute(this._fs.join(via, "..", this._link))
+ )
);
};
-GenericNode.prototype.isDirectory = function () {
- var node = this.get();
- return (
- typeof node === "object" &&
- node.constructor === Object
- )
-};
-
-}).apply(null, typeof exports !== "undefined" ?
- [require, exports] :
- [
- function (id) {
- id = id.toUpperCase()
- .replace(".", "Q_FS")
- .replace("/", "$")
- .replace("-", "_");
- return window[id];
- },
- Q_FS$MOCK
- ]
-)
+// cycle breaking
+var FS = require("./fs");
+
View
2  fs-root.js
@@ -42,7 +42,7 @@ function RootFs(outer, root) {
"outer": actual
};
} else {
- return Q.reject("No such file: " + JSON.stringify(path));
+ return Q.reject("Can't find: " + JSON.stringify(path));
}
});
}
View
47 fs.js
@@ -76,6 +76,8 @@ exports.open = dampen(function (path, flags, charset, options) {
if (charset) {
throw new Error("Can't open a binary file with a charset: " + charset);
}
+ } else {
+ charset = charset || 'utf-8';
}
if (flags.indexOf("w") >= 0) {
var stream = FS.createWriteStream(String(path), nodeOptions);
@@ -170,7 +172,7 @@ exports.stat = function (path) {
error.message = "Can't stat " + JSON.stringify(path) + ": " + error;
done.reject(error);
} else {
- done.resolve(new self.Stats(stat));
+ done.resolve(new Stats(stat));
}
});
} catch (error) {
@@ -179,6 +181,35 @@ exports.stat = function (path) {
return done.promise;
};
+var Stats = function (nodeStat) {
+ this.node = nodeStat;
+ this.size = nodeStat.size;
+};
+
+var stats = [
+ "isDirectory",
+ "isFile",
+ "isBlockDevice",
+ "isCharacterDevice",
+ "isSymbolicLink",
+ "isFIFO",
+ "isSocket"
+];
+
+stats.forEach(function (name) {
+ Stats.prototype[name] = function () {
+ return this.node[name]();
+ };
+});
+
+Stats.prototype.lastModified = function () {
+ return new Date(this.node.mtime);
+};
+
+Stats.prototype.lastAccessed = function () {
+ return new Date(this.node.atime);
+};
+
exports.statLink = function (path) {
path = String(path);
var done = Q.defer();
@@ -265,12 +296,6 @@ exports.symbolicLink = function (target, relative, type) {
return done.promise;
};
-exports.symbolicCopy = function (source, target) {
- return Q.when(exports.relative(target, source), function (relative) {
- return exports.symbolicLink(target, relative, "file");
- });
-};
-
exports.chown = function (path, uid, gid) {
path = String(path);
var done = Q.defer();
@@ -308,14 +333,6 @@ exports.chmod = function (path, mode) {
return done.promise;
};
-exports.lastModified = function (path) {
- return exports.stat(path).invoke('lastModified');
-};
-
-exports.lastAccessed = function (path) {
- return exports.stat(path).invoke('lastAccessed');
-};
-
exports.canonical = function (path) {
var result = Q.defer();
FS.realpath(path, function (error, canonicalPath) {
View
5 reader.js
@@ -20,9 +20,6 @@ function Reader(_stream, charset) {
var begin = Q.defer();
var end = Q.defer();
- // prevent indefinite buffering; resume on demand
- //_stream.pause();
-
_stream.on("error", function (reason) {
begin.reject(reason);
});
@@ -62,7 +59,6 @@ function Reader(_stream, charset) {
*/
self.read = function () {
receiver = undefined;
- //_stream.resume();
var deferred = Q.defer();
Q.done(end.promise, function () {
deferred.resolve(slurp());
@@ -79,7 +75,6 @@ function Reader(_stream, charset) {
* be resolved when the input is depleted.
*/
self.forEach = function (write) {
- //_stream.resume();
if (chunks && chunks.length)
write(slurp());
receiver = write;
View
17 test/fs/boot-directory.js → spec/fs/boot-directory-spec.js
@@ -1,7 +1,7 @@
var FS = require("../../fs-boot");
-[
+var specs = [
{
"from": "foo",
"to": ""
@@ -34,12 +34,13 @@ var FS = require("../../fs-boot");
"from": "/",
"to": "/"
}
-].forEach(function (test) {
- exports['test ' + test.from] = function (assert) {
- assert.equal(FS.directory(test.from), test.to, 'ok');
- };
-});
+];
-if (require.main == module)
- require("test").run(exports);
+describe("fs-boot directory", function () {
+ specs.forEach(function (spec) {
+ it("should parse " + JSON.stringify(spec.from), function () {
+ expect(FS.directory(spec.from)).toBe(spec.to);
+ });
+ });
+});
View
33 spec/fs/issues/1-spec.js
@@ -0,0 +1,33 @@
+
+require("../../lib/jasmine-promise");
+var Q = require("q");
+var FS = require("../../../fs");
+
+describe("write and remove", function () {
+
+ it("should write and remove a file", function () {
+
+ var fixture = FS.join(__dirname, "fixture.txt");
+
+ return FS.write(fixture, "1234")
+ .then(function (result) {
+ expect(result).toBe(undefined);
+ })
+
+ .then(function () {
+ return FS.remove(fixture);
+ })
+ .then(function (result) {
+ expect(result).toBe(undefined);
+ })
+
+ .then(function () {
+ return FS.exists(fixture)
+ })
+ .then(function (exists) {
+ expect(exists).toBe(false);
+ })
+
+ });
+});
+
View
56 spec/fs/mock/copy-tree-spec.js
@@ -0,0 +1,56 @@
+"use strict";
+
+require("../../lib/jasmine-promise");
+var Q = require("q");
+var FS = require("../../../fs");
+var Mock = require("../../../fs-mock");
+
+describe("copyTree", function () {
+ it("should copy a tree", function () {
+
+ var mock = Mock({
+ "a/b": {
+ "c": {
+ "d": 66,
+ "e": 99
+ }
+ }
+ });
+
+ return Q.fcall(function () {
+ return mock.copyTree("a/b", "a/f");
+ })
+ .then(function () {
+ return Q.all([
+ mock.isDirectory("a/f"),
+ mock.exists("a/f/c"),
+ mock.isFile("a/f/c/d"),
+ mock.read("a/f/c/e")
+ ])
+ })
+ .then(function (existence) {
+ expect(existence.every(Boolean)).toBe(true);
+ })
+
+ .then(function () {
+ return mock.listTree();
+ })
+ .then(function (list) {
+ expect(list).toEqual([
+ ".",
+ "a",
+ "a/b",
+ "a/b/c",
+ "a/b/c/d",
+ "a/b/c/e",
+ "a/f",
+ "a/f/c",
+ "a/f/c/d",
+ "a/f/c/e"
+ ]);
+ })
+
+ });
+
+});
+
View
0  test/fs/mock/dummy/hello.txt → spec/fs/mock/dummy/hello.txt
File renamed without changes
View
0  test/fs/fixtures/1234.txt → spec/fs/mock/fixtures/1234.txt
File renamed without changes
View
69 spec/fs/mock/link-spec.js
@@ -0,0 +1,69 @@
+
+require("../../lib/jasmine-promise");
+var MockFs = require("../../../fs-mock");
+
+describe("link", function () {
+ it("should", function () {
+ var mock = MockFs();
+
+ // make some content
+ return mock.makeTree("a/b")
+ .then(function () {
+ return mock.write("a/b/c.txt", "Hello, World!")
+ })
+
+ // verify content
+ .then(function () {
+ return mock.read("a/b/c.txt")
+ })
+ .then(function (content) {
+ expect(content).toBe("Hello, World!");
+ })
+
+ // link it
+ .then(function () {
+ return mock.link("a/b/c.txt", "a/b/d.txt")
+ })
+
+ // should be non-destructive
+ .then(function () {
+ return mock.read("a/b/c.txt")
+ })
+ .then(function (content) {
+ expect(content).toBe("Hello, World!");
+ })
+
+ // should be listed
+ .then(function () {
+ return mock.listTree()
+ })
+ .then(function (content) {
+ expect(content).toEqual([
+ ".",
+ "a",
+ "a/b",
+ "a/b/c.txt",
+ "a/b/d.txt"
+ ])
+ })
+
+ // should be identified as a file
+ .then(function () {
+ return mock.isFile("a/b/d.txt");
+ })
+ .then(function (isFile) {
+ expect(isFile).toBe(true);
+ })
+
+ // should have the same content
+ .then(function () {
+ return mock.read("a/b/d.txt");
+ })
+ .then(function (content) {
+ expect(content).toBe("Hello, World!");
+ });
+
+ });
+});
+
+
View
48 spec/fs/mock/make-tree-spec.js
@@ -0,0 +1,48 @@
+"use strict";
+
+require("../../lib/jasmine-promise");
+var Q = require("q");
+var FS = require("../../../fs");
+var Mock = require("../../../fs-mock");
+
+describe("makeTree", function () {
+ it("should make a branch of a tree", function () {
+
+ var mock = Mock({
+ "a": {}
+ });
+
+ return Q.fcall(function () {
+ return mock.makeTree("a/b/c");
+ })
+
+ .then(function () {
+ return mock.listTree();
+ })
+ .then(function (list) {
+ expect(list).toEqual([
+ ".",
+ "a",
+ "a/b",
+ "a/b/c"
+ ]);
+ })
+
+ .then(function () {
+ return mock.exists("a/b/c")
+ })
+ .then(function (exists) {
+ expect(exists).toBe(true);
+ })
+
+ .then(function () {
+ return mock.isDirectory("a/b/c")
+ })
+ .then(function (isDirectory) {
+ expect(isDirectory).toBe(true);
+ })
+
+ });
+
+});
+
View
66 spec/fs/mock/merge-spec.js
@@ -0,0 +1,66 @@
+"use strict";
+
+require("../../lib/jasmine-promise");
+var Q = require("q");
+var FS = require("../../../fs");
+var Mock = require("../../../fs-mock");
+
+describe("makeTree", function () {
+ it("should make a branch of a tree", function () {
+
+ var merged = FS.merge([
+ Mock({
+ "a": 10,
+ "b": 20,
+ "1/2/3": "123"
+ }),
+ Mock({
+ "a": 20,
+ "c": 30
+ }),
+ Mock({
+ "a": 30,
+ "d": 40
+ }),
+ ])
+
+ return merged.then(function (merged) {
+
+ return Q.fcall(function () {
+ return merged.listTree();
+ })
+ .then(function (list) {
+ expect(list.sort()).toEqual([
+ ".",
+ "1",
+ "1/2",
+ "1/2/3",
+ "a",
+ "b",
+ "c",
+ "d",
+ ]);
+ })
+
+ // overridden by a previous tree
+ .then(function () {
+ return merged.read("a");
+ })
+ .then(function (a) {
+ expect(a).toBe("30");
+ })
+
+ // not overridden
+ .then(function () {
+ return merged.read("b");
+ })
+ .then(function (a) {
+ expect(a).toBe("20");
+ })
+
+ })
+
+ });
+
+});
+
View
59 spec/fs/mock/move-spec.js
@@ -0,0 +1,59 @@
+"use strict";
+
+require("../../lib/jasmine-promise");
+var Q = require("q");
+var FS = require("../../../fs");
+
+describe("move", function () {
+ it("should move", function () {
+
+ return FS.mock(FS, FS.join(__dirname, "dummy"))
+ .then(function (mock) {
+
+ // initial list
+ return Q.fcall(function () {
+ return mock.listTree()
+ })
+ .then(function (list) {
+ expect(list).toEqual([
+ ".",
+ "hello.txt"
+ ]);
+ })
+
+ // initial content
+ .then(function () {
+ return mock.read("hello.txt");
+ })
+ .then(function (content) {
+ expect(content).toBe("Hello, World!\n");
+ })
+
+ // move!
+ .then(function () {
+ return mock.move("hello.txt", "new-hello.txt");
+ })
+
+ // list after
+ .then(function () {
+ return mock.listTree();
+ })
+ .then(function (list) {
+ expect(list).toEqual([
+ ".",
+ "new-hello.txt"
+ ]);
+ })
+
+ // content after
+ .then(function () {
+ return mock.read("new-hello.txt");
+ })
+ .then(function (content) {
+ expect(content).toBe("Hello, World!\n");
+ })
+
+ });
+ });
+});
+
View
20 spec/fs/mock/object-spec.js
@@ -0,0 +1,20 @@
+"use strict";
+
+require("../../lib/jasmine-promise");
+var Q = require("q");
+var FS = require("../../../fs");
+
+describe("toObject", function () {
+ it("should take a snapshot of a tree", function () {
+
+ return FS.mock(FS, FS.join(__dirname, "dummy"))
+ .invoke("toObject")
+ .then(function (tree) {
+
+ expect(tree["hello.txt"].toString("utf-8")).toEqual("Hello, World!\n");
+ expect(Object.keys(tree)).toEqual(["hello.txt"]);
+
+ });
+ });
+});
+
View
26 spec/fs/mock/range-spec.js
@@ -0,0 +1,26 @@
+"use strict";
+
+require("../../lib/jasmine-promise");
+var Q = require("q");
+var FS = require("../../../fs");
+var Mock = require("../../../fs-mock");
+
+describe("open range", function () {
+ it("read a partial range of a file", function () {
+
+ return FS.mock(FS, FS.join(__dirname, "dummy"))
+ .then(function (mock) {
+
+ return mock.read("hello.txt", {
+ begin: 1,
+ end: 3
+ })
+ .then(function (content) {
+ expect(content).toBe("el");
+ })
+
+ });
+
+ });
+});
+
View
23 spec/fs/mock/read-spec.js
@@ -0,0 +1,23 @@
+"use strict";
+
+require("../../lib/jasmine-promise");
+var Q = require("q");
+var FS = require("../../../fs");
+
+describe("read", function () {
+ it("should read a file from a mock filesystem", function () {
+
+ return FS.mock(FS, FS.join(__dirname, "dummy"))
+ .then(function (mock) {
+
+ return Q.fcall(function () {
+ return mock.read("hello.txt");
+ })
+ .then(function (content) {
+ expect(content).toBe("Hello, World!\n");
+ })
+
+ });
+ });
+});
+
View
37 spec/fs/mock/remove-directory-spec.js
@@ -0,0 +1,37 @@
+"use strict";
+
+require("../../lib/jasmine-promise");
+var Q = require("q");
+var FS = require("../../../fs");
+
+describe("removeDirectory", function () {
+ it("should remove a directory", function () {
+
+ return FS.mock(FS, FS.join(__dirname))
+ .then(function (mock) {
+
+ // now you see it
+ return Q.fcall(function () {
+ return mock.isDirectory("dummy");
+ })
+ .then(function (isDirectory) {
+ expect(isDirectory).toBe(true);
+ })
+
+ .then(function () {
+ return mock.removeDirectory("dummy");
+ })
+
+ // now you don't
+ .then(function () {
+ return mock.isDirectory("dummy");
+ })
+ .then(function (isDirectory) {
+ expect(isDirectory).toBe(false);
+ })
+
+ });
+
+ });
+});
+
View
38 spec/fs/mock/remove-tree-spec.js
@@ -0,0 +1,38 @@
+"use strict";
+
+require("../../lib/jasmine-promise");
+var Q = require("q");
+var FS = require("../../../fs");
+var Mock = require("../../../fs-mock");
+
+describe("removeTree", function () {
+ it("should remove a tree", function () {
+
+ var mock = Mock({
+ "a/b": {
+ "c": {
+ "d": 66,
+ "e": 99
+ }
+ }
+ });
+
+ return Q.fcall(function () {
+ return mock.removeTree("a/b/c");
+ })
+
+ .then(function () {
+ return mock.listTree();
+ })
+ .then(function (list) {
+ expect(list).toEqual([
+ ".",
+ "a",
+ "a/b"
+ ]);
+ })
+
+ });
+
+});
+
View
32 spec/fs/mock/root-spec.js
@@ -0,0 +1,32 @@
+"use strict";
+
+require("../../lib/jasmine-promise");
+var Q = require("q");
+var FS = require("../../../fs");
+var Mock = require("../../../fs-mock");
+var Root = require("../../../fs-root");
+
+describe("root", function () {
+ it("should make a filesystem from a subtree of a mock filesystem", function () {
+
+ var mock = Mock({
+ "a/b/1": 10,
+ "a/b/2": 20,
+ "a/b/3": 30
+ });
+
+ var chroot = Root(mock, "a/b");
+
+ return chroot.invoke("listTree")
+ .then(function (list) {
+ expect(list).toEqual([
+ ".",
+ "1",
+ "2",
+ "3"
+ ]);
+ });
+
+ });
+});
+
View
85 spec/fs/mock/symbolic-link-spec.js
@@ -0,0 +1,85 @@
+
+require("../../lib/jasmine-promise");
+var MockFs = require("../../../fs-mock");
+
+describe("symbolic link", function () {
+ it("should", function () {
+ var mock = MockFs();
+
+ // make some content
+ return mock.makeTree("a/b")
+ .then(function () {
+ return mock.write("a/b/c.txt", "Hello, World!")
+ })
+
+ // verify content
+ .then(function () {
+ return mock.read("a/b/c.txt")
+ })
+ .then(function (content) {
+ expect(content).toBe("Hello, World!");
+ })
+
+ // link it
+ .then(function () {
+ return mock.symbolicCopy("/a/b/c.txt", "a/b/d.txt", "file")
+ })
+
+ // should have a link
+ .then(function () {
+ return mock.readLink("a/b/d.txt")
+ })
+ .then(function (link) {
+ expect(link).toBe("c.txt");
+ })
+
+ // should have a canonical path
+ .then(function () {
+ return mock.canonical("a/b/d.txt")
+ })
+ .then(function (canonical) {
+ expect(canonical).toBe("/a/b/c.txt");
+ })
+
+ // should be listed
+ .then(function () {
+ return mock.listTree()
+ })
+ .then(function (content) {
+ expect(content).toEqual([
+ ".",
+ "a",
+ "a/b",
+ "a/b/c.txt",
+ "a/b/d.txt"
+ ])
+ })
+
+ // should be non-destructive
+ .then(function () {
+ return mock.read("a/b/c.txt")
+ })
+ .then(function (content) {
+ expect(content).toBe("Hello, World!");
+ })
+
+ // should be identified as a file
+ .then(function () {
+ return mock.isSymbolicLink("a/b/d.txt");
+ })
+ .then(function (isSymbolicLink) {
+ expect(isSymbolicLink).toBe(true);
+ })
+
+ // should have the same content
+ .then(function () {
+ return mock.read("a/b/d.txt");
+ })
+ .then(function (content) {
+ expect(content).toBe("Hello, World!");
+ });
+
+ });
+});
+
+
View
26 spec/fs/mock/write-spec.js
@@ -0,0 +1,26 @@
+"use strict";
+
+require("../../lib/jasmine-promise");
+var Q = require("q");
+var FS = require("../../../fs");
+
+describe("write", function () {
+ it("should write a file to a mock filesystem", function () {
+
+ return FS.mock(FS, FS.join(__dirname, "dummy"))
+ .then(function (mock) {
+
+ return Q.fcall(function () {
+ return mock.write("hello.txt", "Goodbye!\n");
+ })
+ .then(function () {
+ return mock.isFile("hello.txt");
+ })
+ .then(function (isFile) {
+ expect(isFile).toBe(true);
+ })
+
+ });
+ });
+});
+
View
23 spec/fs/range-spec.js
@@ -0,0 +1,23 @@
+"use strict";
+
+require("../lib/jasmine-promise");
+var Q = require("q");
+var FS = require("../../fs");
+
+describe("open range", function () {
+ it("read a partial range of a file", function () {
+
+ var name = FS.join(module.directory || __dirname, "range-spec.txt");
+
+ return FS.open(name, {
+ begin: 1,
+ end: 3
+ })
+ .invoke("read")
+ .then(function (content) {
+ expect(content).toBe("23");
+ })
+
+ });
+});
+
View
1  spec/fs/range-spec.txt
@@ -0,0 +1 @@
+1234
View
42 spec/lib/jasmine-promise.js
@@ -0,0 +1,42 @@
+"use strict";
+
+var Q = require("q");
+
+/**
+ * Modifies the way that individual specs are run to easily test async
+ * code with promises.
+ *
+ * A spec may return a promise. If it does, then the spec passes if and
+ * only if that promise is fulfilled within a very short period of time.
+ * If it is rejected, or if it isn't fulfilled quickly, the spec fails.
+ *
+ * In this way, we can use promise chaining to structure our asynchronous
+ * tests. Expectations all down the chain of promises are all checked and
+ * guaranteed to be run and resolved or the test fails.
+ *
+ * This is a big win over the runs() and watches() code that jasmine
+ * supports out of the box.
+ */
+jasmine.Block.prototype.execute = function (onComplete) {
+ var spec = this.spec;
+ try {
+ var result = this.func.call(spec, onComplete);
+
+ // It seems Jasmine likes to return the suite if you pass it anything.
+ // So make sure it's a promise first.
+ if (result && typeof result.then === "function") {
+ Q.timeout(result, 500).then(function () {
+ onComplete();
+ }, function (error) {
+ spec.fail(error);
+ onComplete();
+ });
+ } else if (this.func.length === 0) {
+ onComplete();
+ }
+ } catch (error) {
+ spec.fail(error);
+ onComplete();
+ }
+};
+
View
2  test/all.js
@@ -1,8 +1,6 @@
-exports["test fs"] = require("./fs/all");
exports["test http"] = require("./http/all");
exports["test http apps"] = require("./http-apps/all");
-exports["test issue 1"] = require("./issues/1");
if (require.main === module) {
require("test").run(exports);
View
17 test/fs/all.js
@@ -1,17 +0,0 @@
-'use strict'
-
-exports['test mock/merge'] = require('./mock/merge');
-exports['test mock/read'] = require('./mock/read');
-exports['test mock/subtree'] = require('./mock/subtree');
-exports['test mock/write'] = require('./mock/write');
-exports['test mock/move'] = require('./mock/move');
-exports['test mock/removeDirectory'] = require('./mock/remove-directory');
-exports['test mock/copyTree'] = require('./mock/copy-tree');
-exports['test mock/makeTree'] = require('./mock/make-tree');
-exports['test mock/removeTree'] = require('./mock/remove-tree');
-exports['test root mock'] = require('./root');
-exports['test partial'] = require("./partial");
-
-if (module == require.main)
- require('test').run(exports)
-
View
25 test/fs/issues/1.js
@@ -1,25 +0,0 @@
-
-var Q = require("q");
-var FS = require("../../../fs");
-
-exports["test write/remove"] = function (assert, done) {
- var fileName = FS.join(module.directory || __dirname, "fixture.txt");
-
- FS.write(fileName, "1234")
- .then(function (data) {
- assert.equal(data, undefined, 'written');
- return FS.remove(fileName).then(function (data) {
- assert.equal(data, undefined, 'removed');
- return FS.isFile(fileName).then(function (isFile) {
- assert.equal(isFile, false, 'confirmed removal');
- });
- });
- })
- .fin(done)
- .done()
-
-};
-
-if (require.main === module)
- require("test").run(exports);
-
View
32 test/fs/lazy.js
@@ -1,32 +0,0 @@
-
-var Q = require("q");
-var FS = require("../q-fs");
-
-exports['test lazy list mock'] = function (ASSERT, done) {
- var fs = FS.Mock({
- "a": 1,
- "a/b": 2,
- "a/b/c": 3
- });
- var tree = fs.listTree("");
- ASSERT.ok(Q.isPromise(tree), 'tree is promise');
- var results = [".", "a", "a/b", "a/b/c"];
- fs.listTree("").forEach(function (name, i) {
- ASSERT.equal(name, results.shift(), 'tree is lazy array: ' + i);
- })
- .fin(done)
- .done()
-};
-
-exports['test lazy stat'] = function (ASSERT, done) {
- // the isFile should not throw an exception
- FS.stat(__filename)
- .isFile()
- .fin(done)
- .done()
-};
-
-if (require.main === module) {
- require("test").run(exports);
-}
-
View
35 test/fs/mock/copy-tree.js
@@ -1,35 +0,0 @@
-"use strict";
-
-var Q = require("q");
-var FS = require("../../../fs");
-var Root = FS.Root;
-var Mock = FS.Mock;
-var ASSERT = require("assert");
-
-exports['test removeTree'] = function (ASSERT, done) {
-
- // constructs a mock file-system API object
- var mock = Mock({
- "a/b/c/d": 66,
- "a/b/c/e": 99
- });
-
- Q.when(mock, function (mock) {
- return mock.copyTree("a/b", "a/f").then(function () {
- return [mock.exists("a/f"), mock.exists("a/f/c"), mock.exists("a/f/c/d"), mock.exists("a/f/c/e")]
- }).spread(function (fExists, cExists, dExists, eExists) {
- return ASSERT.ok(fExists && cExists && dExists && eExists, "tree copied");
- });
- })
- .catch(function (error) {
- ASSERT.ok(false, error);
- })
- .finally(done)
-
-
-};
-
-if (require.main === module) {
- require("test").run(exports);
-}
-
View
34 test/fs/mock/make-tree.js
@@ -1,34 +0,0 @@
-"use strict";
-
-var Q = require("q");
-var FS = require("../../../fs");
-var Root = FS.Root;
-var Mock = FS.Mock;
-var ASSERT = require("assert");
-
-exports['test makeTree'] = function (ASSERT, done) {
-
- // constructs a mock file-system API object
- var mock = Mock({
- "a": {}
- });
-
- Q.when(mock, function (mock) {
- return mock.makeTree("a/b/c").then(function () {
- return mock.exists("a/b/c")
- }).then(function (exists) {
- return ASSERT.ok(exists === true, "tree made");
- });
- })
- .catch(function (error) {
- ASSERT.ok(false, error);
- })
- .finally(done)
-
-
-};
-
-if (require.main === module) {
- require("test").run(exports);
-}
-
View
51 test/fs/mock/merge.js
@@ -1,51 +0,0 @@
-"use strict";
-
-var Q = require("q");
-var FS = require("../../../fs");
-var Root = require("../../../fs-root");
-var Mock = require("../../../fs-mock");
-var ASSERT = require("assert");
-
-exports['test merge'] = function (ASSERT, done) {
-
- var merged = FS.merge([
- Mock({
- "a": 10,
- "b": 20,
- "1/2/3": "123"
- }),
- Mock({
- "a": 20,
- "c": 30
- }),
- Mock({
- "a": 30,
- "d": 40
- }),
- ])
-
- Q.when(merged, function (merged) {
- return Q.when(merged.listTree(), function (list) {
- ASSERT.deepEqual(list.sort(), [
- ".", "a", "b", "c", "d", "1", "1/2", "1/2/3"
- ].sort(), 'listTree');
- }).then(function () {
- return Q.when(merged.read("a", "rb"), function (a) {
- ASSERT.deepEqual(a, 30, 'read overridden');
- });
- }).then(function () {
- return Q.when(merged.read("b", "rb"), function (a) {
- ASSERT.deepEqual(a, 20, 'read non-overridden');
- });
- });
- })
- .fin(done)
- .done()
-
-};
-
-if (require.main === module) {
- require("test").run(exports);
-}
-
-
View
37 test/fs/mock/move.js
@@ -1,37 +0,0 @@
-"use strict";
-
-var Q = require("q");
-var FS = require("../../../fs");
-var Root = FS.Root;
-var Mock = FS.Mock;
-var ASSERT = require("assert");
-
-exports['test move'] = function (ASSERT, done) {
-
- var mock = FS.mock(FS, FS.join(__dirname, 'dummy'));
-
- Q.when(mock, function (mock) {
- return Q.when(mock.listTree(), function (list) {
- ASSERT.deepEqual(list.sort(), [
- ".", "hello.txt"
- ].sort(), "listTree");
- }).then(function () {
- return mock.move("hello.txt", "new-hello.txt");
- }).then(function () {
- return Q.when(mock.listTree(), function (list) {
- ASSERT.deepEqual(list.sort(), [
- ".", "new-hello.txt"
- ].sort(), "move file");
- });
- });
- })
- .catch(function (error) {
- ASSERT.ok(false, error);
- })
- .finally(done)
-
-};
-
-if (require.main === module) {
- require("test").run(exports);
-}
View
28 test/fs/mock/object.js
@@ -1,28 +0,0 @@
-"use strict";
-
-var Q = require("q");
-var FS = require("../../../fs");
-var Root = require("../../../fs").Root;
-var Mock = require("../../../fs").Mock;
-var ASSERT = require("assert");
-
-exports['test merge'] = function (ASSERT, done) {
-
- var input = {
- "a": 10,
- "b": 20
- };
- var output = Mock(input).toObject();
- Q.when(output, function (output) {
- ASSERT.deepEqual(output, input, 'toObject');
- })
- .fin(done)
- .done()
-
-};
-
-if (require.main === module) {
- require("test").run(exports);
-}
-
-
View
35 test/fs/mock/read.js
@@ -1,35 +0,0 @@
-"use strict";
-
-var Q = require("q");
-var FS = require("../../../fs");
-var Root = FS.Root;
-var Mock = FS.Mock;
-var ASSERT = require("assert");
-
-exports['test read'] = function (ASSERT, done) {
-
- var mock = FS.mock(FS, FS.join(__dirname, 'dummy'));
-
- Q.when(mock, function (mock) {
- return Q.when(mock.listTree(), function (list) {
- ASSERT.deepEqual(list.sort(), [
- ".", "hello.txt"
- ].sort(), "listTree");
- }).then(function () {
- return Q.when(mock.read("hello.txt"), function (hello) {
- ASSERT.strictEqual(hello, 'Hello, World!\n', 'read content');
- });
- });
- })
- .catch(function (error) {
- ASSERT.ok(false, error);
- })
- .finally(done)
-
-};
-
-if (require.main === module) {
- require("test").run(exports);
-}
-
-
View
34 test/fs/mock/remove-directory.js
@@ -1,34 +0,0 @@
-"use strict";
-
-var Q = require("q");
-var FS = require("../../../fs");
-var Root = FS.Root;
-var Mock = FS.Mock;
-var ASSERT = require("assert");
-
-exports['test removeDirectory'] = function (ASSERT, done) {
-
- // constructs a mock file-system API object
- var mock = Mock({
- "folder": {}
- });
-
- Q.when(mock, function (mock) {
- return mock.removeDirectory("folder").then(function () {
- return mock.exists("folder")
- }).then(function (exists) {
- return ASSERT.ok(exists === false, "directory removed");
- });
- })
- .catch(function (error) {
- ASSERT.ok(false, error);
- })
- .finally(done)
-
-
-};
-
-if (require.main === module) {
- require("test").run(exports);
-}
-
View
34 test/fs/mock/remove-tree.js
@@ -1,34 +0,0 @@
-"use strict";
-
-var Q = require("q");
-var FS = require("../../../fs");
-var Root = FS.Root;
-var Mock = FS.Mock;
-var ASSERT = require("assert");
-
-exports['test removeTree'] = function (ASSERT, done) {
-
- // constructs a mock file-system API object
- var mock = Mock({
- "a/b/c/d": 1
- });
-
- Q.when(mock, function (mock) {
- return mock.removeTree("a/b").then(function () {
- return mock.exists("a/b")
- }).then(function (exists) {
- return ASSERT.ok(exists === false, "tree removed");
- });
- })
- .catch(function (error) {
- ASSERT.ok(false, error);
- })
- .finally(done)
-
-
-};
-
-if (require.main === module) {
- require("test").run(exports);
-}
-
View
47 test/fs/mock/subtree.js
@@ -1,47 +0,0 @@
-"use strict";
-
-var Q = require("q");
-var FS = require("../../../fs");
-var Root = FS.Root;
-var Mock = FS.Mock;
-var ASSERT = require("assert");
-
-exports['test mock'] = function (ASSERT, done) {
-
- // constructs a mock file-system API object
- var mock = Mock({
- "a/b/1": 10,
- "a/b/2": 20,
- "a/b/3": 30,
- "a/b/c": Mock({
- "d/e/f": "abcdef",
- "1/2/3": "abc123"
- }).getNode()
- });
-
- mock.listTree("").then(function (list) {
- ASSERT.deepEqual(list.sort(), [
- ".",
- "a",
- "a/b",
- "a/b/1",
- "a/b/2",
- "a/b/3",
- "a/b/c",
- "a/b/c/d",
- "a/b/c/d/e",
- "a/b/c/d/e/f",
- "a/b/c/1",
- "a/b/c/1/2",
- "a/b/c/1/2/3"
- ].sort(), "subtree list");
- })
- .fin(done)
- .done()
-
-};
-
-if (require.main === module) {
- require("test").run(exports);
-}
-
View
35 test/fs/mock/write.js
@@ -1,35 +0,0 @@
-"use strict";
-
-var Q = require("q");
-var FS = require("../../../fs");
-var Root = FS.Root;
-var Mock = FS.Mock;
-var ASSERT = require("assert");
-
-exports['test write'] = function (ASSERT, done) {
-
- var mock = FS.mock(FS, FS.join(__dirname, 'dummy'));
-
- Q.when(mock, function (mock) {
- return Q.when(mock.listTree(), function (list) {
- ASSERT.deepEqual(list.sort(), [
- ".", "hello.txt"
- ].sort(), "listTree");
- }).then(function () {
- return mock.write("hello.txt", 'Hello, New World!\n');
- }).then(function () {
- return Q.when(mock.read("hello.txt"), function (hello) {
- ASSERT.strictEqual(hello, 'Hello, New World!\n', 'write content');
- });
- });
- })
- .catch(function (error) {
- ASSERT.ok(false, error);
- })
- .finally(done)
-
-};
-
-if (require.main === module) {
- require("test").run(exports);
-}
View
25 test/fs/partial.js
@@ -1,25 +0,0 @@
-
-var FS = require("../../fs");
-
-module.exports = function (ASSERT, done) {
-
- var name = FS.join(
- module.directory || __dirname,
- "fixtures", "1234.txt"
- );
- FS.open(name, {
- begin: 1,
- end: 3
- })
- .invoke('read')
- .then(function (content) {
- ASSERT.equal(content, "23", "partial read");
- })
- .fin(done)
- .done()
-
-};
-
-if (module == require.main)
- require('test').run(module.exports)
-
View
52 test/fs/root.js
@@ -1,52 +0,0 @@
-"use strict";
-