[Pkg-javascript-commits] [node-fs-extra] 01/02: Imported Upstream version 0.16.5

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Sat Mar 21 01:38:26 UTC 2015


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository node-fs-extra.

commit 6d90c68db1c522421efe80411170b4ae45080df0
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Sat Mar 21 01:59:25 2015 +0100

    Imported Upstream version 0.16.5
---
 .gitignore                                         |   5 +
 .npmignore                                         |   3 +
 .travis.yml                                        |  10 +
 CHANGELOG.md                                       | 191 ++++++++++
 LICENSE                                            |  15 +
 README.md                                          | 411 +++++++++++++++++++++
 lib/_copy.js                                       | 250 +++++++++++++
 lib/copy.js                                        |  99 +++++
 lib/create.js                                      |  39 ++
 lib/index.js                                       |  90 +++++
 lib/json.js                                        |  31 ++
 lib/mkdir.js                                       | 103 ++++++
 lib/move.js                                        | 136 +++++++
 lib/output.js                                      |  34 ++
 lib/remove.js                                      |  14 +
 package.json                                       |  59 +++
 test/copy-sync.test.js                             | 223 +++++++++++
 test/copy.test.js                                  | 238 ++++++++++++
 test/create.test.js                                |  65 ++++
 test/ensure.test.js                                | 122 ++++++
 test/fixtures/move/a-file                          |   1 +
 test/fixtures/move/a-folder/another-file           |   1 +
 test/fixtures/move/a-folder/another-folder/file3   |   1 +
 test/fs-integration.test.js                        |  23 ++
 test/json.test.js                                  |  50 +++
 test/lib/util.js                                   |  36 ++
 test/mkdir.test.js                                 |  69 ++++
 test/mkdirp/README.md                              |   1 +
 test/mkdirp/chmod.test.js                          |  52 +++
 test/mkdirp/clobber.test.js                        |  41 ++
 test/mkdirp/mkdirp.test.js                         |  34 ++
 test/mkdirp/opts_fs.test.js                        |  32 ++
 test/mkdirp/opts_fs_sync.test.js                   |  30 ++
 test/mkdirp/perm.test.js                           |  41 ++
 test/mkdirp/perm_sync.js                           |  46 +++
 test/mkdirp/race.test.js                           |  42 +++
 test/mkdirp/rel.test.js                            |  32 ++
 test/mkdirp/return.test.js                         |  29 ++
 test/mkdirp/return_sync.test.js                    |  27 ++
 test/mkdirp/root.test.js                           |  22 ++
 test/mkdirp/sync.test.js                           |  31 ++
 test/mkdirp/umask.test.js                          |  75 ++++
 test/mocha.opts                                    |   5 +
 test/move.test.js                                  | 262 +++++++++++++
 .../broken-symlink-fixtures/src/broken-symlink     |   1 +
 test/ncp/fixtures/modified-files/out/a             |   1 +
 test/ncp/fixtures/modified-files/src/a             |   1 +
 test/ncp/fixtures/regular-fixtures/out/a           |   1 +
 test/ncp/fixtures/regular-fixtures/out/b           |   1 +
 test/ncp/fixtures/regular-fixtures/out/c           |   0
 test/ncp/fixtures/regular-fixtures/out/d           |   0
 test/ncp/fixtures/regular-fixtures/out/e           |   0
 test/ncp/fixtures/regular-fixtures/out/f           |   0
 test/ncp/fixtures/regular-fixtures/out/sub/a       |   1 +
 test/ncp/fixtures/regular-fixtures/out/sub/b       |   0
 test/ncp/fixtures/regular-fixtures/out/sub/z       |   1 +
 test/ncp/fixtures/regular-fixtures/out/z           |   1 +
 test/ncp/fixtures/regular-fixtures/src/a           |   1 +
 test/ncp/fixtures/regular-fixtures/src/b           |   1 +
 test/ncp/fixtures/regular-fixtures/src/c           |   0
 test/ncp/fixtures/regular-fixtures/src/d           |   0
 test/ncp/fixtures/regular-fixtures/src/e           |   0
 test/ncp/fixtures/regular-fixtures/src/f           |   0
 test/ncp/fixtures/regular-fixtures/src/sub/a       |   1 +
 test/ncp/fixtures/regular-fixtures/src/sub/b       |   0
 .../fixtures/symlink-fixtures/out/dir-symlink/bar  |   1 +
 test/ncp/fixtures/symlink-fixtures/out/dir/bar     |   1 +
 .../ncp/fixtures/symlink-fixtures/out/file-symlink |   1 +
 test/ncp/fixtures/symlink-fixtures/out/foo         |   1 +
 test/ncp/fixtures/symlink-fixtures/src/dir-symlink |   1 +
 test/ncp/fixtures/symlink-fixtures/src/dir/bar     |   1 +
 .../ncp/fixtures/symlink-fixtures/src/file-symlink |   1 +
 test/ncp/fixtures/symlink-fixtures/src/foo         |   1 +
 test/ncp/ncp.test.js                               | 198 ++++++++++
 test/output.test.js                                |  69 ++++
 test/read.test.js                                  |  48 +++
 test/remove.test.js                                | 124 +++++++
 77 files changed, 3579 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5281cfd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+coverage/
+node_modules/
+
+.idea
+*.iml
\ No newline at end of file
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..950be15
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,3 @@
+coverage/
+test/
+.travis.yml
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..22a70cd
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,10 @@
+language: node_js
+before_install:
+  - "npm install npm -g"
+node_js:
+  - 0.11
+  - 0.10
+env:
+  - TEST_SUITE=test
+  - TEST_SUITE=coveralls
+script: "npm run-script $TEST_SUITE"
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..c964faa
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,191 @@
+0.16.5 / 2015-03-08
+-------------------
+- fixed `fs.move` when `clobber` is `true` and destination is a directory, it should clobber. https://github.com/jprichardson/node-fs-extra/issues/114
+
+0.16.4 / 2015-03-01
+-------------------
+- `fs.mkdirs` fix infinite loop on Windows. See: See https://github.com/substack/node-mkdirp/pull/74 and https://github.com/substack/node-mkdirp/issues/66
+
+0.16.3 / 2015-01-28
+-------------------
+- reverted https://github.com/jprichardson/node-fs-extra/commit/1ee77c8a805eba5b99382a2591ff99667847c9c9
+
+
+0.16.2 / 2015-01-28
+-------------------
+- fixed `fs.copy` for Node v0.8 (support is temporary and will be removed in the near future)
+
+0.16.1 / 2015-01-28
+-------------------
+- if `setImmediate` is not available, fall back to `process.nextTick`
+
+0.16.0 / 2015-01-28
+-------------------
+- bugfix `fs.move()` into itself. Closes #104
+- bugfix `fs.move()` moving directory across device. Closes #108
+- added coveralls support
+- bugfix: nasty multiple callback `fs.copy()` bug. Closes #98
+- misc fs.copy code cleanups
+
+0.15.0 / 2015-01-21
+-------------------
+- dropped `ncp`, imported code in
+- because of previous, now supports `io.js`
+- `graceful-fs` is now a dependency
+
+0.14.0 / 2015-01-05
+-------------------
+- changed `copy`/`copySync` from `fs.copy(src, dest, [filters], callback)` to `fs.copy(src, dest, [options], callback)` https://github.com/jprichardson/node-fs-extra/pull/100
+- removed mockfs tests for mkdirp (this may be temporary, but was getting in the way of other tests)
+
+0.13.0 / 2014-12-10
+-------------------
+- removed `touch` and `touchSync` methods (they didn't handle permissions like UNIX touch)
+- updated `"ncp": "^0.6.0"` to `"ncp": "^1.0.1"`
+- imported `mkdirp` => `minimist` and `mkdirp` are no longer dependences, should now appease people who wanted `mkdirp` to be `--use_strict` safe. See [#59](https://github.com/jprichardson/node-fs-extra/issues/59)
+
+0.12.0 / 2014-09-22
+-------------------
+- copy symlinks in `copySync()` [#85](https://github.com/jprichardson/node-fs-extra/pull/85)
+
+0.11.1 / 2014-09-02
+-------------------
+- bugfix `copySync()` preserve file permissions [#80](https://github.com/jprichardson/node-fs-extra/pull/80)
+
+0.11.0 / 2014-08-11
+-------------------
+- upgraded `"ncp": "^0.5.1"` to `"ncp": "^0.6.0"`
+- upgrade `jsonfile": "^1.2.0"` to `jsonfile": "^2.0.0"` => on write, json files now have `\n` at end. Also adds `options.throws` to `readJsonSync()`
+see https://github.com/jprichardson/node-jsonfile#readfilesyncfilename-options for more details.
+
+0.10.0 / 2014-06-29
+------------------
+* bugfix: upgaded `"jsonfile": "~1.1.0"` to `"jsonfile": "^1.2.0"`, bumped minor because of `jsonfile` dep change
+from `~` to `^`. #67
+
+0.9.1 / 2014-05-22
+------------------
+* removed Node.js `0.8.x` support, `0.9.0` was published moments ago and should have been done there
+
+0.9.0 / 2014-05-22
+------------------
+* upgraded `ncp` from `~0.4.2` to `^0.5.1`, #58
+* upgraded `rimraf` from `~2.2.6` to `^2.2.8`
+* upgraded `mkdirp` from `0.3.x` to `^0.5.0`
+* added methods `ensureFile()`, `ensureFileSync()`
+* added methods `ensureDir()`, `ensureDirSync()` #31
+* added `move()` method. From: https://github.com/andrewrk/node-mv
+
+
+0.8.1 / 2013-10-24
+------------------
+* copy failed to return an error to the callback if a file doesn't exist (ulikoehler #38, #39)
+
+0.8.0 / 2013-10-14
+------------------
+* `filter` implemented on `copy()` and `copySync()`. (Srirangan / #36)
+
+0.7.1 / 2013-10-12
+------------------
+* `copySync()` implemented (Srirangan / #33)
+* updated to the latest `jsonfile` version `1.1.0` which gives `options` params for the JSON methods. Closes #32
+
+0.7.0 / 2013-10-07
+------------------
+* update readme conventions
+* `copy()` now works if destination directory does not exist. Closes #29
+
+0.6.4 / 2013-09-05
+------------------
+* changed `homepage` field in package.json to remove NPM warning
+
+0.6.3 / 2013-06-28
+------------------
+* changed JSON spacing default from `4` to `2` to follow Node conventions
+* updated `jsonfile` dep
+* updated `rimraf` dep
+
+0.6.2 / 2013-06-28
+------------------
+* added .npmignore, #25
+
+0.6.1 / 2013-05-14
+------------------
+* modified for `strict` mode, closes #24
+* added `outputJson()/outputJsonSync()`, closes #23
+
+0.6.0 / 2013-03-18
+------------------
+* removed node 0.6 support
+* added node 0.10 support
+* upgraded to latest `ncp` and `rimraf`.
+* optional `graceful-fs` support. Closes #17
+
+
+0.5.0 / 2013-02-03
+------------------
+* Removed `readTextFile`.
+* Renamed `readJSONFile` to `readJSON` and `readJson`, same with write.
+* Restructured documentation a bit. Added roadmap.
+
+0.4.0 / 2013-01-28
+------------------
+* Set default spaces in `jsonfile` from 4 to 2.
+* Updated `testutil` deps for tests.
+* Renamed `touch()` to `createFile()`
+* Added `outputFile()` and `outputFileSync()`
+* Changed creation of testing diretories so the /tmp dir is not littered.
+* Added `readTextFile()` and `readTextFileSync()`.
+
+0.3.2 / 2012-11-01
+------------------
+* Added `touch()` and `touchSync()` methods.
+
+0.3.1 / 2012-10-11
+------------------
+* Fixed some stray globals.
+
+0.3.0 / 2012-10-09
+------------------
+* Removed all CoffeeScript from tests.
+* Renamed `mkdir` to `mkdirs`/`mkdirp`.
+
+0.2.1 / 2012-09-11
+------------------
+* Updated `rimraf` dep.
+
+0.2.0 / 2012-09-10
+------------------
+* Rewrote module into JavaScript. (Must still rewrite tests into JavaScript)
+* Added all methods of [jsonfile][https://github.com/jprichardson/node-jsonfile]
+* Added Travis-CI.
+
+0.1.3 / 2012-08-13
+------------------
+* Added method `readJSONFile`.
+
+0.1.2 / 2012-06-15
+------------------
+* Bug fix: `deleteSync()` didn't exist.
+* Verified Node v0.8 compatibility.
+
+0.1.1 / 2012-06-15
+------------------
+* Fixed bug in `remove()`/`delete()` that wouldn't execute the function if a callback wasn't passed.
+
+0.1.0 / 2012-05-31
+------------------
+* Renamed `copyFile()` to `copy()`. `copy()` can now copy directories (recursively) too.
+* Renamed `rmrf()` to `remove()`.
+* `remove()` aliased with `delete()`.
+* Added `mkdirp` capabilities. Named: `mkdir()`. Hides Node.js native `mkdir()`.
+* Instead of exporting the native `fs` module with new functions, I now copy over the native methods to a new object and export that instead.
+
+0.0.4 / 2012-03-14
+------------------
+* Removed CoffeeScript dependency
+
+0.0.3 / 2012-01-11
+------------------
+* Added methods rmrf and rmrfSync
+* Moved tests from Jasmine to Mocha
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..bc7481c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,15 @@
+(The MIT License)
+
+Copyright (c) 2011-2014 JP Richardson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 
+(the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 
+OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..279addf
--- /dev/null
+++ b/README.md
@@ -0,0 +1,411 @@
+Node.js: fs-extra
+=================
+
+[![build status](https://secure.travis-ci.org/jprichardson/node-fs-extra.svg)](http://travis-ci.org/jprichardson/node-fs-extra)
+[![downloads per month](http://img.shields.io/npm/dm/fs-extra.svg)](https://www.npmjs.org/package/fs-extra)
+[![Coverage Status](https://img.shields.io/coveralls/jprichardson/node-fs-extra.svg)](https://coveralls.io/r/jprichardson/node-fs-extra)
+
+This module adds a few extra file system methods that aren't included in the native `fs` module. It is a drop in replacement for `fs`.
+
+
+
+Why?
+----
+
+I got tired of including `mkdirp`, `rimraf`, and `cp -r` in most of my projects. 
+
+
+
+
+Installation
+------------
+
+    npm install --save fs-extra
+
+
+
+Usage
+-----
+
+`fs-extra` is a drop in replacement for native `fs`. All methods in `fs` are unmodified and attached to `fs-extra`.
+
+You don't ever need to include the original `fs` module again:
+
+```javascript
+var fs = require('fs') //this is no longer necessary
+```
+
+you can now do this:
+
+```javascript
+var fs = require('fs-extra') //var fs = require('fs')
+```
+
+or if you prefer to make it clear that you're using `fs-extra` and not `fs`, you may want 
+to do this:
+
+```javascript
+//var fs = require('fs')
+var fse = require('fs-extra')
+```
+
+you can also keep both, but it's redundant:
+
+```javascript
+var fs = require('fs')
+var fse = require('fs-extra')
+```
+
+
+
+Methods
+-------
+
+**NOTE:** You can still use the native Node.js methods. They are copied over to `fs-extra`.
+
+
+### copy(src, dest, [options], callback)
+
+Copy a file or directory. The directory can have contents. Like `cp -r`.
+
+Sync: `copySync()`
+
+
+Examples:
+
+```javascript
+var fs = require('fs-extra')
+
+fs.copy('/tmp/myfile', '/tmp/mynewfile', function(err) {
+  if (err) return console.error(err)
+  console.log("success!")
+}) //copies file
+
+fs.copy('/tmp/mydir', '/tmp/mynewdir', function(err) {
+  if (err) return console.error(err)
+  console.log("success!")
+}) //copies directory, even if it has subdirectories or files
+```
+
+
+### ensureFile(file, callback) 
+
+Ensures that the file exists. If the file that is requested to be created is in directories that do not exist, these directories are created. If the file already exists, it is **NOT MODIFIED**.
+
+Alias: `createFile()`
+
+Sync: `createFileSync()`,`ensureFileSync()`
+
+
+Example:
+
+```javascript
+var fs = require('fs-extra')
+
+var file = '/tmp/this/path/does/not/exist/file.txt'
+fs.ensureFile(file, function(err) {
+  console.log(err) // => null
+  //file has now been created, including the directory it is to be placed in
+})
+```
+
+
+### ensureDir(dir, callback) 
+
+Ensures that the directory exists. If the directory structure does not exist, it is created.
+
+Sync: `ensureDirSync()`
+
+
+Example:
+
+```javascript
+var fs = require('fs-extra')
+
+var dir = '/tmp/this/path/does/not/exist'
+fs.ensureDir(dir, function(err) {
+  console.log(err) // => null
+  //dir has now been created, including the directory it is to be placed in
+})
+```
+
+
+
+### mkdirs(dir, callback) 
+
+Creates a directory. If the parent hierarchy doesn't exist, it's created. Like `mkdir -p`.
+
+Alias: `mkdirp()`
+
+Sync: `mkdirsSync()` / `mkdirpSync()`
+
+
+Examples:
+
+```javascript
+var fs = require('fs-extra')
+
+fs.mkdirs('/tmp/some/long/path/that/prob/doesnt/exist', function(err) {
+  if (err) return console.error(err)
+  console.log("success!")
+})
+
+fs.mkdirsSync('/tmp/another/path')
+```
+
+
+### move(src, dest, [options], callback)
+
+Moves a file or directory, even across devices.
+
+Options:  
+clobber (boolean): overwrite existing file or directory  
+limit (number): number of concurrent moves, see ncp for more information
+
+Example:
+
+```javascript
+var fs = require('fs-extra')
+
+fs.move('/tmp/somefile', '/tmp/does/not/exist/yet/somefile', function(err) {
+  if (err) return console.error(err)
+  console.log("success!")
+})
+```
+
+
+### outputFile(file, data, callback)
+
+Almost the same as `writeFile` (i.e. it [overwrites](http://pages.citebite.com/v2o5n8l2f5reb)), except that if the parent directory does not exist, it's created.
+
+Sync: `outputFileSync()`
+
+
+Example:
+
+```javascript
+var fs = require('fs-extra')
+var file = '/tmp/this/path/does/not/exist/file.txt'
+
+fs.outputFile(file, 'hello!', function(err) {
+  console.log(err) // => null
+
+  fs.readFile(file, 'utf8', function(err, data) {
+    console.log(data) // => hello!
+  })
+})
+```
+
+
+
+### outputJson(file, data, callback)
+
+Almost the same as `writeJson`, except that if the directory does not exist, it's created.
+
+Alias: `outputJSON()`
+
+Sync: `outputJsonSync()`, `outputJSONSync()`
+
+
+Example:
+
+```javascript
+var fs = require('fs-extra')
+var file = '/tmp/this/path/does/not/exist/file.txt'
+
+fs.outputJson(file, {name: 'JP'}, function(err) {
+  console.log(err) // => null
+
+  fs.readJson(file, function(err, data) {
+    console.log(data.name) // => JP
+  })
+})
+```
+
+
+
+### readJson(file, [options], callback) 
+
+Reads a JSON file and then parses it into an object. `options` are the same that you'd pass to `fs.readFile`.
+
+Alias: `readJSON()`
+
+Sync: `readJsonSync()`, `readJSONSync()`
+
+
+Example:
+
+```javascript
+var fs = require('fs-extra')
+
+fs.readJson('./package.json', function(err, packageObj) {
+  console.log(packageObj.version) // => 0.1.3
+})
+```
+
+`readJsonSync()` can take a `throws` option set to `false` and it won't throw if the JSON is invalid. Example:
+
+```js
+var fs = require('fs-extra')
+var file = path.join('/tmp/some-invalid.json')
+var data = "{not valid JSON"
+fs.writeFileSync(file, data)
+
+var obj = fs.readJsonSync(file, {throws: false})
+console.log(obj) // => null
+```
+
+
+### remove(dir, callback)
+
+Removes a file or directory. The directory can have contents. Like `rm -rf`.
+
+Alias: `delete()`
+
+Sync: `removeSync()` / `deleteSync()`
+
+
+Examples:
+
+```javascript
+var fs = require('fs-extra')
+
+fs.remove('/tmp/myfile', function(err) {
+  if (err) return console.error(err)
+  
+  console.log("success!")
+})
+
+fs.removeSync('/home/jprichardson') //I just deleted my entire HOME directory. 
+```
+
+
+
+### writeJson(file, object, [options], callback) 
+
+Writes an object to a JSON file. `options` are the same that you'd pass to `fs.readFile`.
+
+Alias: `writeJSON()`
+
+Sync: `writeJsonSync()`, `writeJSONSync()`
+
+Example:
+
+```javascript
+var fs = require('fs-extra')
+fs.writeJson('./package.json', {name: 'fs-extra'}, function(err) {
+  console.log(err)
+})
+```
+
+
+Third Party
+-----------
+
+### Promises
+
+Use [Bluebird](https://github.com/petkaantonov/bluebird). See https://github.com/petkaantonov/bluebird/blob/master/API.md#promisification. `fs-extra` is
+explicitly listed as supported.
+
+```js
+var Promise = require("bluebird")
+var fs = Promise.promisifyAll(require("fs-extra"))
+```
+
+Or you can use the package [`fs-extra-promise`](https://github.com/overlookmotel/fs-extra-promise) that marries the two together.
+
+
+### TypeScript
+
+If you like TypeScript, you can use `fs-extra` with it: https://github.com/borisyankov/DefinitelyTyped/tree/master/fs-extra
+
+
+### File / Directory Watching
+
+If you want to watch for changes to files or directories, then you should use [chokidar](https://github.com/paulmillr/chokidar).
+
+
+### Misc.
+
+- [mfs](https://github.com/cadorn/mfs) - Monitor your fs-extra calls.
+
+
+
+
+Naming
+------
+
+I put a lot of thought into the naming of these functions. Inspired by @coolaj86's request. So he deserves much of the credit for raising the issue. See discussion(s) here:
+
+* https://github.com/jprichardson/node-fs-extra/issues/2
+* https://github.com/flatiron/utile/issues/11
+* https://github.com/ryanmcgrath/wrench-js/issues/29
+* https://github.com/substack/node-mkdirp/issues/17
+
+First, I believe that in as many cases as possible, the [Node.js naming schemes](http://nodejs.org/api/fs.html) should be chosen. However, there are problems with the Node.js own naming schemes.
+
+For example, `fs.readFile()` and `fs.readdir()`: the **F** is capitalized in *File* and the **d** is not capitalized in *dir*. Perhaps a bit pedantic, but they should still be consistent. Also, Node.js has chosen a lot of POSIX naming schemes, which I believe is great. See: `fs.mkdir()`, `fs.rmdir()`, `fs.chown()`, etc.
+
+We have a dilemma though. How do you consistently name methods that perform the following POSIX commands: `cp`, `cp -r`, `mkdir -p`, and `rm -rf`?
+
+My perspective: when in doubt, err on the side of simplicity. A directory is just a hierarchical grouping of directories and files. Consider that for a moment. So when you want to copy it or remove it, in most cases you'll want to copy or remove all of its contents. When you want to create a directory, if the directory that it's suppose to be contained in does not exist, then in most cases you'll want to create that too. 
+
+So, if you want to remove a file or a directory regardless of whether it has contents, just call `fs.remove(path)` or its alias `fs.delete(path)`. If you want to copy a file or a directory whether it has contents, just call `fs.copy(source, destination)`. If you want to create a directory regardless of whether its parent directories exist, just call `fs.mkdirs(path)` or `fs.mkdirp(path)`. 
+
+
+Credit
+------
+
+`fs-extra` wouldn't be possible without using the modules from the following authors:
+
+- [Isaac Shlueter](https://github.com/isaacs)
+- [Charlie McConnel](https://github.com/avianflu)
+- [James Halliday](https://github.com/substack)
+- [Andrew Kelley](https://github.com/andrewrk)
+
+
+Contributions
+-------------
+
+If you want to contribute, please add a test. Also, don't change the version in `package.json`.
+
+
+### Contributors
+
+- [*] [JP Richardson](https://github.com/jprichardson)
+- [*] [Mike McNeil](https://github.com/mikermcneil)
+- [*] [Ian Crowther](https://github.com/iancrowther)
+- [*] [Stephen Mathieson](https://github.com/stephenmathieson)
+- [*] [Srirangan](https://github.com/Srirangan)
+- [*] [Uli Köhler](https://github.com/ulikoehler)
+- [2] [Sylvain Cleymans](https://github.com/Ackar)
+- [1] [Jim Higson](https://github.com/jimhigson)
+- [1] [PatrickJS](https://github.com/gdi2290)
+- [1] [Michael Tiller](https://github.com/xogeny)
+- [1] [yibuyisheng](https://github.com/yibuyisheng)
+- [1] [overlookmotel](https://github.com/overlookmotel)
+- `<your name here>`
+
+
+
+
+License
+-------
+
+
+Licensed under MIT
+
+Copyright (c) 2011-2014 JP Richardson
+
+[1]: http://nodejs.org/docs/latest/api/fs.html 
+
+
+[jsonfile]: https://github.com/jprichardson/node-jsonfile
+
+
+
+
+
+
+
+
diff --git a/lib/_copy.js b/lib/_copy.js
new file mode 100644
index 0000000..c42108e
--- /dev/null
+++ b/lib/_copy.js
@@ -0,0 +1,250 @@
+// imported from ncp (this is temporary, will rewrite)
+
+var fs = require('graceful-fs')
+var path = require('path')
+
+function ncp (source, dest, options, callback) {
+  var cback = callback
+
+  if (!callback) {
+    cback = options
+    options = {}
+  }
+
+  var basePath = process.cwd()
+  var currentPath = path.resolve(basePath, source)
+  var targetPath = path.resolve(basePath, dest)
+
+  var filter = options.filter
+  var transform = options.transform
+  var clobber = options.clobber !== false
+  var dereference = options.dereference
+
+  var errs = null
+  
+  var started = 0
+  var finished = 0
+  var running = 0
+  // this is pretty useless now that we're using graceful-fs
+  // consider removing
+  var limit = options.limit || 512
+
+  startCopy(currentPath)
+  
+  function startCopy(source) {
+    started++
+    if (filter) {
+      if (filter instanceof RegExp) {
+        if (!filter.test(source)) {
+          return cb(true)
+        }
+      }
+      else if (typeof filter === 'function') {
+        if (!filter(source)) {
+          return cb(true)
+        }
+      }
+    }
+    return getStats(source)
+  }
+
+  function getStats(source) {
+    var defer = global.setImmediate || process.nextTick
+    var stat = dereference ? fs.stat : fs.lstat
+    if (running >= limit) {
+      return defer(function () {
+        getStats(source)
+      })
+    }
+    running++
+    stat(source, function (err, stats) {
+      var item = {}
+      if (err) {
+        return onError(err)
+      }
+
+      // We need to get the mode from the stats object and preserve it.
+      item.name = source
+      item.mode = stats.mode
+      item.mtime = stats.mtime //modified time
+      item.atime = stats.atime //access time
+
+      if (stats.isDirectory()) {
+        return onDir(item)
+      }
+      else if (stats.isFile()) {
+        return onFile(item)
+      }
+      else if (stats.isSymbolicLink()) {
+        // Symlinks don't really need to know about the mode.
+        return onLink(source)
+      }
+    })
+  }
+
+  function onFile(file) {
+    var target = file.name.replace(currentPath, targetPath)
+    isWritable(target, function (writable) {
+      if (writable) {
+        copyFile(file, target)
+      } else {
+        if(clobber) {
+          rmFile(target, function () {
+            copyFile(file, target)
+          })
+        } else {
+          cb()
+        }
+      }
+    })
+  }
+
+  function copyFile(file, target) {
+    var readStream = fs.createReadStream(file.name),
+        writeStream = fs.createWriteStream(target, { mode: file.mode })
+    
+    readStream.on('error', onError)
+    writeStream.on('error', onError)
+    
+    if(transform) {
+      transform(readStream, writeStream, file)
+    } else {
+      writeStream.on('open', function() {
+        readStream.pipe(writeStream)
+      })
+    }
+
+    //presumably old node then
+    var eventName = global.setImmediate ? 'finish' : 'close'
+    writeStream.once(eventName, function() {
+      cb()
+    })
+  }
+
+  function rmFile(file, done) {
+    fs.unlink(file, function (err) {
+      if (err) {
+        return onError(err)
+      }
+      return done()
+    })
+  }
+
+  function onDir(dir) {
+    var target = dir.name.replace(currentPath, targetPath)
+    isWritable(target, function (writable) {
+      if (writable) {
+        return mkDir(dir, target)
+      }
+      copyDir(dir.name)
+    })
+  }
+
+  function mkDir(dir, target) {
+    fs.mkdir(target, dir.mode, function (err) {
+      if (err) {
+        return onError(err)
+      }
+      copyDir(dir.name)
+    })
+  }
+
+  function copyDir(dir) {
+    fs.readdir(dir, function (err, items) {
+      if (err) {
+        return onError(err)
+      }
+      items.forEach(function (item) {
+        startCopy(path.join(dir, item))
+      })
+      return cb()
+    })
+  }
+
+  function onLink(link) {
+    var target = link.replace(currentPath, targetPath)
+    fs.readlink(link, function (err, resolvedPath) {
+      if (err) {
+        return onError(err)
+      }
+      checkLink(resolvedPath, target)
+    })
+  }
+
+  function checkLink(resolvedPath, target) {
+    if (dereference) {
+      resolvedPath = path.resolve(basePath, resolvedPath)
+    }
+    isWritable(target, function (writable) {
+      if (writable) {
+        return makeLink(resolvedPath, target)
+      }
+      fs.readlink(target, function (err, targetDest) {
+        if (err) {
+          return onError(err)
+        }
+        if (dereference) {
+          targetDest = path.resolve(basePath, targetDest)
+        }
+        if (targetDest === resolvedPath) {
+          return cb()
+        }
+        return rmFile(target, function () {
+          makeLink(resolvedPath, target)
+        })
+      })
+    })
+  }
+
+  function makeLink(linkPath, target) {
+    fs.symlink(linkPath, target, function (err) {
+      if (err) {
+        return onError(err)
+      }
+      return cb()
+    })
+  }
+
+  function isWritable(path, done) {
+    fs.lstat(path, function (err) {
+      if (err) {
+        if (err.code === 'ENOENT') return done(true)
+        return done(false)
+      }
+      return done(false)
+    })
+  }
+
+  function onError(err) {
+    if (options.stopOnError) {
+      return cback(err)
+    }
+    else if (!errs && options.errs) {
+      errs = fs.createWriteStream(options.errs)
+    }
+    else if (!errs) {
+      errs = []
+    }
+    if (typeof errs.write === 'undefined') {
+      errs.push(err)
+    }
+    else { 
+      errs.write(err.stack + '\n\n')
+    }
+    return cb()
+  }
+
+  function cb(skipped) {
+    if (!skipped) running--
+    finished++
+    if ((started === finished) && (running === 0)) {
+      if (cback !== undefined ) {
+        return errs ? cback(errs) : cback(null)
+      }
+    }
+  }
+}
+
+// todo, make this just export ncp
+module.exports.ncp = ncp
+
diff --git a/lib/copy.js b/lib/copy.js
new file mode 100644
index 0000000..36d13bc
--- /dev/null
+++ b/lib/copy.js
@@ -0,0 +1,99 @@
+var fs = require('graceful-fs')
+var path = require('path')
+var ncp = require('./_copy').ncp
+var mkdir = require('./mkdir')
+var create = require('./create')
+
+var BUF_LENGTH = 64 * 1024
+var _buff = new Buffer(BUF_LENGTH)
+
+var copyFileSync = function(srcFile, destFile) {
+  var fdr = fs.openSync(srcFile, 'r')
+  var stat = fs.fstatSync(fdr)
+  var fdw = fs.openSync(destFile, 'w', stat.mode)
+  var bytesRead = 1
+  var pos = 0
+
+  while (bytesRead > 0) {
+    bytesRead = fs.readSync(fdr, _buff, 0, BUF_LENGTH, pos)
+    fs.writeSync(fdw, _buff, 0, bytesRead)
+    pos += bytesRead
+  }
+
+  fs.closeSync(fdr)
+  fs.closeSync(fdw)
+}
+
+function copy(src, dest, options, callback) {
+  if( typeof options == "function" && !callback) {
+    callback = options
+    options = {}
+  } else if (typeof options == "function" || options instanceof RegExp) {
+    options = {filter: options}
+  }
+  callback = callback || function(){}
+
+  fs.lstat(src, function(err, stats) {
+    if (err) return callback(err)
+
+    var dir = null
+    if (stats.isDirectory()) {
+      var parts = dest.split(path.sep)
+      parts.pop()
+      dir = parts.join(path.sep)
+    } else {
+      dir = path.dirname(dest)
+    }
+
+    fs.exists(dir, function(dirExists) {
+      if (dirExists) return ncp(src, dest, options, callback)
+      mkdir.mkdirs(dir, function(err) {
+        if (err) return callback(err)
+        ncp(src, dest, options, callback)
+      })
+    })
+  })
+}
+
+function copySync(src, dest, options) {
+  if (typeof options == "function" || options instanceof RegExp) {
+    options = {filter: options}
+  }
+
+  options = options || {}
+  options.recursive = !!options.recursive
+
+  options.filter = options.filter || function() { return true }
+
+  var stats = options.recursive ? fs.lstatSync(src) : fs.statSync(src)
+  var destFolder = path.dirname(dest)
+  var destFolderExists = fs.existsSync(destFolder)
+  var performCopy = false
+
+  if (stats.isFile()) {
+    if (options.filter instanceof RegExp) performCopy = options.filter.test(src)
+    else if (typeof options.filter == "function") performCopy = options.filter(src)
+
+    if (performCopy) {
+      if (!destFolderExists) mkdir.mkdirsSync(destFolder)
+      copyFileSync(src, dest)
+    }
+  }
+  else if (stats.isDirectory()) {
+    if (!fs.existsSync(dest)) mkdir.mkdirsSync(dest)
+    var contents = fs.readdirSync(src)
+    contents.forEach(function(content) {
+      copySync(path.join(src, content), path.join(dest, content), {filter: options.filter, recursive: true})
+    })
+  }
+  else if (options.recursive && stats.isSymbolicLink()) {
+    var srcPath = fs.readlinkSync(src)
+    fs.symlinkSync(srcPath, dest)
+  }
+}
+
+module.exports = {
+  copy: copy,
+  copySync: copySync
+}
+
diff --git a/lib/create.js b/lib/create.js
new file mode 100644
index 0000000..68e9582
--- /dev/null
+++ b/lib/create.js
@@ -0,0 +1,39 @@
+var path = require('path')
+var fs = require('graceful-fs')
+var mkdir = require('./mkdir')
+
+function createFile (file, callback) {
+  function makeFile() {
+    fs.writeFile(file, '', function(err) {
+      if (err) return callback(err)
+      callback()
+    })
+  }
+
+  fs.exists(file, function(fileExists) {
+    if (fileExists) return callback()
+    var dir = path.dirname(file)
+    fs.exists(dir, function(dirExists) {
+      if (dirExists) return makeFile()
+      mkdir.mkdirs(dir, function(err) {
+        if (err) return callback(err)
+        makeFile()
+      })
+    })
+  })
+}
+
+function createFileSync (file) {
+  if (fs.existsSync(file)) return
+
+  var dir = path.dirname(file)
+  if (!fs.existsSync(dir))
+    mkdir.mkdirsSync(dir)
+
+  fs.writeFileSync(file, '')
+}
+
+module.exports = {
+  createFile: createFile,
+  createFileSync: createFileSync
+}
diff --git a/lib/index.js b/lib/index.js
new file mode 100644
index 0000000..25c73ab
--- /dev/null
+++ b/lib/index.js
@@ -0,0 +1,90 @@
+var jsonFile = require('jsonfile')
+var json = require('./json')
+
+var fse = {}
+var fs = require("graceful-fs")
+
+//attach fs methods to fse
+Object.keys(fs).forEach(function(key) {
+  var func = fs[key]
+  if (typeof func == 'function')
+    fse[key] = func
+})
+fs = fse
+
+var copy = require('./copy')
+fs.copy = copy.copy
+fs.copySync = copy.copySync
+
+var remove = require('./remove')
+fs.remove = remove.remove
+fs.removeSync = remove.removeSync
+fs['delete'] = fs.remove
+fs.deleteSync = fs.removeSync
+
+var mkdir = require('./mkdir')
+fs.mkdirs = mkdir.mkdirs
+fs.mkdirsSync = mkdir.mkdirsSync
+fs.mkdirp = fs.mkdirs
+fs.mkdirpSync = fs.mkdirsSync
+
+var create = require('./create')
+fs.createFile = create.createFile
+fs.createFileSync = create.createFileSync
+
+fs.ensureFile = create.createFile
+fs.ensureFileSync = create.createFileSync
+fs.ensureDir = mkdir.mkdirs
+fs.ensureDirSync = mkdir.mkdirsSync
+
+
+var move = require('./move')
+fs.move = function(src, dest, opts, callback) {
+  if (typeof opts == 'function') {
+    callback = opts
+    opts = {}
+  }
+
+  if (opts.mkdirp == null) opts.mkdirp = true
+  if (opts.clobber == null) opts.clobber = false
+
+  move(src, dest, opts, callback)
+}
+
+
+var output = require('./output')
+fs.outputFile = output.outputFile
+fs.outputFileSync = output.outputFileSync
+
+
+fs.readJsonFile = jsonFile.readFile
+fs.readJSONFile = jsonFile.readFile
+fs.readJsonFileSync = jsonFile.readFileSync
+fs.readJSONFileSync = jsonFile.readFileSync
+
+fs.readJson = jsonFile.readFile
+fs.readJSON = jsonFile.readFile
+fs.readJsonSync = jsonFile.readFileSync
+fs.readJSONSync = jsonFile.readFileSync
+
+fs.outputJsonSync = json.outputJsonSync
+fs.outputJSONSync = json.outputJsonSync
+fs.outputJson = json.outputJson
+fs.outputJSON = json.outputJson
+
+fs.writeJsonFile = jsonFile.writeFile
+fs.writeJSONFile = jsonFile.writeFile
+fs.writeJsonFileSync = jsonFile.writeFileSync
+fs.writeJSONFileSync = jsonFile.writeFileSync
+
+fs.writeJson = jsonFile.writeFile
+fs.writeJSON = jsonFile.writeFile
+fs.writeJsonSync = jsonFile.writeFileSync
+fs.writeJSONSync = jsonFile.writeFileSync
+
+
+module.exports = fs
+
+jsonFile.spaces = 2 //set to 2
+module.exports.jsonfile = jsonFile //so users of fs-extra can modify jsonFile.spaces
+
diff --git a/lib/json.js b/lib/json.js
new file mode 100644
index 0000000..8e12498
--- /dev/null
+++ b/lib/json.js
@@ -0,0 +1,31 @@
+var fs = require('graceful-fs')
+var path = require('path')
+var jsonFile = require('jsonfile')
+var mkdir = require('./mkdir')
+
+function outputJsonSync(file, data) {
+  var dir = path.dirname(file)
+
+  if (!fs.existsSync(dir))
+    mkdir.mkdirsSync(dir)
+
+  jsonFile.writeFileSync(file, data)
+}
+
+function outputJson(file, data, callback) {
+  var dir = path.dirname(file)
+
+  fs.exists(dir, function(itDoes) {
+    if (itDoes) return jsonFile.writeFile(file, data, callback)
+
+    mkdir.mkdirs(dir, function(err) {
+      if (err) return callback(err)
+      jsonFile.writeFile(file, data, callback)
+    })
+  })
+}
+
+module.exports = {
+  outputJsonSync: outputJsonSync,
+  outputJson: outputJson
+}
diff --git a/lib/mkdir.js b/lib/mkdir.js
new file mode 100644
index 0000000..6ac2e86
--- /dev/null
+++ b/lib/mkdir.js
@@ -0,0 +1,103 @@
+var fs = require('graceful-fs')
+var path = require('path')
+
+var octal_0777 = parseInt('0777', 8)
+
+function mkdirs(p, opts, f, made) {
+  if (typeof opts === 'function') {
+    f = opts
+    opts = {}
+  }
+  else if (!opts || typeof opts !== 'object') {
+    opts = { mode: opts }
+  }
+
+  var mode = opts.mode
+  var xfs = opts.fs || fs
+
+  if (mode === undefined) {
+    mode = octal_0777 & (~process.umask())
+  }
+  if (!made) made = null
+
+  var cb = f || function () {}
+  p = path.resolve(p)
+
+  xfs.mkdir(p, mode, function (er) {
+    if (!er) {
+      made = made || p
+      return cb(null, made)
+    }
+    switch (er.code) {
+      case 'ENOENT':
+        if (path.dirname(p) == p) return cb(er)
+        mkdirs(path.dirname(p), opts, function (er, made) {
+          if (er) cb(er, made)
+          else mkdirs(p, opts, cb, made)
+        })
+        break
+
+      // In the case of any other error, just see if there's a dir
+      // there already.  If so, then hooray!  If not, then something
+      // is borked.
+      default:
+        xfs.stat(p, function (er2, stat) {
+          // if the stat fails, then that's super weird.
+          // let the original error be the failure reason.
+          if (er2 || !stat.isDirectory()) cb(er, made)
+          else cb(null, made)
+        })
+        break
+    }
+  })
+}
+
+function mkdirsSync (p, opts, made) {
+  if (!opts || typeof opts !== 'object') {
+    opts = { mode: opts }
+  }
+
+  var mode = opts.mode
+  var xfs = opts.fs || fs
+
+  if (mode === undefined) {
+    mode = octal_0777 & (~process.umask())
+  }
+  if (!made) made = null
+
+  p = path.resolve(p)
+
+  try {
+    xfs.mkdirSync(p, mode)
+    made = made || p
+  }
+  catch (err0) {
+    switch (err0.code) {
+      case 'ENOENT' :
+        made = mkdirsSync(path.dirname(p), opts, made)
+        mkdirsSync(p, opts, made)
+        break
+
+      // In the case of any other error, just see if there's a dir
+      // there already.  If so, then hooray!  If not, then something
+      // is borked.
+      default:
+        var stat
+        try {
+          stat = xfs.statSync(p)
+        }
+        catch (err1) {
+          throw err0
+        }
+        if (!stat.isDirectory()) throw err0
+        break
+    }
+  }
+
+  return made
+}
+
+module.exports = {
+  mkdirs: mkdirs,
+  mkdirsSync: mkdirsSync
+}
diff --git a/lib/move.js b/lib/move.js
new file mode 100644
index 0000000..08320fd
--- /dev/null
+++ b/lib/move.js
@@ -0,0 +1,136 @@
+// most of this code was written by Andrew Kelley
+// licensed under the BSD license: see
+// https://github.com/andrewrk/node-mv/blob/master/package.json
+
+// this needs a cleanup
+
+var fs = require('graceful-fs')
+var ncp = require('./_copy').ncp
+var path = require('path')
+var rimraf = require('rimraf')
+var mkdirp = require('./mkdir').mkdirs
+
+function mv(source, dest, options, callback){
+  if (typeof options === 'function') {
+    callback = options
+    options = {}
+  }
+
+  var shouldMkdirp = !!options.mkdirp
+  var clobber = options.clobber !== false
+  var limit = options.limit || 16
+
+  if (shouldMkdirp) {
+    mkdirs()
+  } else {
+    doRename()
+  }
+
+  function mkdirs() {
+    mkdirp(path.dirname(dest), function(err) {
+      if (err) return callback(err)
+      doRename()
+    })
+  }
+
+  function doRename() {
+    if (clobber) {
+      fs.rename(source, dest, function(err) {
+        if (!err) return callback()
+
+        if (err.code === 'ENOTEMPTY') {
+          rimraf(dest, function(err) {
+            if (err) return callback(err)
+            options.clobber = false // just clobbered it, no need to do it again
+            mv(source, dest, options, callback)
+          })
+          return
+        }
+
+        if (err.code !== 'EXDEV') return callback(err)
+        moveFileAcrossDevice(source, dest, clobber, limit, callback)
+      })
+    } else {
+      fs.link(source, dest, function(err) {
+        if (err) {
+          if (err.code === 'EXDEV') {
+            moveFileAcrossDevice(source, dest, clobber, limit, callback)
+            return
+          }
+          if (err.code === 'EISDIR' || err.code === 'EPERM') {
+            moveDirAcrossDevice(source, dest, clobber, limit, callback)
+            return
+          }
+          callback(err)
+          return
+        }
+        fs.unlink(source, callback)
+      })
+    }
+  }
+}
+
+function moveFileAcrossDevice(source, dest, clobber, limit, callback) {
+  var outFlags = clobber ? 'w' : 'wx'
+  var ins = fs.createReadStream(source)
+  var outs = fs.createWriteStream(dest, {flags: outFlags})
+
+  ins.on('error', function(err) {
+    ins.destroy()
+    outs.destroy()
+    outs.removeListener('close', onClose)
+
+    // may want to create a directory but `out` line above
+    // creates an empty file for us: See #108
+    // don't care about error here
+    fs.unlink(dest, function() {
+      // note: `err` here is from the input stream errror
+      if (err.code === 'EISDIR' || err.code === 'EPERM') {
+        moveDirAcrossDevice(source, dest, clobber, limit, callback)
+      } else {
+        callback(err)
+      }
+    })
+  })
+
+  outs.on('error', function(err) {
+    ins.destroy()
+    outs.destroy()
+    outs.removeListener('close', onClose)
+    callback(err)
+  })
+
+  outs.once('close', onClose)
+  ins.pipe(outs)
+
+  function onClose() {
+    fs.unlink(source, callback)
+  }
+}
+
+function moveDirAcrossDevice(source, dest, clobber, limit, callback) {
+  var options = {
+    stopOnErr: true,
+    clobber: false,
+    limit: limit,
+  }
+
+  function startNcp() {
+    ncp(source, dest, options, function(errList) {
+      if (errList) return callback(errList[0])
+      rimraf(source, callback)
+    })
+  }
+
+  if (clobber) {
+    rimraf(dest, function(err) {
+      if (err) return callback(err)
+      startNcp()
+    })
+  } else {
+    startNcp()
+  }
+}
+
+module.exports = mv
+
diff --git a/lib/output.js b/lib/output.js
new file mode 100644
index 0000000..eb9ec3c
--- /dev/null
+++ b/lib/output.js
@@ -0,0 +1,34 @@
+var path = require('path')
+var fs = require('graceful-fs')
+var mkdir = require('./mkdir')
+
+function outputFile (file, data, encoding, callback) {
+  if (typeof encoding === 'function') {
+    callback = encoding
+    encoding = 'utf8'
+  }
+
+  var dir = path.dirname(file)
+  fs.exists(dir, function(itDoes) {
+    if (itDoes) return fs.writeFile(file, data, encoding, callback)
+    
+    mkdir.mkdirs(dir, function(err) {
+      if (err) return callback(err)
+      
+      fs.writeFile(file, data, encoding, callback)
+    })
+  })
+}
+
+function outputFileSync (file, data, encoding) {
+  var dir = path.dirname(file)
+  if (fs.existsSync(dir)) 
+    return fs.writeFileSync.apply(fs, arguments)
+  mkdir.mkdirsSync(dir)
+  fs.writeFileSync.apply(fs, arguments)
+}
+
+module.exports = {
+  outputFile: outputFile,
+  outputFileSync: outputFileSync
+}
diff --git a/lib/remove.js b/lib/remove.js
new file mode 100644
index 0000000..d6e3876
--- /dev/null
+++ b/lib/remove.js
@@ -0,0 +1,14 @@
+var rimraf = require('rimraf')
+
+function removeSync(dir) {
+  return rimraf.sync(dir)
+}
+
+function remove(dir, callback) {
+  return callback ? rimraf(dir, callback) : rimraf(dir, function(){})
+}
+
+module.exports = {
+  remove: remove,
+  removeSync: removeSync
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..1f2b3c5
--- /dev/null
+++ b/package.json
@@ -0,0 +1,59 @@
+{
+  "name": "fs-extra",
+  "version": "0.16.5",
+  "description": "fs-extra contains methods that aren't included in the vanilla Node.js fs package. Such as mkdir -p, cp -r, and rm -rf.",
+  "homepage": "https://github.com/jprichardson/node-fs-extra",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/jprichardson/node-fs-extra"
+  },
+  "keywords": [
+    "fs",
+    "file",
+    "file system",
+    "copy",
+    "directory",
+    "extra",
+    "mkdirp",
+    "mkdir",
+    "mkdirs",
+    "recursive",
+    "json",
+    "read",
+    "write",
+    "extra",
+    "delete",
+    "remove",
+    "touch",
+    "create",
+    "text",
+    "output",
+    "move"
+  ],
+  "author": "JP Richardson <jprichardson at gmail.com>",
+  "licenses": [
+    {
+      "type": "MIT",
+      "url": "http://github.com/jprichardson/node-fs-extra/raw/master/LICENSE"
+    }
+  ],
+  "dependencies": {
+    "graceful-fs": "^3.0.5",
+    "jsonfile": "^2.0.0",
+    "rimraf": "^2.2.8"
+  },
+  "devDependencies": {
+    "coveralls": "^2.11.2",
+    "istanbul": "^0.3.5",
+    "mocha": "^2.1.0",
+    "read-dir-files": "^0.1.1",
+    "secure-random": "^1.1.1",
+    "testutil": "^0.7.0"
+  },
+  "main": "./lib/index",
+  "scripts": {
+    "coverage": "istanbul cover ./node_modules/.bin/_mocha -- --reporter list test/*.js",
+    "coveralls": "npm run coverage && coveralls < coverage/lcov.info",
+    "test": "mocha test"
+  }
+}
diff --git a/test/copy-sync.test.js b/test/copy-sync.test.js
new file mode 100644
index 0000000..c9f3e7f
--- /dev/null
+++ b/test/copy-sync.test.js
@@ -0,0 +1,223 @@
+var assert = require('assert')
+var crypto = require('crypto')
+var path = require('path')
+var fs = require('../lib')
+var testutil = require('testutil')
+
+var testlib = require('./lib/util')
+
+var SIZE = 16 * 64 * 1024 + 7
+var DIR = ''
+
+describe("+ copySync()", function () {
+  beforeEach(function() {
+    DIR = testutil.createTestDir('fs-extra')
+  })
+
+  afterEach(function(done) {
+    fs.remove(DIR, done)
+  })
+
+  describe("> when the source is a file", function () {
+    it("should copy the file synchronously", function () {
+      var fileSrc = path.join(DIR, "TEST_fs-extra_src")
+      var fileDest = path.join(DIR, "TEST_fs-extra_copy")
+      var fileSrc = testlib.createFileWithData(fileSrc, SIZE)
+      var srcMd5 = crypto.createHash('md5').update(fs.readFileSync(fileSrc)).digest("hex")
+      var destMd5 = ''
+
+      fs.copySync(fileSrc, fileDest)
+
+      destMd5 = crypto.createHash('md5').update(fs.readFileSync(fileDest)).digest("hex")
+      assert.strictEqual(srcMd5, destMd5)
+    })
+
+    it("should follow symlinks", function () {
+      var fileSrc = path.join(DIR, "TEST_fs-extra_src")
+      var fileDest = path.join(DIR, "TEST_fs-extra_copy")
+      var linkSrc = path.join(DIR, "TEST_fs-extra_copy_link")
+      var fileSrc = testlib.createFileWithData(fileSrc, SIZE)
+      var srcMd5 = crypto.createHash('md5').update(fs.readFileSync(fileSrc)).digest("hex")
+      var destMd5 = ''
+
+      fs.symlinkSync(fileSrc, linkSrc)
+      fs.copySync(linkSrc, fileDest)
+      destMd5 = crypto.createHash('md5').update(fs.readFileSync(fileDest)).digest("hex")
+      assert.strictEqual(srcMd5, destMd5)
+    })
+
+    it("should maintain file mode", function () {
+      var fileSrc = path.join(DIR, "TEST_fs-extra_src")
+      var fileDest = path.join(DIR, "TEST_fs-extra_copy")
+      var fileSrc = testlib.createFileWithData(fileSrc, SIZE)
+
+      fs.chmodSync(fileSrc, 0750)
+      fs.copySync(fileSrc, fileDest)
+
+      var statSrc = fs.statSync(fileSrc)
+      var statDest = fs.statSync(fileDest)
+      assert.strictEqual(statSrc.mode, statDest.mode)
+    })
+
+    it("should only copy files allowed by filter regex", function() {
+      var srcFile1 = testlib.createFileWithData(path.join(DIR, "1.html"), SIZE)
+      var srcFile2 = testlib.createFileWithData(path.join(DIR, "2.css"), SIZE)
+      var srcFile3 = testlib.createFileWithData(path.join(DIR, "3.jade"), SIZE)
+      var destFile1 = path.join(DIR, "dest1.html")
+      var destFile2 = path.join(DIR, "dest2.css")
+      var destFile3 = path.join(DIR, "dest3.jade")
+      var filter = /.html$|.css$/i
+
+      fs.copySync(srcFile1, destFile1, {filter: filter})
+      fs.copySync(srcFile2, destFile2, {filter: filter})
+      fs.copySync(srcFile3, destFile3, {filter: filter})
+
+      assert(fs.existsSync(destFile1))
+      assert(fs.existsSync(destFile2))
+      assert(!fs.existsSync(destFile3))
+    })
+
+    it("should only copy files allowed by filter fn", function() {
+      var srcFile1 = testlib.createFileWithData(path.join(DIR, "1.html"), SIZE)
+      var srcFile2 = testlib.createFileWithData(path.join(DIR, "2.css"), SIZE)
+      var srcFile3 = testlib.createFileWithData(path.join(DIR, "3.jade"), SIZE)
+      var destFile1 = path.join(DIR, "dest1.html")
+      var destFile2 = path.join(DIR, "dest2.css")
+      var destFile3 = path.join(DIR, "dest3.jade")
+
+      var filter = function(s) { return s.split(".").pop() !== "css";}
+
+      fs.copySync(srcFile1, destFile1, filter)
+      fs.copySync(srcFile2, destFile2, filter)
+      fs.copySync(srcFile3, destFile3, filter)
+
+      assert(fs.existsSync(destFile1))
+      assert(!fs.existsSync(destFile2))
+      assert(fs.existsSync(destFile3))
+    })
+
+    describe("> when the destination dir does not exist", function () {
+      it('should create the destination directory and copy the file', function () {
+        var src = path.join(DIR, 'file.txt')
+        var dest = path.join(DIR, 'this/path/does/not/exist/copied.txt')
+        var data = "did it copy?\n"
+
+        fs.writeFileSync(src, data, 'utf8')
+        fs.copySync(src, dest)
+
+        var data2 = fs.readFileSync(dest, 'utf8')
+
+        assert.strictEqual(data, data2)
+      })
+    })
+  })
+
+  describe("> when the source is a directory", function() {
+    it("should copy the directory synchronously", function() {
+      var FILES = 2
+      var src = path.join(DIR, 'src')
+      var dest = path.join(DIR, 'dest')
+
+      var i, j
+
+      fs.mkdirsSync(src)
+
+      for (i = 0; i < FILES; ++i)
+        testlib.createFileWithData(path.join(src, i.toString()), SIZE)
+
+      var subdir = path.join(src, 'subdir')
+
+      fs.mkdirsSync(subdir)
+
+      for (i = 0; i < FILES; ++i)
+        testlib.createFileWithData(path.join(subdir, i.toString()), SIZE)
+
+      fs.copySync(src, dest)
+      assert(fs.existsSync(dest))
+
+      for (i = 0; i < FILES; ++i) 
+        assert(fs.existsSync(path.join(dest, i.toString())))
+
+      var destSub = path.join(dest, 'subdir')
+      for (j = 0; j < FILES; ++j) 
+        assert(fs.existsSync(path.join(destSub, j.toString())))
+    })
+
+    it("should preserve symbolic links", function() {
+      var src = path.join(DIR, 'src')
+      var dest = path.join(DIR, 'dest')
+
+      fs.mkdirsSync(src)
+      fs.symlinkSync('destination', path.join(src, 'symlink'))
+
+      fs.copySync(src, dest)
+
+      var link = fs.readlinkSync(path.join(dest, 'symlink'))
+      assert.strictEqual(link, 'destination')
+    })
+
+    it("should should apply filter recursively", function() {
+      var FILES = 2
+      var src = path.join(DIR, 'src')
+      var dest = path.join(DIR, 'dest')
+      var filter = /0$/i
+
+      fs.mkdirsSync(src)
+
+      for (var i = 0; i < FILES; ++i)
+        testlib.createFileWithData(path.join(src, i.toString()), SIZE)
+
+      var subdir = path.join(src, 'subdir')
+      fs.mkdirsSync(subdir)
+
+      for (i = 0; i < FILES; ++i)
+        testlib.createFileWithData(path.join(subdir, i.toString()), SIZE)
+
+      fs.copySync(src, dest, filter)
+
+      assert(fs.existsSync(dest))
+      assert(FILES>1)
+
+      for (i = 0; i < FILES; ++i) {
+        if (i==0) {
+          assert(fs.existsSync(path.join(dest, i.toString())))
+        } else {
+          assert(!fs.existsSync(path.join(dest, i.toString())))
+        }
+      }
+
+      var destSub = path.join(dest, 'subdir')
+      
+      for (var j = 0; j < FILES; ++j) {
+        if (j==0) {
+          assert(fs.existsSync(path.join(destSub, j.toString())))
+        } else {
+          assert(!fs.existsSync(path.join(destSub, j.toString())))
+        }
+      }
+    })
+
+    describe("> when the destination dir does not exist", function() {
+      it("should create the destination directory and copy the file", function() {
+        var src = path.join(DIR, 'data/')
+        fs.mkdirSync(src)
+
+        var d1 = "file1"
+        var d2 = "file2"
+        var f1 = fs.writeFileSync(path.join(src, "f1.txt"), d1)
+        var f2 = fs.writeFileSync(path.join(src, "f2.txt"), d2)
+
+        var dest = path.join(DIR, 'this/path/does/not/exist/outputDir')
+
+        fs.copySync(src, dest)
+
+        var o1 = fs.readFileSync(path.join(dest, 'f1.txt'), 'utf8')
+        var o2 = fs.readFileSync(path.join(dest, 'f2.txt'), 'utf8')
+
+        assert.strictEqual(d1, o1)
+        assert.strictEqual(d2, o2)
+      })
+    })
+  })
+})
+
diff --git a/test/copy.test.js b/test/copy.test.js
new file mode 100644
index 0000000..842c0f8
--- /dev/null
+++ b/test/copy.test.js
@@ -0,0 +1,238 @@
+var assert = require('assert')
+var crypto = require('crypto')
+var fs = require('../lib')
+var path = require('path')
+var testutil = require('testutil')
+var mkdirp = fs.mkdirs
+//var userid = require('userid')
+
+var testlib = require('./lib/util')
+
+var SIZE = 16 * 64 * 1024 + 7
+var DIR = ''
+
+describe('fs-extra', function() {
+  beforeEach(function() {
+    DIR = testutil.createTestDir('fs-extra')
+  })
+
+  afterEach(function() {
+    fs.removeSync(DIR)
+  })
+
+  describe('+ copy()', function() {
+    describe('> when the source is a file', function() {
+      it('should copy the file asynchronously', function(done) {
+        var fileSrc = path.join(DIR, "TEST_fs-extra_src")
+        var fileDest = path.join(DIR, "TEST_fs-extra_copy")
+        var fileSrc = testlib.createFileWithData(fileSrc, SIZE)
+        var srcMd5 = crypto.createHash('md5').update(fs.readFileSync(fileSrc)).digest("hex")
+        var destMd5 = ''
+
+        fs.copy(fileSrc, fileDest, function(err) {
+          destMd5 = crypto.createHash('md5').update(fs.readFileSync(fileDest)).digest("hex")
+          assert.strictEqual(srcMd5, destMd5)
+          done()
+        })
+      })
+      
+      it('should return an error if the source file does not exist', function(done) {
+        var fileSrc = "we-simply-assume-this-file-does-not-exist.bin"
+        var fileDest = path.join(DIR, "TEST_fs-extra_copy")
+        var destMd5 = ''
+
+        fs.copy(fileSrc, fileDest, function(err) {
+          assert(err)
+          done()
+        })
+      })
+
+      it("should only copy files allowed by filter regex", function(done) {
+        var srcFile1 = testlib.createFileWithData(path.join(DIR, "1.jade"), SIZE)
+        var destFile1 = path.join(DIR, "dest1.jade")
+        var filter = /.html$|.css$/i
+        fs.copy(srcFile1, destFile1, filter, function() {
+          assert(!fs.existsSync(destFile1))
+          done()
+        })
+      })
+
+      it("should only copy files allowed by filter fn", function(done) {
+        var srcFile1 = testlib.createFileWithData(path.join(DIR, "1.css"), SIZE)
+        var destFile1 = path.join(DIR, "dest1.css")
+        var filter = function(s) { return s.split(".").pop() !== "css";}
+        fs.copy(srcFile1, destFile1, filter, function() {
+          assert(!fs.existsSync(destFile1))
+          done()
+        })
+      })
+
+      it("accepts options object in place of filter", function(done) {
+        var srcFile1 = testlib.createFileWithData(path.join(DIR, "1.jade"), SIZE)
+        var destFile1 = path.join(DIR, "dest1.jade")
+        var options = {filter: /.html$|.css$/i}
+        fs.copy(srcFile1, destFile1, options, function() {
+          assert(!fs.existsSync(destFile1))
+          done()
+        })
+      })
+
+      describe('> when the destination dir does not exist', function() {
+        it('should create the destination directory and copy the file', function(done) {
+          var src = path.join(DIR, 'file.txt')
+          var dest = path.join(DIR, 'this/path/does/not/exist/copied.txt')
+          var data = "did it copy?\n"
+
+          fs.writeFileSync(src, data, 'utf8')
+
+          fs.copy(src, dest, function(err) {
+            var data2 = fs.readFileSync(dest, 'utf8')
+            assert.strictEqual(data, data2)
+            done(err)
+          })
+        })
+      })
+    })
+
+    describe('> when the source is a directory', function() {
+      describe('> when the source directory does not exist', function() {
+        it('should return an error', function(done) {
+          var ts = path.join(DIR, 'this_dir_does_not_exist')
+          var td = path.join(DIR, 'this_dir_really_does_not_matter')
+          fs.copy(ts, td, function(err) {
+            assert(err)
+            done()
+          })
+        })
+      })
+
+      it('should copy the directory asynchronously', function(done) {
+        var FILES = 2
+        var src = path.join(DIR, 'src')
+        var dest = path.join(DIR, 'dest')
+
+        mkdirp(src, function(err) {
+          for (var i = 0; i < FILES; ++i)
+            testlib.createFileWithData(path.join(src, i.toString()), SIZE)
+
+          var subdir = path.join(src, 'subdir')
+          mkdirp(subdir, function(err) {
+            for (var i = 0; i < FILES; ++i)
+              testlib.createFileWithData(path.join(subdir, i.toString()), SIZE)
+
+            fs.copy(src, dest, function(err) {
+              assert.ifError(err)
+              assert(fs.existsSync(dest))
+
+              for (var i = 0; i < FILES; ++i)
+                assert(fs.existsSync(path.join(dest, i.toString())))
+
+
+              var destSub = path.join(dest, 'subdir')
+              for (var j = 0; j < FILES; ++j)
+                assert(fs.existsSync(path.join(destSub, j.toString())))
+
+              done()
+            })
+          })
+        })
+      })
+
+      describe('> when the destination dir does not exist', function() {
+        it('should create the destination directory and copy the file', function(done) {
+          var src = path.join(DIR, 'data/')
+          fs.mkdirsSync(src)
+          var d1 = "file1"
+          var d2 = "file2"
+
+          var f1 = fs.writeFileSync(path.join(src, "f1.txt"), d1)
+          var f2 = fs.writeFileSync(path.join(src, "f2.txt"), d2)
+
+          var dest = path.join(DIR, 'this/path/does/not/exist/outputDir')
+
+          fs.copy(src, dest, function(err) {
+            var o1 = fs.readFileSync(path.join(dest, 'f1.txt'), 'utf8')
+            var o2 = fs.readFileSync(path.join(dest, 'f2.txt'), 'utf8')
+
+            assert.strictEqual(d1, o1)
+            assert.strictEqual(d2, o2)
+
+            done(err)
+          })
+        })
+      })
+
+      describe('> when src dir does not exist', function() {
+        it('should return an error', function(done) {
+          fs.copy('/does/not/exist', '/something/else', function(err) {
+            assert(err instanceof Error)
+            done()
+          })
+        })
+      })
+    })
+
+    describe.skip('> REGRESSIONS', function() {
+      //pretty UNIX specific, may not pass on windows... only test on Mac OS X 10.9
+      it('should maintain file permissions and ownership', function(done) {
+
+        //http://man7.org/linux/man-pages/man2/stat.2.html
+        var S_IFREG = 0100000 //regular file
+        var S_IFDIR = 0040000 //directory
+
+        var permDir = path.join(DIR, 'perms')
+        fs.mkdirSync(permDir)
+
+        var srcDir = path.join(permDir, 'src')
+        fs.mkdirSync(srcDir)
+
+        var f1 = path.join(srcDir, 'f1.txt')
+        fs.writeFileSync(f1, '')
+        fs.chmodSync(f1, 0666)
+        fs.chownSync(f1, process.getuid(), userid.gid('wheel'))
+        var f1stats = fs.lstatSync(f1)
+        assert.strictEqual(f1stats.mode - S_IFREG, 0666)
+
+        var d1 = path.join(srcDir, 'somedir')
+        fs.mkdirSync(d1)
+        fs.chmodSync(d1, 0777)
+        fs.chownSync(d1, process.getuid(), userid.gid('staff'))
+        var d1stats = fs.lstatSync(d1)
+        assert.strictEqual(d1stats.mode - S_IFDIR, 0777)
+
+        var f2 = path.join(d1, 'f2.bin')
+        fs.writeFileSync(f2, '')
+        fs.chmodSync(f2, 0777)
+        fs.chownSync(f2, process.getuid(), userid.gid('staff'))
+        var f2stats = fs.lstatSync(f2)
+        assert.strictEqual(f2stats.mode - S_IFREG, 0777)
+
+        var d2 = path.join(srcDir, 'crazydir')
+        fs.mkdirSync(d2)
+        fs.chmodSync(d2, 0444)
+        fs.chownSync(d2, process.getuid(), userid.gid('wheel'))
+        var d2stats = fs.lstatSync(d2)
+        assert.strictEqual(d2stats.mode - S_IFDIR, 0444)
+
+        var destDir = path.join(permDir, 'dest')
+        fs.copy(srcDir, destDir, function(err) {
+          assert.ifError(err)
+
+          var newf1stats = fs.lstatSync(path.join(permDir, 'dest/f1.txt'))
+          var newd1stats = fs.lstatSync(path.join(permDir, 'dest/somedir'))
+          var newf2stats = fs.lstatSync(path.join(permDir, 'dest/somedir/f2.bin'))
+          var newd2stats = fs.lstatSync(path.join(permDir, 'dest/crazydir'))
+
+          assert.strictEqual(newf1stats.mode, f1stats.mode)
+          assert.strictEqual(newd1stats.mode, d1stats.mode)
+          assert.strictEqual(newf2stats.mode, f2stats.mode)
+          assert.strictEqual(newd2stats.mode, d2stats.mode)
+
+          done();  
+        })
+      })
+    })
+  })
+})
+
+
diff --git a/test/create.test.js b/test/create.test.js
new file mode 100644
index 0000000..7c205b0
--- /dev/null
+++ b/test/create.test.js
@@ -0,0 +1,65 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var testutil = require('testutil')
+var fse = require('../')
+
+var TEST_DIR = ''
+
+describe('fs-extra', function () {
+  beforeEach(function() {
+    TEST_DIR = testutil.createTestDir('fs-extra')
+  })
+
+  afterEach(function(done) {
+    fse.remove(TEST_DIR, done)
+  })
+
+  describe('+ createFile', function() {
+    describe('> when the file and directory does not exist', function() {
+      it('should create the file', function(done) {
+        var file = path.join(TEST_DIR, Math.random() + 't-ne', Math.random() + '.txt')
+        assert(!fs.existsSync(file))
+        fse.createFile(file, function(err) {
+          assert.ifError(err)
+          assert(fs.existsSync(file))
+          done()
+        })
+      })
+    })
+
+    describe('> when the file does exist', function() {
+      it('should not modify the file', function(done) {
+        var file = path.join(TEST_DIR, Math.random() + 't-e', Math.random() + '.txt')
+        fse.mkdirsSync(path.dirname(file))
+        fs.writeFileSync(file, 'hello world')
+        fse.createFile(file, function(err) {
+          assert.ifError(err)
+          assert.equal(fs.readFileSync(file, 'utf8'), 'hello world')
+          done()
+        })
+      })
+    })
+  })
+
+  describe('+ createFileSync', function() {
+    describe('> when the file and directory does not exist', function() {
+      it('should create the file', function() {
+        var file = path.join(TEST_DIR, Math.random() + 'ts-ne', Math.random() + '.txt')
+        assert(!fs.existsSync(file))
+        fse.createFileSync(file)
+        assert(fs.existsSync(file))
+      })
+    })
+
+    describe('> when the file does exist', function() {
+      it('should not modify the file', function() {
+        var file = path.join(TEST_DIR, Math.random() + 'ts-e', Math.random() + '.txt')
+        fse.mkdirsSync(path.dirname(file))
+        fs.writeFileSync(file, 'hello world')
+        fse.createFileSync(file)
+        assert.equal(fs.readFileSync(file, 'utf8'), 'hello world')
+      })
+    })
+  })
+})
diff --git a/test/ensure.test.js b/test/ensure.test.js
new file mode 100644
index 0000000..bf3c85d
--- /dev/null
+++ b/test/ensure.test.js
@@ -0,0 +1,122 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var testutil = require('testutil')
+var fse = require('../')
+
+var TEST_DIR = ''
+
+describe('fs-extra', function() {
+  beforeEach(function() {
+    TEST_DIR = testutil.createTestDir('fs-extra')
+  })
+
+  afterEach(function(done) {
+    fse.remove(TEST_DIR, done)
+  })
+
+  describe('+ ensureFile()', function() {
+    describe('> when file exists', function() {
+      it('should not do anything', function(done) {
+        var file = path.join(TEST_DIR, 'file.txt')
+        fs.writeFileSync(file, 'blah')
+
+        assert(fs.existsSync(file))
+        fse.ensureFile(file, function(err) {
+          assert.ifError(err)
+          assert(fs.existsSync(file))
+          done()
+        })
+      })
+    })
+
+    describe('> when file does not exist', function() {
+      it('should create the file', function(done) {
+        var file = path.join(TEST_DIR, 'dir/that/does/not/exist', 'file.txt')
+
+        assert(!fs.existsSync(file))
+        fse.ensureFile(file, function(err) {
+          assert.ifError(err)
+          assert(fs.existsSync(file))
+          done()
+        })
+      })
+    })
+  })
+
+  describe('+ ensureFileSync()', function() {
+    describe('> when file exists', function() {
+      it('should not do anything', function() {
+        var file = path.join(TEST_DIR, 'file.txt')
+        fs.writeFileSync(file, 'blah')
+
+        assert(fs.existsSync(file))
+        fse.ensureFileSync(file)
+        assert(fs.existsSync(file))
+      })
+    })
+
+    describe('> when file does not exist', function() {
+      it('should create the file', function() {
+        var file = path.join(TEST_DIR, 'dir/that/does/not/exist', 'file.txt')
+
+        assert(!fs.existsSync(file))
+        fse.ensureFileSync(file)
+        assert(fs.existsSync(file))
+      })
+    })
+  })
+
+  describe('+ ensureDir()', function() {
+    describe('> when dir exists', function() {
+      it('should not do anything', function(done) {
+        var dir = path.join(TEST_DIR, 'dir/does/not/exist')
+        fse.mkdirpSync(dir)
+
+        assert(fs.existsSync(dir))
+        fse.ensureDir(dir, function(err) {
+          assert.ifError(err)
+          assert(fs.existsSync(dir))
+          done()
+        })
+      })
+    })
+
+    describe('> when dir does not exist', function() {
+      it('should create the dir', function(done) {
+        var dir = path.join(TEST_DIR, 'dir/that/does/not/exist')
+
+        assert(!fs.existsSync(dir))
+        fse.ensureDir(dir, function(err) {
+          assert.ifError(err)
+          assert(fs.existsSync(dir))
+          done()
+        })
+      })
+    })
+  })
+
+  describe('+ ensureDirSync()', function() {
+    describe('> when dir exists', function() {
+      it('should not do anything', function() {
+        var dir = path.join(TEST_DIR, 'dir/does/not/exist')
+        fse.mkdirpSync(dir)
+
+        assert(fs.existsSync(dir))
+        fse.ensureDirSync(dir)
+        assert(fs.existsSync(dir))
+      })
+    })
+
+    describe('> when dir does not exist', function() {
+      it('should create the dir', function() {
+        var dir = path.join(TEST_DIR, 'dir/that/does/not/exist')
+
+        assert(!fs.existsSync(dir))
+        fse.ensureDirSync(dir)
+        assert(fs.existsSync(dir))
+      })
+    })
+  })
+})
+
diff --git a/test/fixtures/move/a-file b/test/fixtures/move/a-file
new file mode 100644
index 0000000..94a709d
--- /dev/null
+++ b/test/fixtures/move/a-file
@@ -0,0 +1 @@
+sonic the hedgehog
diff --git a/test/fixtures/move/a-folder/another-file b/test/fixtures/move/a-folder/another-file
new file mode 100644
index 0000000..31340c7
--- /dev/null
+++ b/test/fixtures/move/a-folder/another-file
@@ -0,0 +1 @@
+tails
diff --git a/test/fixtures/move/a-folder/another-folder/file3 b/test/fixtures/move/a-folder/another-folder/file3
new file mode 100644
index 0000000..73a394d
--- /dev/null
+++ b/test/fixtures/move/a-folder/another-folder/file3
@@ -0,0 +1 @@
+knuckles
diff --git a/test/fs-integration.test.js b/test/fs-integration.test.js
new file mode 100644
index 0000000..0bf98a7
--- /dev/null
+++ b/test/fs-integration.test.js
@@ -0,0 +1,23 @@
+var assert = require('assert')
+var path = require('path')
+var fse = require('../')
+var testutil = require('testutil')
+
+var TEST_DIR;
+
+describe('native fs', function() {
+  beforeEach(function() {
+    TEST_DIR = testutil.createTestDir('fs-extra')
+  })
+
+  afterEach(function(done) {
+    fse.remove(TEST_DIR, done)
+  })
+
+  it('should use native fs methods', function() {
+    var file = path.join(TEST_DIR, 'write.txt')
+    fse.writeFileSync(file, 'hello')
+    var data = fse.readFileSync(file, 'utf8')
+    assert.equal(data, 'hello')
+  })
+})
\ No newline at end of file
diff --git a/test/json.test.js b/test/json.test.js
new file mode 100644
index 0000000..1240fa8
--- /dev/null
+++ b/test/json.test.js
@@ -0,0 +1,50 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var testutil = require('testutil')
+var fse = require('../')
+
+var TEST_DIR = null
+
+describe('json', function() {
+  beforeEach(function() {
+    TEST_DIR = testutil.createTestDir('fs-extra')    
+  })
+
+  afterEach(function(done) {
+    fse.remove(TEST_DIR, done)
+  })
+
+  describe('+ outputJsonSync(file, data)', function() {
+    it('should write the file regardless of whether the directory exists or not', function() {
+      var file = path.join(TEST_DIR, 'this-dir', 'does-not', 'exist', 'file.json')
+      assert(!fs.existsSync(file))
+
+      var data = {name: 'JP'}
+      fse.outputJsonSync(file, data)
+      
+      assert(fs.existsSync(file))
+      var newData = JSON.parse(fs.readFileSync(file, 'utf8'))
+
+      assert.equal(data.name, newData.name)
+    })
+  })
+
+  describe('+ outputJson(file, data)', function() {
+    it('should write the file regardless of whether the directory exists or not', function(done) {
+      var file = path.join(TEST_DIR, 'this-dir', 'prob-does-not', 'exist', 'file.json')
+      assert(!fs.existsSync(file))
+
+      var data = {name: 'JP'}
+      fse.outputJson(file, data, function(err) {
+        if (err) return done(err)
+
+        assert(fs.existsSync(file))
+        var newData = JSON.parse(fs.readFileSync(file, 'utf8'))
+
+        assert.equal(data.name, newData.name)
+        done()
+      })
+    })
+  })
+})
diff --git a/test/lib/util.js b/test/lib/util.js
new file mode 100644
index 0000000..b4658ed
--- /dev/null
+++ b/test/lib/util.js
@@ -0,0 +1,36 @@
+var fs = require('fs')
+var path = require('path')
+var os = require('os')
+var rimraf = require('rimraf')
+var sr = require('secure-random')
+
+function tmpdir() {
+  if (os.type().toLowerCase().indexOf('win') === 0)
+    return process.env['TEMP']
+  else
+    return '/tmp'
+}
+
+function createFileWithData(file, size) {
+  fs.writeFileSync(file, sr.randomBuffer(size))
+  return file
+}
+
+function createTestDir() {
+  var app = 'fs-extra'
+  var dir = path.join(tmpdir(), 'test-' + app)
+  if (fs.existsSync(dir)) {
+    var files = fs.readdirSync(dir)
+    files.forEach(function(file) {
+      return rimraf.sync(path.join(dir, file))
+    })
+  } else {
+    fs.mkdirSync(dir)
+  }
+  return dir
+}
+
+module.exports = {
+  createFileWithData: createFileWithData,
+  createTestDir: createTestDir
+}
diff --git a/test/mkdir.test.js b/test/mkdir.test.js
new file mode 100644
index 0000000..9c10c7e
--- /dev/null
+++ b/test/mkdir.test.js
@@ -0,0 +1,69 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var testutil = require('testutil')
+var fse = require('../')
+
+/* global afterEach, beforeEach, describe, it */
+
+var TEST_DIR = ''
+
+describe('fs-extra', function() {
+  beforeEach(function() {
+    TEST_DIR = testutil.createTestDir('fs-extra')
+  })
+
+  afterEach(function(done) {
+    fse.remove(TEST_DIR, done)
+  })
+
+  describe('+ mkdirs()', function() {
+    it('should make the directory', function(done) {
+      var dir = path.join(TEST_DIR, 'tmp-' + Date.now() + Math.random())
+
+      assert(!fs.existsSync(dir))
+
+      fse.mkdirs(dir, function(err) {
+        assert.ifError(err)
+        assert(fs.existsSync(dir))
+        done()
+      })
+    })
+
+    it('should make the entire directory path', function(done) {
+      var dir = path.join(TEST_DIR, 'tmp-' + Date.now() + Math.random())
+      var newDir = path.join(TEST_DIR, 'dfdf', 'ffff', 'aaa')
+
+      assert(!fs.existsSync(dir))
+
+      fse.mkdirs(newDir, function(err) {
+        assert.ifError(err)
+        assert(fs.existsSync(newDir))
+        done()
+      })
+    })
+  })
+
+  describe('+ mkdirsSync()', function() {
+    it('should make the directory', function(done) {
+      var dir = path.join(TEST_DIR, 'tmp-' + Date.now() + Math.random())
+
+      assert(!fs.existsSync(dir))
+      fse.mkdirsSync(dir)
+      assert(fs.existsSync(dir))
+
+      done()
+    })
+
+    it('should make the entire directory path', function(done) {
+      var dir = path.join(TEST_DIR, 'tmp-' + Date.now() + Math.random())
+      var newDir = path.join(dir, 'dfdf', 'ffff', 'aaa')
+
+      assert(!fs.existsSync(newDir))
+      fse.mkdirsSync(newDir)
+      assert(fs.existsSync(newDir))
+
+      done()
+    })
+  })
+})
diff --git a/test/mkdirp/README.md b/test/mkdirp/README.md
new file mode 100644
index 0000000..a211103
--- /dev/null
+++ b/test/mkdirp/README.md
@@ -0,0 +1 @@
+These tests imported from https://github.com/substack/node-mkdirp.
\ No newline at end of file
diff --git a/test/mkdirp/chmod.test.js b/test/mkdirp/chmod.test.js
new file mode 100644
index 0000000..b40a975
--- /dev/null
+++ b/test/mkdirp/chmod.test.js
@@ -0,0 +1,52 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var fse = require('../../')
+var testutil = require('testutil')
+
+var TEST_DIR = ''
+
+var ps = []
+for (var i = 0; i < 25; i++) {
+  var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+  ps.push(dir)
+}
+
+var file = ps.join('/')
+
+describe('mkdirp / chmod', function() {
+  beforeEach(function() {
+    TEST_DIR = testutil.createTestDir('fs-extra')
+    file = path.join(TEST_DIR, file)
+  })
+
+  afterEach(function(done) {
+    fse.remove(TEST_DIR, done)
+  })
+
+  it('chmod-pre', function (done) {
+    var mode = 0744
+    fse.mkdirp(file, mode, function (er) {
+      assert.ifError(er, 'should not error')
+      fs.stat(file, function (er, stat) {
+        assert.ifError(er, 'should exist')
+        assert.ok(stat && stat.isDirectory(), 'should be directory')
+        assert.equal(stat && stat.mode & 0777, mode, 'should be 0744')
+        done()
+      })
+    })
+  })
+
+  it('chmod', function (done) {
+    var mode = 0755
+    fse.mkdirp(file, mode, function (er) {
+      assert.ifError(er, 'should not error')
+      fs.stat(file, function (er, stat) {
+        assert.ifError(er, 'should exist')
+        assert.ok(stat && stat.isDirectory(), 'should be directory')
+        done()
+      })
+    })
+  })
+})
+
diff --git a/test/mkdirp/clobber.test.js b/test/mkdirp/clobber.test.js
new file mode 100644
index 0000000..9f53f33
--- /dev/null
+++ b/test/mkdirp/clobber.test.js
@@ -0,0 +1,41 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var fse = require('../../')
+var testutil = require('testutil')
+
+describe('mkdirp / clobber', function() {
+  var ps, file, itw
+
+  before(function(done) {
+    ps = [ '', testutil.createTestDir('fs-extra')]
+
+    for (var i = 0; i < 25; i++) {
+      var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+      ps.push(dir)
+    }
+
+    file = ps.join('/')
+
+    // a file in the way
+    itw = ps.slice(0, 3).join('/')
+
+    console.error("about to write to "+itw)
+    fs.writeFileSync(itw, 'I AM IN THE WAY, THE TRUTH, AND THE LIGHT.')
+
+    fs.stat(itw, function (er, stat) {
+      assert.ifError(er)
+      assert.ok(stat && stat.isFile(), 'should be file')
+      done()
+    })
+  })
+
+  it('should clobber', function (done) {
+    fse.mkdirp(file, 0755, function (err) {
+      assert.ok(err)
+      assert.equal(err.code, 'ENOTDIR')
+      done()
+    })
+  })
+})
+
diff --git a/test/mkdirp/mkdirp.test.js b/test/mkdirp/mkdirp.test.js
new file mode 100644
index 0000000..b82b46d
--- /dev/null
+++ b/test/mkdirp/mkdirp.test.js
@@ -0,0 +1,34 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var fse = require('../../')
+var testutil = require('testutil')
+
+describe('mkdirp / mkdirp', function() {
+  var TEST_DIR
+
+  before(function() {
+    TEST_DIR = testutil.createTestDir('fs-extra')
+  })
+
+  it('woo', function (done) {
+    var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    
+    var file = TEST_DIR + [x,y,z].join('/')
+    
+    fse.mkdirp(file, 0755, function (err) {
+      assert.ifError(err)
+      fs.exists(file, function (ex) {
+        assert.ok(ex, 'file created')
+        fs.stat(file, function (err, stat) {
+          assert.ifError(err)
+          assert.equal(stat.mode & 0777, 0755)
+          assert.ok(stat.isDirectory(), 'target not a directory')
+          done()
+        })
+      })
+    })
+  })
+})
\ No newline at end of file
diff --git a/test/mkdirp/opts_fs.test.js b/test/mkdirp/opts_fs.test.js
new file mode 100644
index 0000000..d153978
--- /dev/null
+++ b/test/mkdirp/opts_fs.test.js
@@ -0,0 +1,32 @@
+return // skip for now
+
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var fse = require('../../')
+var testutil = require('testutil')
+var mockfs = require('mock-fs')
+
+describe('mkdirp / opts_fs', function() {
+  it('opts.fs', function (done) {    
+    var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    
+    var file = '/beep/boop/' + [x,y,z].join('/')
+    var xfs = mockfs.fs()
+    
+    fse.mkdirp(file, { fs: xfs, mode: 0755 }, function (err) {
+      assert.ifError(err)
+      xfs.exists(file, function (ex) {
+        assert.ok(ex, 'created file')
+        xfs.stat(file, function (err, stat) {
+          assert.ifError(err)
+          assert.equal(stat.mode & 0777, 0755)
+          assert.ok(stat.isDirectory(), 'target not a directory')
+          done()
+        })
+      })  
+    })
+  })
+})
diff --git a/test/mkdirp/opts_fs_sync.test.js b/test/mkdirp/opts_fs_sync.test.js
new file mode 100644
index 0000000..90d925e
--- /dev/null
+++ b/test/mkdirp/opts_fs_sync.test.js
@@ -0,0 +1,30 @@
+return // skip for now
+
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var fse = require('../../')
+var testutil = require('testutil')
+var mockfs = require('mock-fs')
+
+describe('mkdirp / opts_fs', function() {
+  it('opts.fs', function (done) {    
+    var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    
+    var file = '/beep/boop/' + [x,y,z].join('/')
+    var xfs = mockfs.fs()
+    
+    fse.mkdirpSync(file, { fs: xfs, mode: 0755 })
+    xfs.exists(file, function (ex) {
+      assert.ok(ex, 'created file')
+      xfs.stat(file, function (err, stat) {
+        assert.ifError(err)
+        assert.equal(stat.mode & 0777, 0755)
+        assert.ok(stat.isDirectory(), 'target not a directory')
+        done()
+      })
+    })  
+  })
+})
diff --git a/test/mkdirp/perm.test.js b/test/mkdirp/perm.test.js
new file mode 100644
index 0000000..eb93566
--- /dev/null
+++ b/test/mkdirp/perm.test.js
@@ -0,0 +1,41 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var fse = require('../../')
+var testutil = require('testutil')
+
+describe('mkdirp / perm', function() {
+  var TEST_DIR
+
+  before(function() {
+    TEST_DIR = testutil.createTestDir('fs-extra')
+  })
+
+  afterEach(function(done) {
+    fse.remove(TEST_DIR, done)
+  })
+
+  it('async perm', function (done) {
+    var file = path.join(TEST_DIR, (Math.random() * (1<<30)).toString(16))
+    
+    fse.mkdirp(file, 0755, function (err) {
+      assert.ifError(err)
+      fs.exists(file, function (ex) {
+        assert.ok(ex, 'file created')
+        fs.stat(file, function (err, stat) {
+          assert.ifError(err)
+          assert.equal(stat.mode & 0777, 0755)
+          assert.ok(stat.isDirectory(), 'target not a directory')
+          done()
+        })
+      })
+    })
+  })
+
+  it('async root perm', function (done) {
+    fse.mkdirp('/tmp', 0755, function (err) {
+      assert.ifError(err)
+      done()
+    })
+  })
+})
diff --git a/test/mkdirp/perm_sync.js b/test/mkdirp/perm_sync.js
new file mode 100644
index 0000000..d7245d1
--- /dev/null
+++ b/test/mkdirp/perm_sync.js
@@ -0,0 +1,46 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var fse = require('../../')
+var testutil = require('testutil')
+
+describe('mkdirp / perm_sync', function() {
+  var TEST_DIR
+
+  before(function() {
+    TEST_DIR = testutil.createTestDir('fs-extra')
+  })
+
+  afterEach(function(done) {
+    fse.remove(TEST_DIR, done)
+  })
+
+  it('sync perm', function (done) {
+    var file = path.join(TEST_DIR, (Math.random() * (1<<30)).toString(16) + '.json')
+    
+    fse.mkdirpSync(file, 0755)
+    fs.exists(file, function (ex) {
+      assert.ok(ex, 'file created')
+      fs.stat(file, function (err, stat) {
+        assert.ifError(err)
+        assert.equal(stat.mode & 0777, 0755)
+        assert.ok(stat.isDirectory(), 'target not a directory')
+        done()
+      })
+    })
+  })
+
+  it('sync root perm', function (done) {    
+    var file = TEST_DIR
+    fse.mkdirpSync(file, 0755)
+    fs.exists(file, function (ex) {
+      assert.ok(ex, 'file created')
+      fs.stat(file, function (err, stat) {
+        assert.ifError(err)
+        assert.ok(stat.isDirectory(), 'target not a directory')
+        done()
+      })
+    })
+  })
+})
+
diff --git a/test/mkdirp/race.test.js b/test/mkdirp/race.test.js
new file mode 100644
index 0000000..3dd6ed1
--- /dev/null
+++ b/test/mkdirp/race.test.js
@@ -0,0 +1,42 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var fse = require('../../')
+var testutil = require('testutil')
+
+describe('mkdirp / race', function() {
+  it('race', function (done) {
+
+    var ps = [ '', testutil.createTestDir('fs-extra') ]
+    
+    for (var i = 0; i < 25; i++) {
+      var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+      ps.push(dir)
+    }
+    var file = ps.join('/')
+    
+    var res = 2
+    mk(file, function () {
+      if (--res === 0) done()
+    })
+    
+    mk(file, function () {
+      if (--res === 0) done()
+    })
+    
+    function mk (file, cb) {
+      fse.mkdirp(file, 0755, function (err) {
+        assert.ifError(err)
+        fs.exists(file, function (ex) {
+          assert.ok(ex, 'file created')
+          fs.stat(file, function (err, stat) {
+            assert.ifError(err)
+            assert.equal(stat.mode & 0777, 0755)
+            assert.ok(stat.isDirectory(), 'target not a directory')
+            if (cb) cb()
+          })
+        })
+      })
+    }
+  })
+})
diff --git a/test/mkdirp/rel.test.js b/test/mkdirp/rel.test.js
new file mode 100644
index 0000000..7d26904
--- /dev/null
+++ b/test/mkdirp/rel.test.js
@@ -0,0 +1,32 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var fse = require('../../')
+var testutil = require('testutil')
+
+describe('mkdirp / rel', function() {
+  it('rel', function (done) {
+    var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    
+    var cwd = process.cwd()
+    process.chdir(testutil.createTestDir('fs-extra'))
+    
+    var file = [x,y,z].join('/')
+    
+    fse.mkdirp(file, 0755, function (err) {
+      assert.ifError(err)
+      fs.exists(file, function (ex) {
+        assert.ok(ex, 'file created')
+        fs.stat(file, function (err, stat) {
+          assert.ifError(err)
+          process.chdir(cwd)
+          assert.equal(stat.mode & 0777, 0755)
+          assert.ok(stat.isDirectory(), 'target not a directory')
+          done()
+        })
+      })
+    })
+  })
+})
diff --git a/test/mkdirp/return.test.js b/test/mkdirp/return.test.js
new file mode 100644
index 0000000..1d93be8
--- /dev/null
+++ b/test/mkdirp/return.test.js
@@ -0,0 +1,29 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var fse = require('../../')
+var testutil = require('testutil')
+
+describe('mkdirp / return value', function() {
+  it('should', function (done) {
+    var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+
+    var dir =  testutil.createTestDir('fs-extra') + '/'
+    var file = dir + [x,y,z].join('/')
+
+    // should return the first dir created.
+    // By this point, it would be profoundly surprising if /tmp didn't
+    // already exist, since every other test makes things in there.
+    fse.mkdirp(file, function (err, made) {
+      assert.ifError(err)
+      assert.equal(made, dir + x)
+      fse.mkdirp(file, function (err, made) {
+        assert.ifError(err)
+        assert.equal(made, null)
+        done()
+      })
+    })
+  })
+})
diff --git a/test/mkdirp/return_sync.test.js b/test/mkdirp/return_sync.test.js
new file mode 100644
index 0000000..d2324d8
--- /dev/null
+++ b/test/mkdirp/return_sync.test.js
@@ -0,0 +1,27 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var fse = require('../../')
+var testutil = require('testutil')
+
+describe('mkdirp / return value', function() {
+  it('should', function () {
+    var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+
+    var dir =  testutil.createTestDir('fs-extra') + '/'
+    var file = dir + [x,y,z].join('/')
+
+    // should return the first dir created.
+    // By this point, it would be profoundly surprising if /tmp didn't
+    // already exist, since every other test makes things in there.
+    // Note that this will throw on failure, which will fail the test.
+    var made = fse.mkdirpSync(file)
+    assert.equal(made, dir + x)
+
+    // making the same file again should have no effect.
+    made = fse.mkdirpSync(file)
+    assert.equal(made, null)
+  })
+})
diff --git a/test/mkdirp/root.test.js b/test/mkdirp/root.test.js
new file mode 100644
index 0000000..4743fbf
--- /dev/null
+++ b/test/mkdirp/root.test.js
@@ -0,0 +1,22 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var fse = require('../../')
+var testutil = require('testutil')
+
+describe('mkdirp / root', function () {
+
+  it('should', function(done) {
+    // '/' on unix, 'c:/' on windows.
+    var file = path.resolve('/')
+
+    fse.mkdirp(file, 0755, function (err) {
+      if (err) throw err
+      fs.stat(file, function (er, stat) {
+        if (er) throw er
+        assert.ok(stat.isDirectory(), 'target is a directory')
+        done()
+      })
+    })
+  })
+})
\ No newline at end of file
diff --git a/test/mkdirp/sync.test.js b/test/mkdirp/sync.test.js
new file mode 100644
index 0000000..883db23
--- /dev/null
+++ b/test/mkdirp/sync.test.js
@@ -0,0 +1,31 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var fse = require('../../')
+var testutil = require('testutil')
+
+describe('mkdirp / sync', function() {
+  it('should', function (done) {
+    var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+    var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16)
+
+    var file = testutil.createTestDir('fs-extra') + '/' + [x,y,z].join('/')
+
+    try {
+      fse.mkdirpSync(file, 0755)
+    } catch (err) {
+      assert.fail(err)
+    }
+
+    fs.exists(file, function (ex) {
+      assert.ok(ex, 'file created')
+      fs.stat(file, function (err, stat) {
+        assert.ifError(err)
+        assert.equal(stat.mode & 0777, 0755)
+        assert.ok(stat.isDirectory(), 'target not a directory')
+        done()
+      })
+    })
+  })
+})
diff --git a/test/mkdirp/umask.test.js b/test/mkdirp/umask.test.js
new file mode 100644
index 0000000..3b203ec
--- /dev/null
+++ b/test/mkdirp/umask.test.js
@@ -0,0 +1,75 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var testutil = require('../lib/util')
+var fse = require('../../')
+
+'use strict'
+
+var TEST_DIR = ''
+var oct777 = parseInt('777', 8)
+
+describe('mkdirp', function() {
+  var _rndDir
+
+  beforeEach(function() {
+    TEST_DIR = testutil.createTestDir()
+    TEST_DIR = path.join(TEST_DIR, 'mkdirp')
+
+    // verify clean directory
+    assert(!fs.existsSync(TEST_DIR))
+    fs.mkdirSync(TEST_DIR)
+
+    // for actual tests
+    var x = Math.floor(Math.random() * Math.pow(16,6)).toString(16)
+    var y = Math.floor(Math.random() * Math.pow(16,6)).toString(16)
+    var z = Math.floor(Math.random() * Math.pow(16,6)).toString(16)
+    _rndDir = path.join(TEST_DIR, [x, y, z].join(path.sep))
+
+    // just to be safe, although unnecessary
+    assert(!fs.existsSync(_rndDir))
+  })
+
+  afterEach(function() {
+    fse.removeSync(TEST_DIR)
+  })
+
+  describe('umask', function() {
+    describe('async', function() {
+      it('should have proper umask', function(done) {
+        fse.mkdirp(_rndDir, function (err) {
+          assert.ifError(err)
+          fs.exists(_rndDir, function (ex) {
+            assert.ok(ex, 'file created')
+            fs.stat(_rndDir, function (err, stat) {
+              assert.ifError(err)
+              assert.equal(stat.mode & oct777, oct777 & (~process.umask()))
+              assert.ok(stat.isDirectory(), 'target not a directory')
+              done()
+            })
+          })
+        })
+      })
+    })
+
+    describe('sync', function() {
+      it('should have proper umask', function(done) {
+        try {
+          fse.mkdirpSync(_rndDir)
+        } catch (err) {
+          return done(err)
+        }
+
+        fs.exists(_rndDir, function (ex) {
+          assert.ok(ex, 'file created')
+          fs.stat(_rndDir, function (err, stat) {
+            assert.ifError(err)
+            assert.equal(stat.mode & oct777, (oct777 & (~process.umask())))
+            assert.ok(stat.isDirectory(), 'target not a directory')
+            done()
+          })
+        })
+      })
+    })
+  })
+})
diff --git a/test/mocha.opts b/test/mocha.opts
new file mode 100644
index 0000000..951f112
--- /dev/null
+++ b/test/mocha.opts
@@ -0,0 +1,5 @@
+--reporter spec
+--ui bdd
+--growl
+--timeout 7000
+--recursive
\ No newline at end of file
diff --git a/test/move.test.js b/test/move.test.js
new file mode 100644
index 0000000..6418c79
--- /dev/null
+++ b/test/move.test.js
@@ -0,0 +1,262 @@
+var assert = require('assert')
+var path = require('path')
+var rimraf = require('rimraf')
+var fs =  require('fs')
+var fse = require('../')
+var testutil = require('./lib/util')
+
+var TEST_DIR = ''
+var FIXTURES_DIR = ''
+var SRC_FIXTURES_DIR = 'test/fixtures/move'
+
+// makes fs.rename return cross-device error.
+var mock_fs = {}
+mock_fs.rename = function(src, dest, callback) {
+  setTimeout(function() {
+    var err = new Error()
+    err.code = 'EXDEV'
+    callback(err)
+  }, 10)
+}
+
+describe("move", function() {
+  beforeEach(function() {
+    TEST_DIR = testutil.createTestDir('fs-extra')
+    TEST_DIR = path.join(TEST_DIR, 'move')
+    if (!fs.existsSync(TEST_DIR))
+      fs.mkdirSync(TEST_DIR)
+    FIXTURES_DIR = path.join(TEST_DIR, 'fixtures')
+    fse.copySync(SRC_FIXTURES_DIR, FIXTURES_DIR)
+  })
+
+  afterEach(function() {
+    rimraf.sync(TEST_DIR)
+  })
+
+  it("should rename a file on the same device", function (done) {
+    var src = FIXTURES_DIR + '/a-file'
+    var dest = FIXTURES_DIR + '/a-file-dest'
+
+    fse.move(src, dest, function (err) {
+      assert.ifError(err)
+      fs.readFile(dest, 'utf8', function (err, contents) {
+        assert.ifError(err)
+        assert.strictEqual(contents, "sonic the hedgehog\n")
+        done()
+      })
+    })
+  })
+
+  it("should not overwrite if clobber = false", function (done) {
+    var src = FIXTURES_DIR + "/a-file"
+    var dest = FIXTURES_DIR + "/a-folder/another-file"
+
+    // verify file exists already
+    assert(fs.existsSync(dest))
+
+    fse.move(src, dest, {clobber: false}, function (err) {
+      assert.ok(err && err.code === 'EEXIST', "throw EEXIST")
+      done()
+    })
+  })
+
+  it("should not create directory structure if mkdirp is false", function (done) {
+    var src = FIXTURES_DIR + "/a-file"
+    var dest = FIXTURES_DIR + "/does/not/exist/a-file-dest"
+
+    // verify dest directory does not exist
+    assert(!fs.existsSync(path.dirname(dest)))
+
+    fse.move(src, dest, {mkdirp: false}, function (err) {
+      assert.strictEqual(err.code, 'ENOENT')
+      done()
+    })
+  })
+
+  it("should create directory structure by default", function (done) {
+    var src = FIXTURES_DIR + "/a-file"
+    var dest = FIXTURES_DIR + "/does/not/exist/a-file-dest"
+
+    // verify dest directory does not exist
+    assert(!fs.existsSync(path.dirname(dest)))
+
+    fse.move(src, dest, function (err) {
+      assert.ifError(err)
+      fs.readFile(dest, 'utf8', function (err, contents) {
+        assert.ifError(err)
+        assert.strictEqual(contents, "sonic the hedgehog\n")
+        done()
+      })
+    })
+  })
+
+  it("should work across devices", function (done) {
+    var src = FIXTURES_DIR + "/a-file"
+    var dest = FIXTURES_DIR + "/a-file-dest"
+
+    var oldRename = fs.rename
+    fs.rename = mock_fs.rename
+
+    fse.move(src, dest, function (err) {
+      assert.ifError(err)
+      fs.readFile(dest, 'utf8', function (err, contents) {
+        assert.ifError(err)
+        assert.strictEqual(contents, "sonic the hedgehog\n")
+
+        // restore
+        fs.rename = oldRename
+
+        done()
+      })
+    })
+  })
+
+  it("should move folders", function (done) {
+    var src = FIXTURES_DIR + "/a-folder"
+    var dest = FIXTURES_DIR + "/a-folder-dest"
+
+    // verify it doesn't exist
+    assert(!fs.existsSync(dest))
+
+    fse.move(src, dest, function (err) {
+      assert.ifError(err)
+      fs.readFile(dest + "/another-file", 'utf8', function (err, contents) {
+        assert.ifError(err)
+        assert.strictEqual(contents, "tails\n")
+        done()
+      })
+    })
+  })
+
+  it("should move folders across devices", function (done) {
+    var src = FIXTURES_DIR + "/a-folder"
+    var dest = FIXTURES_DIR + "/a-folder-dest"
+
+    var oldRename = fs.rename
+    fs.rename = mock_fs.rename
+
+    fse.move(src, dest, function (err) {
+      assert.ifError(err)
+      fs.readFile(dest + "/another-folder/file3", 'utf8', function (err, contents) {
+        assert.ifError(err)
+        assert.strictEqual(contents, "knuckles\n")
+
+        // restore
+        fs.rename = oldRename
+
+        done()
+      })
+    })
+  })
+
+  describe.skip('> when trying to a move a folder into itself', function() {
+    it('should produce an error', function(done) {
+      var SRC_DIR = path.join(TEST_DIR, 'test')
+      var DEST_DIR = path.join(TEST_DIR, 'test', 'test')
+
+      assert(!fs.existsSync(SRC_DIR))
+      fs.mkdirSync(SRC_DIR)
+      assert(fs.existsSync(SRC_DIR))
+
+      fse.move(SRC_DIR, DEST_DIR, function(err) {
+        assert(fs.existsSync(SRC_DIR))
+        assert(err)
+        done()
+      })
+    })
+  })
+
+  // tested on Linux ubuntu 3.13.0-32-generic #57-Ubuntu SMP i686 i686 GNU/Linux
+  // this won't trigger a bug on Mac OS X Yosimite with a USB drive (/Volumes)
+  // see issue #108
+  describe('> when actually trying to a move a folder across devices', function() {
+    var differentDevice = '/mnt'
+    var __skipTests = false
+
+    // must set this up, if not, exit silently
+    if (!fs.existsSync(differentDevice)) {
+      console.log('Skipping cross-device move test')
+      __skipTests = true
+    }
+
+    // make sure we have permission on device
+    try {
+      fs.writeFileSync(path.join(differentDevice, 'file'), 'hi')
+    } catch (err) {
+      console.log("Can't write to device. Skipping test.")
+      __skipTests = true
+    }
+
+    var _it = __skipTests ? it.skip : it
+
+    describe('> just the folder', function() {
+      _it('should move the folder', function(done) {
+        var src = '/mnt/some/weird/dir-really-weird'
+        var dest = path.join(TEST_DIR, 'device-weird')
+
+        if (!fs.existsSync(src))
+          fse.mkdirpSync(src)
+
+        assert(!fs.existsSync(dest))
+
+        assert(fs.lstatSync(src).isDirectory())
+
+        fse.move(src, dest, function(err) {
+          assert.ifError(err)
+          assert(fs.existsSync(dest))
+          //console.log(path.normalize(dest))
+          assert(fs.lstatSync(dest).isDirectory())
+          done()
+        })
+      })
+    })
+
+    describe('> a folder with a bunch of stuff', function() {
+
+    })
+
+    describe('> when clobber = true', function() {
+      describe('> when dest is a directory', function() {
+        it('should clobber the destination', function(done) {
+          // use fixtures dir as dest since it has stuff
+          var dest = FIXTURES_DIR
+          var paths = fs.readdirSync(dest)
+
+          // verify dest has stuff
+          assert(paths.indexOf('a-file') >= 0)
+          assert(paths.indexOf('a-folder') >= 0)
+
+          // create new source dir
+          var src = path.join(TEST_DIR, 'src')
+          fse.ensureDirSync(src)
+          fse.mkdirsSync(path.join(src, 'some-folder'))
+          fs.writeFileSync(path.join(src, 'some-file'), 'hi')
+
+          // verify source has stuff
+          paths = fs.readdirSync(src)
+          assert(paths.indexOf('some-file') >= 0)
+          assert(paths.indexOf('some-folder') >= 0)
+
+          fse.move(src, dest, {clobber: true}, function(err) {
+            if (err) return done(err)
+
+            // verify dest does not have old stuff
+            var paths = fs.readdirSync(dest)
+            assert(paths.indexOf('a-file') == -1)
+            assert(paths.indexOf('a-folder') == -1)
+
+            // verify dest has new stuff
+            assert(paths.indexOf('some-file') >= 0)
+            assert(paths.indexOf('some-folder') >= 0)
+
+            done()
+          })
+        })
+      })
+    })
+  })
+})
+
+
+
+
diff --git a/test/ncp/fixtures/broken-symlink-fixtures/src/broken-symlink b/test/ncp/fixtures/broken-symlink-fixtures/src/broken-symlink
new file mode 120000
index 0000000..cfa0a46
--- /dev/null
+++ b/test/ncp/fixtures/broken-symlink-fixtures/src/broken-symlink
@@ -0,0 +1 @@
+does-not-exist
\ No newline at end of file
diff --git a/test/ncp/fixtures/modified-files/out/a b/test/ncp/fixtures/modified-files/out/a
new file mode 100644
index 0000000..d606037
--- /dev/null
+++ b/test/ncp/fixtures/modified-files/out/a
@@ -0,0 +1 @@
+test2
\ No newline at end of file
diff --git a/test/ncp/fixtures/modified-files/src/a b/test/ncp/fixtures/modified-files/src/a
new file mode 100644
index 0000000..29f446a
--- /dev/null
+++ b/test/ncp/fixtures/modified-files/src/a
@@ -0,0 +1 @@
+test3
\ No newline at end of file
diff --git a/test/ncp/fixtures/regular-fixtures/out/a b/test/ncp/fixtures/regular-fixtures/out/a
new file mode 100644
index 0000000..802992c
--- /dev/null
+++ b/test/ncp/fixtures/regular-fixtures/out/a
@@ -0,0 +1 @@
+Hello world
diff --git a/test/ncp/fixtures/regular-fixtures/out/b b/test/ncp/fixtures/regular-fixtures/out/b
new file mode 100644
index 0000000..9f6bb18
--- /dev/null
+++ b/test/ncp/fixtures/regular-fixtures/out/b
@@ -0,0 +1 @@
+Hello ncp
diff --git a/test/ncp/fixtures/regular-fixtures/out/c b/test/ncp/fixtures/regular-fixtures/out/c
new file mode 100644
index 0000000..e69de29
diff --git a/test/ncp/fixtures/regular-fixtures/out/d b/test/ncp/fixtures/regular-fixtures/out/d
new file mode 100644
index 0000000..e69de29
diff --git a/test/ncp/fixtures/regular-fixtures/out/e b/test/ncp/fixtures/regular-fixtures/out/e
new file mode 100644
index 0000000..e69de29
diff --git a/test/ncp/fixtures/regular-fixtures/out/f b/test/ncp/fixtures/regular-fixtures/out/f
new file mode 100644
index 0000000..e69de29
diff --git a/test/ncp/fixtures/regular-fixtures/out/sub/a b/test/ncp/fixtures/regular-fixtures/out/sub/a
new file mode 100644
index 0000000..cf291b5
--- /dev/null
+++ b/test/ncp/fixtures/regular-fixtures/out/sub/a
@@ -0,0 +1 @@
+Hello nodejitsu
diff --git a/test/ncp/fixtures/regular-fixtures/out/sub/b b/test/ncp/fixtures/regular-fixtures/out/sub/b
new file mode 100644
index 0000000..e69de29
diff --git a/test/ncp/fixtures/regular-fixtures/out/sub/z b/test/ncp/fixtures/regular-fixtures/out/sub/z
new file mode 100644
index 0000000..cf291b5
--- /dev/null
+++ b/test/ncp/fixtures/regular-fixtures/out/sub/z
@@ -0,0 +1 @@
+Hello nodejitsu
diff --git a/test/ncp/fixtures/regular-fixtures/out/z b/test/ncp/fixtures/regular-fixtures/out/z
new file mode 100644
index 0000000..802992c
--- /dev/null
+++ b/test/ncp/fixtures/regular-fixtures/out/z
@@ -0,0 +1 @@
+Hello world
diff --git a/test/ncp/fixtures/regular-fixtures/src/a b/test/ncp/fixtures/regular-fixtures/src/a
new file mode 100644
index 0000000..802992c
--- /dev/null
+++ b/test/ncp/fixtures/regular-fixtures/src/a
@@ -0,0 +1 @@
+Hello world
diff --git a/test/ncp/fixtures/regular-fixtures/src/b b/test/ncp/fixtures/regular-fixtures/src/b
new file mode 100644
index 0000000..9f6bb18
--- /dev/null
+++ b/test/ncp/fixtures/regular-fixtures/src/b
@@ -0,0 +1 @@
+Hello ncp
diff --git a/test/ncp/fixtures/regular-fixtures/src/c b/test/ncp/fixtures/regular-fixtures/src/c
new file mode 100644
index 0000000..e69de29
diff --git a/test/ncp/fixtures/regular-fixtures/src/d b/test/ncp/fixtures/regular-fixtures/src/d
new file mode 100644
index 0000000..e69de29
diff --git a/test/ncp/fixtures/regular-fixtures/src/e b/test/ncp/fixtures/regular-fixtures/src/e
new file mode 100644
index 0000000..e69de29
diff --git a/test/ncp/fixtures/regular-fixtures/src/f b/test/ncp/fixtures/regular-fixtures/src/f
new file mode 100644
index 0000000..e69de29
diff --git a/test/ncp/fixtures/regular-fixtures/src/sub/a b/test/ncp/fixtures/regular-fixtures/src/sub/a
new file mode 100644
index 0000000..cf291b5
--- /dev/null
+++ b/test/ncp/fixtures/regular-fixtures/src/sub/a
@@ -0,0 +1 @@
+Hello nodejitsu
diff --git a/test/ncp/fixtures/regular-fixtures/src/sub/b b/test/ncp/fixtures/regular-fixtures/src/sub/b
new file mode 100644
index 0000000..e69de29
diff --git a/test/ncp/fixtures/symlink-fixtures/out/dir-symlink/bar b/test/ncp/fixtures/symlink-fixtures/out/dir-symlink/bar
new file mode 100644
index 0000000..fd06f5f
--- /dev/null
+++ b/test/ncp/fixtures/symlink-fixtures/out/dir-symlink/bar
@@ -0,0 +1 @@
+bar contents
\ No newline at end of file
diff --git a/test/ncp/fixtures/symlink-fixtures/out/dir/bar b/test/ncp/fixtures/symlink-fixtures/out/dir/bar
new file mode 100644
index 0000000..fd06f5f
--- /dev/null
+++ b/test/ncp/fixtures/symlink-fixtures/out/dir/bar
@@ -0,0 +1 @@
+bar contents
\ No newline at end of file
diff --git a/test/ncp/fixtures/symlink-fixtures/out/file-symlink b/test/ncp/fixtures/symlink-fixtures/out/file-symlink
new file mode 100644
index 0000000..35fc060
--- /dev/null
+++ b/test/ncp/fixtures/symlink-fixtures/out/file-symlink
@@ -0,0 +1 @@
+foo contents
\ No newline at end of file
diff --git a/test/ncp/fixtures/symlink-fixtures/out/foo b/test/ncp/fixtures/symlink-fixtures/out/foo
new file mode 100644
index 0000000..35fc060
--- /dev/null
+++ b/test/ncp/fixtures/symlink-fixtures/out/foo
@@ -0,0 +1 @@
+foo contents
\ No newline at end of file
diff --git a/test/ncp/fixtures/symlink-fixtures/src/dir-symlink b/test/ncp/fixtures/symlink-fixtures/src/dir-symlink
new file mode 120000
index 0000000..8724519
--- /dev/null
+++ b/test/ncp/fixtures/symlink-fixtures/src/dir-symlink
@@ -0,0 +1 @@
+dir
\ No newline at end of file
diff --git a/test/ncp/fixtures/symlink-fixtures/src/dir/bar b/test/ncp/fixtures/symlink-fixtures/src/dir/bar
new file mode 100644
index 0000000..fd06f5f
--- /dev/null
+++ b/test/ncp/fixtures/symlink-fixtures/src/dir/bar
@@ -0,0 +1 @@
+bar contents
\ No newline at end of file
diff --git a/test/ncp/fixtures/symlink-fixtures/src/file-symlink b/test/ncp/fixtures/symlink-fixtures/src/file-symlink
new file mode 120000
index 0000000..1910281
--- /dev/null
+++ b/test/ncp/fixtures/symlink-fixtures/src/file-symlink
@@ -0,0 +1 @@
+foo
\ No newline at end of file
diff --git a/test/ncp/fixtures/symlink-fixtures/src/foo b/test/ncp/fixtures/symlink-fixtures/src/foo
new file mode 100644
index 0000000..35fc060
--- /dev/null
+++ b/test/ncp/fixtures/symlink-fixtures/src/foo
@@ -0,0 +1 @@
+foo contents
\ No newline at end of file
diff --git a/test/ncp/ncp.test.js b/test/ncp/ncp.test.js
new file mode 100644
index 0000000..d9aecf5
--- /dev/null
+++ b/test/ncp/ncp.test.js
@@ -0,0 +1,198 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var rimraf = require('rimraf')
+var readDirFiles = require('read-dir-files').read //temporary, will remove
+var util = require('util')
+var ncp = require('../../lib/_copy').ncp
+
+var fixturesDir = path.join(__dirname, 'fixtures')
+
+describe('ncp', function () {
+  describe('regular files and directories', function () {
+    var fixtures = path.join(fixturesDir, 'regular-fixtures'),
+        src = path.join(fixtures, 'src'),
+        out = path.join(fixtures, 'out')
+
+    before(function (cb) {
+      rimraf(out, function() {
+        ncp(src, out, cb)
+      })
+    })
+
+    describe('when copying a directory of files', function () {
+      it('files are copied correctly', function (cb) {
+        readDirFiles(src, 'utf8', function (srcErr, srcFiles) {
+          readDirFiles(out, 'utf8', function (outErr, outFiles) {
+            assert.ifError(srcErr)
+            assert.deepEqual(srcFiles, outFiles)
+            cb()
+          })
+        })
+      })
+    })
+
+    describe('when copying files using filter', function () {
+      before(function (cb) {
+        var filter = function(name) {
+          return name.substr(name.length - 1) != 'a'
+        }
+        rimraf(out, function () {
+          ncp(src, out, {filter: filter}, cb)
+        })
+      })
+
+      it('files are copied correctly', function (cb) {
+        readDirFiles(src, 'utf8', function (srcErr, srcFiles) {
+          function filter(files) {
+            for (var fileName in files) {
+              var curFile = files[fileName]
+              if (curFile instanceof Object)
+                return filter(curFile)
+              if (fileName.substr(fileName.length - 1) == 'a')
+                delete files[fileName]
+            }
+          }
+          filter(srcFiles)
+          readDirFiles(out, 'utf8', function (outErr, outFiles) {
+            assert.ifError(outErr)
+            assert.deepEqual(srcFiles, outFiles)
+            cb()
+          })
+        })
+      })
+    })
+
+    describe('when using clobber=false', function () {
+      it('the copy is completed successfully', function (cb) {
+        ncp(src, out, function() {
+          ncp(src, out, {clobber: false}, function(err) {
+            assert.ifError(err)
+            cb()
+          })
+        })
+      })
+    })
+
+    describe('when using transform', function () {
+      it('file descriptors are passed correctly', function (cb) {
+        ncp(src, out, {
+           transform: function(read,write,file) {
+              assert.notEqual(file.name, undefined)
+              assert.strictEqual(typeof file.mode,'number')
+              read.pipe(write)
+           }
+        }, cb)
+      })
+    })
+  })
+
+  describe('symlink handling', function () {
+    var fixtures = path.join(fixturesDir, 'symlink-fixtures'),
+        src = path.join(fixtures, 'src'),
+        out = path.join(fixtures, 'out')
+
+    beforeEach(function (cb) {
+      rimraf(out, cb)
+    })
+
+    it('copies symlinks by default', function (cb) {
+      ncp(src, out, function (err) {
+        if (err) return cb(err)
+        assert.equal(fs.readlinkSync(path.join(out, 'file-symlink')), 'foo')
+        assert.equal(fs.readlinkSync(path.join(out, 'dir-symlink')), 'dir')
+        cb()
+      })
+    })
+
+    it('copies file contents when dereference=true', function (cb) {
+      ncp(src, out, { dereference: true }, function (err) {
+        var fileSymlinkPath = path.join(out, 'file-symlink')
+        assert.ok(fs.lstatSync(fileSymlinkPath).isFile())
+        assert.equal(fs.readFileSync(fileSymlinkPath), 'foo contents')
+
+        var dirSymlinkPath = path.join(out, 'dir-symlink')
+        assert.ok(fs.lstatSync(dirSymlinkPath).isDirectory())
+        assert.deepEqual(fs.readdirSync(dirSymlinkPath), ['bar'])
+
+        cb()
+      })
+    })
+  })
+
+  describe('broken symlink handling', function () {
+    var fixtures = path.join(fixturesDir, 'broken-symlink-fixtures'),
+        src = path.join(fixtures, 'src'),
+        out = path.join(fixtures, 'out')
+
+    beforeEach(function (cb) {
+      rimraf(out, cb)
+    })
+
+    it('copies broken symlinks by default', function (cb) {
+      ncp(src, out, function (err) {
+        if (err) return cb(err)
+        assert.equal(fs.readlinkSync(path.join(out, 'broken-symlink')), 'does-not-exist')
+        cb()
+      })
+    })
+
+    it('returns an error when dereference=true', function (cb) {
+      ncp(src, out, {dereference: true}, function (err) {
+        assert.equal(err.length, 1)
+        assert.equal(err[0].code, 'ENOENT')
+        cb()
+      })
+    })
+  })
+
+  // see https://github.com/AvianFlu/ncp/issues/71
+  describe('Issue 71: Odd Async Behaviors', function(cb){
+    var fixtures = path.join(__dirname, 'fixtures', 'regular-fixtures')
+    var src = path.join(fixtures, 'src')
+    var out = path.join(fixtures, 'out')
+
+    var totalCallbacks = 0
+
+    function copyAssertAndCount(callback){
+      // rimraf(out, function() {
+        ncp(src, out, function(err){
+          totalCallbacks += 1
+          readDirFiles(src, 'utf8', function (srcErr, srcFiles) {
+            readDirFiles(out, 'utf8', function (outErr, outFiles) {
+              assert.ifError(srcErr)
+              assert.deepEqual(srcFiles, outFiles)
+              callback()
+            })
+          })
+        })
+      // })
+    }
+
+    describe('when copying a directory of files without cleaning the destination', function () {
+      it('callback fires once per run and directories are equal', function (done) {
+        var expected = 10
+        var count = 10
+
+        function next() {
+          if (count > 0) {
+            setTimeout(function(){
+              copyAssertAndCount(function() {
+                count -= 1
+                next()
+              })
+            }, 100)
+
+          } else {
+            // console.log('Total callback count is', totalCallbacks)
+            assert.equal(totalCallbacks, expected)
+            done()
+          }
+        }
+
+        next()
+
+      })
+    })
+  })
+})
diff --git a/test/output.test.js b/test/output.test.js
new file mode 100644
index 0000000..b97cf5d
--- /dev/null
+++ b/test/output.test.js
@@ -0,0 +1,69 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var testutil = require('testutil')
+var fse = require('../')
+
+/* global afterEach, beforeEach, describe, it */
+
+var TEST_DIR = ''
+
+describe('output', function () {
+  beforeEach(function() {
+    TEST_DIR = testutil.createTestDir('fs-extra')
+  })
+
+  afterEach(function(done) {
+    fse.remove(TEST_DIR, done)
+  })
+
+  describe('+ outputFile', function() {
+    describe('> when the file and directory does not exist', function() {
+      it('should create the file', function(done) {
+        var file = path.join(TEST_DIR, Math.random() + 't-ne', Math.random() + '.txt')
+        assert(!fs.existsSync(file))
+        fse.outputFile(file, 'hi jp', function(err) {
+          assert.ifError(err)
+          assert(fs.existsSync(file))
+          assert.equal(fs.readFileSync(file, 'utf8'), 'hi jp')
+          done()
+        })
+      })
+    })
+
+    describe('> when the file does exist', function() {
+      it('should still modify the file', function(done) {
+        var file = path.join(TEST_DIR, Math.random() + 't-e', Math.random() + '.txt')
+        fse.mkdirsSync(path.dirname(file))
+        fs.writeFileSync(file, 'hello world')
+        fse.outputFile(file, 'hello jp', function(err) {
+          if (err) return done(err)
+          assert.equal(fs.readFileSync(file, 'utf8'), 'hello jp')
+          done()
+        })
+      })
+    })
+  })
+
+  describe('+ outputFileSync', function() {
+    describe('> when the file and directory does not exist', function() {
+      it('should create the file', function() {
+        var file = path.join(TEST_DIR, Math.random() + 'ts-ne', Math.random() + '.txt')
+        assert(!fs.existsSync(file))
+        fse.outputFileSync(file, 'hello man')
+        assert(fs.existsSync(file))
+        assert.equal(fs.readFileSync(file, 'utf8'), 'hello man')
+      })
+    })
+
+    describe('> when the file does exist', function() {
+      it('should still modify the file', function() {
+        var file = path.join(TEST_DIR, Math.random() + 'ts-e', Math.random() + '.txt')
+        fse.mkdirsSync(path.dirname(file))
+        fs.writeFileSync(file, 'hello world')
+        fse.outputFileSync(file, 'hello man')
+        assert.equal(fs.readFileSync(file, 'utf8'), 'hello man')
+      })
+    })
+  })
+})
diff --git a/test/read.test.js b/test/read.test.js
new file mode 100644
index 0000000..8a5a32f
--- /dev/null
+++ b/test/read.test.js
@@ -0,0 +1,48 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var fse = require('../')
+var testutil = require('testutil')
+
+/* global afterEach, beforeEach, describe, it */
+
+var TEST_DIR = ''
+
+describe('read', function() {
+  beforeEach(function() {
+    TEST_DIR = testutil.createTestDir('fs-extra')
+  })
+
+  afterEach(function(done) {
+    fse.remove(TEST_DIR, done)
+  })
+
+  describe('+ readJSON', function() {
+    it('should read a file and parse the json', function(done) {
+      var obj1 = {
+        firstName: 'JP',
+        lastName: 'Richardson'
+      }
+
+      var file = path.join(TEST_DIR, 'file.json')
+      fs.writeFileSync(file, JSON.stringify(obj1))
+      fse.readJSON(file, function(err, obj2) {
+        assert.ifError(err)
+        assert.strictEqual(obj1.firstName, obj2.firstName)
+        assert.strictEqual(obj1.lastName, obj2.lastName)
+
+        done()
+      })
+    })
+
+    it('should error if it cant parse the json', function(done) {
+      var file = path.join(TEST_DIR, 'file2.json')
+      fs.writeFileSync(file, '%asdfasdff444')
+      fse.readJSON(file, function(err, obj) {
+        assert(err)
+        assert(!obj)
+        done()
+      })
+    })
+  })
+})
diff --git a/test/remove.test.js b/test/remove.test.js
new file mode 100644
index 0000000..32d444d
--- /dev/null
+++ b/test/remove.test.js
@@ -0,0 +1,124 @@
+var assert = require('assert')
+var fs = require('fs')
+var path = require('path')
+var sr = require('secure-random')
+var testutil = require('testutil')
+var fse = require('../')
+
+/* global afterEach, beforeEach, describe, it */
+
+var TEST_DIR
+
+function buildFixtureDir () {
+  var buf = sr.randomBuffer(5)
+  var baseDir = path.join(TEST_DIR, 'TEST_fs-extra_remove-' + Date.now())
+
+  fs.mkdirSync(baseDir)
+  fs.writeFileSync(path.join(baseDir, Math.random() + ''), buf)
+  fs.writeFileSync(path.join(baseDir, Math.random() + ''), buf)
+
+  var subDir = path.join(TEST_DIR, Math.random() + '')
+  fs.mkdirSync(subDir)
+  fs.writeFileSync(path.join(subDir, Math.random() + ''))
+  return baseDir
+}
+
+describe('remove', function() {
+  beforeEach(function() {
+    TEST_DIR = testutil.createTestDir('fs-extra')
+  })
+
+  afterEach(function() {
+    if (fs.existsSync(TEST_DIR)) fse.removeSync(TEST_DIR)
+  })
+
+  describe('+ removeSync()', function() {
+    it('should delete directories and files synchronously', function() {
+      assert(fs.existsSync(TEST_DIR))
+      fse.removeSync(TEST_DIR)
+      assert(!fs.existsSync(TEST_DIR))
+    })
+
+    it('should delete an empty directory synchronously', function() {
+      assert(fs.existsSync(TEST_DIR))
+      fse.removeSync(TEST_DIR)
+      assert(!fs.existsSync(TEST_DIR))
+    })
+
+    it('should delete a file synchronously', function() {
+      var file = path.join(TEST_DIR, 'file')
+      fs.writeFileSync(file, 'hello')
+      assert(fs.existsSync(file))
+      fse.removeSync(file)
+      assert(!fs.existsSync(file))
+    })
+  })
+
+  describe('+ remove()', function() {
+    it('should delete an empty directory', function(done) {
+      assert(fs.existsSync(TEST_DIR))
+      fse.remove(TEST_DIR, function(err) {
+        assert.ifError(err)
+        assert(!fs.existsSync(TEST_DIR))
+        done()
+      })
+    })
+
+    it('should delete a directory full of directories and files', function(done) {
+      buildFixtureDir()
+      assert(fs.existsSync(TEST_DIR))
+      fse.remove(TEST_DIR, function(err) {
+        assert.ifError(err)
+        assert(!fs.existsSync(TEST_DIR))
+        done()
+      })
+    })
+
+    it('should delete a file', function(done) {
+      var file = path.join(TEST_DIR, 'file')
+      fs.writeFileSync(file, 'hello')
+
+      assert(fs.existsSync(file))
+      fse.remove(file, function(err) {
+        assert.ifError(err)
+        assert(!fs.existsSync(file))
+        done()
+      })
+    })
+
+    it('should delete without a callback', function(done) {
+      var file = path.join(TEST_DIR, 'file')
+      fs.writeFileSync(file, 'hello')
+
+      assert(fs.existsSync(file))
+      var existsChecker = setInterval(function() {
+        fs.exists(file, function(itDoes) {
+          if (!itDoes) {
+            clearInterval(existsChecker)
+            done()
+          }
+        })
+      }, 25)
+      fse.remove(file)
+    })
+  })
+
+  describe('+ delete()', function() {
+    it('should delete an empty directory', function(done) {
+      assert(fs.existsSync(TEST_DIR))
+      fse['delete'](TEST_DIR, function(err) {
+        assert.ifError(err)
+        assert(!fs.existsSync(TEST_DIR))
+        done()
+      })
+    })
+  })
+
+  describe('+ deleteSync()', function() {
+    it('should delete directories and files synchronously', function() {
+      assert(fs.existsSync(TEST_DIR))
+      fse.deleteSync(TEST_DIR)
+      assert(!fs.existsSync(TEST_DIR))
+    })
+  })
+})

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-fs-extra.git



More information about the Pkg-javascript-commits mailing list