[Pkg-javascript-commits] [node-errs] 01/02: Imported Upstream version 0.3.2

Thorsten Alteholz alteholz at moszumanska.debian.org
Sun Jul 17 13:15:29 UTC 2016


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

alteholz pushed a commit to branch master
in repository node-errs.

commit 115daf5893927fe579299aea45f772fe1f4f0585
Author: Thorsten Alteholz <debian at alteholz.de>
Date:   Sun Jul 17 15:15:27 2016 +0200

    Imported Upstream version 0.3.2
---
 .gitignore                           |   3 +
 .travis.yml                          |  10 ++
 LICENSE                              |  19 +++
 README.md                            | 256 ++++++++++++++++++++++++++++++++
 examples/async-uncaught-exception.js |   9 ++
 examples/custom-error.js             |  22 +++
 examples/handling-streams.js         |  14 ++
 examples/stack.js                    |   7 +
 examples/sync-uncaught-exception.js  |   8 +
 lib/errs.js                          | 276 +++++++++++++++++++++++++++++++++++
 package.json                         |  29 ++++
 test/errs-test.js                    | 225 ++++++++++++++++++++++++++++
 test/fixtures.js                     |  23 +++
 test/macros.js                       |  91 ++++++++++++
 14 files changed, 992 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8d4c2d1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+node_modules
+.DS_Store
+npm-debug.log
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..b6a50e4
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,10 @@
+language: node_js
+node_js:
+  - 0.8
+  - 0.10
+
+notifications:
+  email:
+    - travis at nodejitsu.com
+  irc: "irc.freenode.org#nodejitsu"
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..12fd0a3
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2012 Charlie Robbins, Nuno Job, and the Contributors.
+
+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..f6f2e55
--- /dev/null
+++ b/README.md
@@ -0,0 +1,256 @@
+# errs [![Build Status](https://secure.travis-ci.org/flatiron/errs.png)](http://travis-ci.org/flatiron/errs)
+
+Simple error creation and passing utilities focused on:
+
+* [Creating Errors](#creating-errors)
+* [Reusing Error Types](#reusing-types)
+* [Merging with Existing Errors](#merging-errors)
+* [Optional Callback Invocation](#optional-invocation)
+* [Piping Error Events](#piping-errors)
+
+<a name="creating-errors" />
+## Creating Errors
+
+You should know by now that [a String is not an Error][0]. Unfortunately the `Error` constructor in Javascript isn't all that convenient either. How often do you find yourself in this situation?
+
+``` js
+  var err = new Error('This is an error. There are many like it.');
+  err.someProperty = 'more syntax';
+  err.someOtherProperty = 'it wont stop.';
+  err.notEven = 'for the mayor';
+
+  throw err;
+```
+
+Rest your fingers, `errs` is here to help. The following is equivalent to the above:
+
+``` js
+  var errs = require('errs');
+
+  throw errs.create({
+    message: 'This is an error. There are many like it.',
+    someProperty: 'more syntax',
+    someOtherProperty: 'it wont stop.',
+    notEven: 'for the mayor'
+  });
+```
+
+<a name="reusing-types" />
+## Reusing Custom Error Types
+
+`errs` also exposes an [inversion of control][1] interface for easily reusing custom error types across your application. Custom Error Types registered with `errs` will transparently invoke `Error` constructor and `Error.captureStackTrace` to attach transparent stack traces:
+
+``` js
+  /*
+   * file-a.js: Create and register your error type.
+   *
+   */
+
+  var util = require('util'),
+      errs = require('errs');
+
+  function MyError() {
+    this.message = 'This is my error; I made it myself. It has a transparent stack trace.';
+  }
+
+  //
+  // Alternatively `MyError.prototype.__proto__ = Error;`
+  //
+  util.inherits(MyError, Error);
+
+  //
+  // Register the error type
+  //
+  errs.register('myerror', MyError);
+
+
+
+  /*
+   * file-b.js: Use your error type.
+   *
+   */
+
+  var errs = require('errs');
+
+  console.log(
+    errs.create('myerror')
+      .stack
+      .split('\n')
+  );
+```
+
+The output from the two files above is shown below. Notice how it contains no references to `errs.js`:
+
+```
+[ 'MyError: This is my error; I made it myself. It has a transparent stack trace.',
+  '    at Object.<anonymous> (/file-b.js:19:8)',
+  '    at Module._compile (module.js:441:26)',
+  '    at Object..js (module.js:459:10)',
+  '    at Module.load (module.js:348:31)',
+  '    at Function._load (module.js:308:12)',
+  '    at Array.0 (module.js:479:10)',
+  '    at EventEmitter._tickCallback (node.js:192:40)' ]
+```
+
+<a name="merging-errors" />
+## Merging with Existing Errors
+
+When working with errors you catch or are returned in a callback you can extend those errors with properties by using the `errs.merge` method. This will also create a human readable error message and stack-trace:
+
+``` js
+process.on('uncaughtException', function(err) {
+  console.log(errs.merge(err, {namespace: 'uncaughtException'}));
+});
+
+var file = fs.createReadStream('FileDoesNotExist.here');
+```
+
+``` js
+{ [Error: Unspecified error]
+  name: 'Error',
+  namespace: 'uncaughtException',
+  errno: 34,
+  code: 'ENOENT',
+  path: 'FileDoesNotExist.here',
+  description: 'ENOENT, no such file or directory \'FileDoesNotExist.here\'',
+  stacktrace: [ 'Error: ENOENT, no such file or directory \'FileDoesNotExist.here\'' ] }
+```
+
+<a name="optional-invocation" />
+## Optional Callback Invocation
+
+Node.js handles asynchronous IO through the elegant `EventEmitter` API. In many scenarios the `callback` may be optional because you are returning an `EventEmitter` for piping or other event multiplexing. This complicates code with a lot of boilerplate:
+
+``` js
+  function importantFeature(callback) {
+    return someAsyncFn(function (err) {
+      if (err) {
+        if (callback) {
+          return callback(err);
+        }
+
+        throw err;
+      }
+    });
+  }
+```
+
+`errs` it presents a common API for both emitting `error` events and invoking continuations (i.e. callbacks) with errors. If a `callback` is supplied to `errs.handle()` it will be invoked with the error. It no `callback` is provided then an `EventEmitter` is returned which emits an `error` event on the next tick:
+
+``` js
+  function importantFeature(callback) {
+    return someAsyncFn(function (err) {
+      if (err) {
+        return errs.handle(err, callback);
+      }
+    });
+  }
+```
+
+<a name="piping-errors" />
+## Piping Errors
+
+Often when working with streams (especially when buffering for whatever reason), you may have already returned an `EventEmitter` or `Stream` instance by the time an error is handled.
+
+``` js
+  function pipeSomething(callback) {
+    //
+    // You have a stream (e.g. http.ResponseStream) and you
+    // have an optional `callback`.
+    //
+    var stream = new require('stream').Stream;
+
+    //
+    // You need to do something async which may respond with an
+    // error
+    //
+    getAnotherStream(function (err, source) {
+      if (err) {
+        if (callback)
+          callback(err);
+        }
+
+        stream.emit('error', err);
+        return;
+      }
+
+      source.pipe(stream);
+    })
+
+    return stream;
+  }
+```
+
+You may pass either a `function` or `EventEmitter` instance to `errs.handle`.
+
+``` js
+  function pipeSomething(callback) {
+    //
+    // You have a stream (e.g. http.ResponseStream) and you
+    // have an optional `callback`.
+    //
+    var stream = new require('stream').Stream;
+
+    //
+    // You need to do something async which may respond with an
+    // error
+    //
+    getAnotherStream(function (err, source) {
+      if (err) {
+        //
+        // Invoke the callback if it exists otherwise the stream.
+        //
+        return errs.handle(err, callback || stream);
+      }
+
+      source.pipe(stream);
+    })
+
+    return stream;
+  }
+```
+
+If you wish to invoke both a `callback` function and an `error` event simply pass both:
+
+``` js
+  errs.handle(err, callback, stream);
+```
+
+## Methods
+The `errs` modules exposes some simple utility methods:
+
+* `.create(type, opts)`: Creates a new error instance for with the specified `type` and `opts`. If the `type` is not registered then a new `Error` instance will be created.
+* `.register(type, proto)`: Registers the specified `proto` to `type` for future calls to `errors.create(type, opts)`.
+* `.unregister(type)`: Unregisters the specified `type` for future calls to `errors.create(type, opts)`.
+* `.handle(err, callback)`: Attempts to instantiate the given `error`. If the `error` is already a properly formed `error` object (with a `stack` property) it will not be modified.
+* `.merge(err, type, opts)`: Merges an existing error with a new error instance for with the specified `type` and `opts`.
+
+## Installation
+
+### Installing npm (node package manager)
+
+``` bash
+  $ curl http://npmjs.org/install.sh | sh
+```
+
+### Installing errs
+
+``` bash
+  $ [sudo] npm install errs
+```
+
+## Tests
+All tests are written with [vows][2] and should be run with [npm][3]:
+
+``` bash
+  $ npm test
+```
+
+#### Author: [Charlie Robbins](http://github.com/indexzero)
+#### Contributors: [Nuno Job](http://github.com/dscape)
+#### License: MIT
+
+[0]: http://www.devthought.com/2011/12/22/a-string-is-not-an-error/
+[1]: http://martinfowler.com/articles/injection.html
+[2]: https://vowsjs.org
+[3]: https://npmjs.org
diff --git a/examples/async-uncaught-exception.js b/examples/async-uncaught-exception.js
new file mode 100644
index 0000000..7cbf42d
--- /dev/null
+++ b/examples/async-uncaught-exception.js
@@ -0,0 +1,9 @@
+var fs = require('fs'),
+    errs = require('../lib/errs');
+
+process.on('uncaughtException', function(err) {
+  console.log(errs.merge(err, {namespace: 'uncaughtException'}));
+});
+
+var file = fs.createReadStream(__filename, {encoding: 'utf8'});
+file.on('data', function(b) { throw new Error('Oh Noes'); });
diff --git a/examples/custom-error.js b/examples/custom-error.js
new file mode 100644
index 0000000..b964e31
--- /dev/null
+++ b/examples/custom-error.js
@@ -0,0 +1,22 @@
+var util = require('util'),
+    errs = require('../lib/errs');
+
+function MyError () {
+  this.message = 'This is my error; I made it myself. It has a transparent stack trace.';
+}
+
+//
+// Alternatively `MyError.prototype.__proto__ = Error;`
+//
+util.inherits(MyError, Error);
+
+//
+// Register the error type
+//
+errs.register('myerror', MyError);
+
+console.log(
+  errs.create('myerror')
+    .stack
+    .split('\n')
+);
\ No newline at end of file
diff --git a/examples/handling-streams.js b/examples/handling-streams.js
new file mode 100644
index 0000000..725b59c
--- /dev/null
+++ b/examples/handling-streams.js
@@ -0,0 +1,14 @@
+var fs = require('fs'),
+    errs = require('../lib/errs');
+ 
+function safeReadStream(no_such_file, callback) {
+  try { 
+    return fs.createReadStream(no_such_file, callback);
+  } catch (err) {
+    return errs.handle(err, callback);
+  }
+}
+
+// would throw, now even without a callback it gets picked as a stream
+var file = fs.createReadStream('FileDoesNotExist.here');
+file.on('error', function (err) { console.log(err); });
\ No newline at end of file
diff --git a/examples/stack.js b/examples/stack.js
new file mode 100644
index 0000000..3672807
--- /dev/null
+++ b/examples/stack.js
@@ -0,0 +1,7 @@
+var errs = require('../lib/errs');
+
+console.log(
+  errs.create('This is an error. There are many like it. It has a transparent stack trace.')
+    .stack
+    .split('\n')
+);
\ No newline at end of file
diff --git a/examples/sync-uncaught-exception.js b/examples/sync-uncaught-exception.js
new file mode 100644
index 0000000..11b04ef
--- /dev/null
+++ b/examples/sync-uncaught-exception.js
@@ -0,0 +1,8 @@
+var fs = require('fs'),
+    errs = require('../lib/errs');
+
+process.on('uncaughtException', function(err) {
+  console.log(errs.merge(err, {namespace: 'uncaughtException'}));
+});
+
+var file = fs.createReadStream('FileDoesNotExist.here');
diff --git a/lib/errs.js b/lib/errs.js
new file mode 100644
index 0000000..6beaaf3
--- /dev/null
+++ b/lib/errs.js
@@ -0,0 +1,276 @@
+/*
+ * errs.js: Simple error creation and passing utilities.
+ *
+ * (C) 2012, Charlie Robbins, Nuno Job, and the Contributors.
+ * MIT LICENSE
+ *
+ */
+
+var events = require('events'),
+    util = require('util');
+
+//
+// Container for registered error types.
+//
+exports.registered = {};
+
+//
+// Add `Error.prototype.toJSON` if it doesn't exist.
+//
+if (!Error.prototype.toJSON) {
+  Object.defineProperty(Error.prototype, 'toJSON', {
+    enumerable: false,
+    writable: true,
+    value: function () {
+      return mixin({
+        message: this.message,
+        stack: this.stack,
+        arguments: this.arguments,
+        type: this.type
+      }, this);
+    }
+  });
+}
+
+//
+// ### function create (type, opts)
+// #### @type {string} **Optional** Registered error type to create
+// #### @opts {string|object|Array|function} Options for creating the error:
+//   * `string`:   Message for the error
+//   * `object`:   Properties to include on the error
+//   * `array`:    Message for the error (' ' joined).
+//   * `function`: Function to return error options.
+//
+// Creates a new error instance for with the specified `type`
+// and `options`. If the `type` is not registered then a new
+// `Error` instance will be created.
+//
+exports.create = function createErr(type, opts) {
+  if (!arguments[1] && !exports.registered[type]) {
+    opts = type;
+    type = null;
+  }
+
+  //
+  // If the `opts` has a `stack` property assume
+  // that it is already an error instance.
+  //
+  if (opts && opts.stack) {
+    return opts;
+  }
+
+  var message,
+      ErrorProto,
+      error;
+
+  //
+  // Parse arguments liberally for the message
+  //
+  if (typeof opts === 'function') {
+    opts = opts();
+  }
+
+  if (Array.isArray(opts)) {
+    message = opts.join(' ');
+    opts = null;
+  }
+  else if (opts) {
+    switch (typeof opts) {
+      case 'string':
+        message = opts || 'Unspecified error';
+        opts = null;
+        break;
+      case 'object':
+        message = (opts && opts.message) || 'Unspecified error';
+        break;
+      default:
+        message = 'Unspecified error';
+        break;
+    }
+  }
+
+  //
+  // Instantiate a new Error instance or a new
+  // registered error type (if it exists).
+  //
+  ErrorProto = type && exports.registered[type] || Error;
+  error = new (ErrorProto)(message);
+
+  if (!error.name || error.name === 'Error') {
+    error.name = (opts && opts.name) || ErrorProto.name || 'Error';
+  }
+
+  //
+  // Capture a stack trace if it does not already exist and
+  // remote the part of the stack trace referencing `errs.js`.
+  //
+  if (!error.stack) {
+    Error.call(error);
+    Error.captureStackTrace(error, createErr);
+  }
+  else {
+    error.stack = error.stack.split('\n');
+    error.stack.splice(1, 1);
+    error.stack = error.stack.join('\n');
+  }
+
+  //
+  // Copy all options to the new error instance.
+  //
+  if (opts) {
+    Object.keys(opts).forEach(function (key) {
+      error[key] = opts[key];
+    });
+  }
+
+  return error;
+};
+
+//
+// ### function merge (err, type, opts)
+// #### @err  {error}  **Optional** The error to merge
+// #### @type {string} **Optional** Registered error type to create
+// #### @opts {string|object|Array|function} Options for creating the error:
+//   * `string`:   Message for the error
+//   * `object`:   Properties to include on the error
+//   * `array`:    Message for the error (' ' joined).
+//   * `function`: Function to return error options.
+//
+// Merges an existing error with a new error instance for with
+// the specified `type` and `options`.
+//
+exports.merge = function (err, type, opts) {
+  var merged = exports.create(type, opts);
+
+  //
+  // If there is no error just return the merged one
+  //
+  if (err == undefined || err == null) {
+    return merged;
+  }
+
+  //
+  // optional stuff that might be created by module
+  //
+  if (!Array.isArray(err) && typeof err === 'object') {
+    Object.keys(err).forEach(function (key) {
+      //
+      // in node v0.4 v8 errors where treated differently
+      // we need to make sure we aren't merging these properties
+      // http://code.google.com/p/v8/issues/detail?id=1215
+      //
+      if (['stack', 'type', 'arguments', 'message'].indexOf(key)===-1) {
+        merged[key] = err[key];
+      }
+    });
+  }
+
+  // merging
+  merged.name = merged.name || err.name;
+  merged.message = merged.message || err.message;
+
+  // override stack
+  merged.stack = err.stack || merged.stack;
+
+  // add human-readable errors
+  if (err.message) {
+    merged.description = err.message;
+  }
+
+  if (err.stack && err.stack.split) {
+    merged.stacktrace = err.stack.split("\n");
+  }
+
+  return merged;
+};
+
+//
+// ### function handle (error, callback)
+// #### @error {string|function|Array|object} Error to handle
+// #### @callback {function|EventEmitter} **Optional** Continuation or stream to pass the error to.
+// #### @stream {EventEmitter} **Optional** Explicit EventEmitter to use.
+//
+// Attempts to instantiate the given `error`. If the `error` is already a properly
+// formed `error` object (with a `stack` property) it will not be modified.
+//
+// * If `callback` is a function, it is invoked with the `error`.
+// * If `callback` is an `EventEmitter`, it emits the `error` event on
+//   that emitter and returns it.
+// * If no `callback`, return a new `EventEmitter` which emits `error`
+//   on `process.nextTick()`.
+//
+exports.handle = function (error, callback, stream) {
+  error = exports.create(error);
+
+  if (typeof callback === 'function') {
+    callback(error);
+  }
+
+  if (typeof callback !== 'function' || stream) {
+    var emitter = stream || callback || new events.EventEmitter();
+    process.nextTick(function () { emitter.emit('error', error); });
+    return emitter;
+  }
+};
+
+//
+// ### function register (type, proto)
+// #### @type {string} **Optional** Type of the error to register.
+// #### @proto {function} Constructor function of the error to register.
+//
+// Registers the specified `proto` to `type` for future calls to
+// `errors.create(type, opts)`.
+//
+exports.register = function (type, proto) {
+  if (arguments.length === 1) {
+    proto = type;
+    type = proto.name.toLowerCase();
+  }
+  exports.registered[type] = proto;
+};
+
+//
+// ### function unregister (type)
+// #### @type {string} Type of the error to unregister.
+//
+// Unregisters the specified `type` for future calls to
+// `errors.create(type, opts)`.
+//
+exports.unregister = function (type) {
+  delete exports.registered[type];
+};
+
+//
+// ### function mixin (target [source0, source1, ...])
+// Copies enumerable properties from `source0 ... sourceN`
+// onto `target` and returns the resulting object.
+//
+function mixin(target) {
+  //
+  // Quickly and performantly (in V8) `Arrayify` arguments.
+  //
+  var len = arguments.length,
+      args = new Array(len - 1),
+      i = 1;
+
+  for (; i < len; i++) {
+    args[i - 1] = arguments[i];
+  }
+
+  args.forEach(function (o) {
+    Object.keys(o).forEach(function (attr) {
+      var getter = o.__lookupGetter__(attr),
+          setter = o.__lookupSetter__(attr);
+
+      if (!getter && !setter) {
+        target[attr] = o[attr];
+      }
+      else {
+        if (setter) { target.__defineSetter__(attr, setter) }
+        if (getter) { target.__defineGetter__(attr, getter) }
+      }
+    });
+  });
+
+  return target;
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..7593a4b
--- /dev/null
+++ b/package.json
@@ -0,0 +1,29 @@
+{
+  "name": "errs",
+  "description": "Simple error creation and passing utilities",
+  "version": "0.3.2",
+  "author": "Charlie Robbins <charlie.robbins at gmail.com>",
+  "maintainers": [
+    "dscape <nuno at nodejitsu.com>"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "http://github.com/indexzero/errs.git"
+  },
+  "keywords": [
+    "errors",
+    "error",
+    "utilities"
+  ],
+  "devDependencies": {
+    "vows": "0.8.x"
+  },
+  "main": "./lib/errs",
+  "scripts": {
+    "test": "vows test/*-test.js --spec"
+  },
+  "engines": {
+    "node": ">= 0.4.0"
+  }
+}
+
diff --git a/test/errs-test.js b/test/errs-test.js
new file mode 100644
index 0000000..2c9d39a
--- /dev/null
+++ b/test/errs-test.js
@@ -0,0 +1,225 @@
+/*
+ * errs-test.js: Tests for the `errs` module.
+ *
+ * (C) 2012, Charlie Robbins, Nuno Job, and the Contributors.
+ * MIT LICENSE
+ *
+ */
+
+var assert = require('assert'),
+    events = require('events'),
+    vows = require('vows'),
+    errs = require('../lib/errs'),
+    fixtures = require('./fixtures'),
+    macros = require('./macros');
+
+var opts = [{
+  foo: 'bar',
+  status: 404,
+  whatever: 'some other property'
+}, {
+  testing: true,
+  'some-string': 'is-a-value',
+  message: 'This is an error. There are many like it.'
+}, {
+  'a-function': 'that returns an object',
+  should: true,
+  have: 4,
+  properties: 'yes'
+}];
+
+vows.describe('errs').addBatch({
+  "Using errs module": {
+    "the register() method": {
+      "should register the prototype": function () {
+        errs.register('named', fixtures.NamedError);
+        assert.equal(errs.registered['named'], fixtures.NamedError);
+      },
+      "should register an error without providing its name": function () {
+        errs.register(fixtures.AnError);
+        assert.equal(errs.registered['anerror'], fixtures.AnError);
+      }
+    },
+    "the create() method with": {
+      "a string": macros.create.string('An error as a string'),
+      "no parameters": macros.create.string('An error as a string'),
+      "an object": {
+        "that has no message": macros.create.object(opts[0]),
+        "that has a message": macros.create.object(opts[1]),
+        "that has a name": {
+          topic : errs.create({name: 'OverflowError'}),
+          "should respect that name in the stack trace" : function (err) {
+            assert.match(err.stack, /^OverflowError/);
+          },
+        }
+      },
+      "an error": macros.create.err(new Error('An instance of an error')),
+      "a function": macros.create.fn(function () {
+        return opts[2];
+      }),
+      "a registered type": {
+        "that exists": macros.create.registered('named', fixtures.NamedError, opts[1]),
+        "that doesnt exist": macros.create.registered('bad', null, opts[1])
+      }
+    },
+    "the handle() method": {
+      "with a callback": {
+        topic: function () {
+          var err = this.err = errs.create('Some async error');
+          errs.handle(err, this.callback.bind(this, null));
+        },
+        "should invoke the callback with the error": function (_, err) {
+          assert.equal(err, this.err);
+        }
+      },
+      "with an EventEmitter (i.e. stream)": {
+        topic: function () {
+          var err = this.err = errs.create('Some emitted error'),
+              stream = new events.EventEmitter();
+
+          stream.once('error', this.callback.bind(this, null));
+          errs.handle(err, stream);
+        },
+        "should emit the `error` event": function (_, err) {
+          assert.equal(err, this.err);
+        }
+      },
+      "with a callback and an EventEmitter": {
+        topic: function () {
+          var err = this.err = errs.create('Some emitted error'),
+              stream = new events.EventEmitter(),
+              invoked = 0,
+              that = this;
+
+          function onError(err) {
+            if (++invoked === 2) {
+              that.callback.call(that, null, err);
+            }
+          }
+
+          stream.once('error', onError);
+          errs.handle(err, onError, stream);
+        },
+        "should emit the `error` event": function (_, err) {
+          assert.equal(err, this.err);
+        }
+      },
+      "with no callback": {
+        topic: function () {
+          var err = this.err = errs.create('Some emitted error'),
+              emitter = errs.handle(err);
+
+          emitter.once('error', this.callback.bind(this, null));
+        },
+        "should emit the `error` event": function (_, err) {
+          assert.equal(err, this.err);
+        }
+      }
+    }
+  }
+}).addBatch({
+  "Using errs module": {
+    "the unregister() method": {
+      "should unregister the prototype": function () {
+        errs.unregister('named');
+        assert.isTrue(!errs.registered['named']);
+      }
+    }
+  }
+}).addBatch({
+  "Using errs module": {
+    "the merge() method": {
+      "supports": {
+        "an undefined error": function () {
+          var err = errs.merge(undefined, { message: 'oh noes!' });
+          assert.equal(err.message, 'oh noes!')
+          assert.instanceOf(err, Error);
+        },
+        "a null error": function () {
+          var err = errs.merge(null, { message: 'oh noes!' });
+          assert.equal(err.message, 'oh noes!')
+          assert.instanceOf(err, Error);
+        },
+        "a false error": function () {
+          var err = errs.merge(false, { message: 'oh noes!' });
+          assert.equal(err.message, 'oh noes!')
+          assert.instanceOf(err, Error);
+        },
+        "a string error": function () {
+          var err = errs.merge('wat', { message: 'oh noes!' });
+          assert.equal(err.message, 'oh noes!');
+          assert.instanceOf(err, Error);
+        },
+      },
+      "should preserve custom properties": function () {
+        var err = new Error('Msg!');
+        err.foo = "bar";
+        err = errs.merge(err, {message: "Override!", ns: "test"});
+        assert.equal(err.foo, "bar");
+      },
+      "should have a stack trace": function () {
+        var err = new Error('Msg!');
+        err = errs.merge(err, {});
+        assert.isTrue(Array.isArray(err.stacktrace));
+      },
+      "should preserve message specified in create": function () {
+        var err = new Error('Msg!');
+        err = errs.merge(err, {message: "Override!"});
+        assert.equal(err.message, "Override!");
+      },
+      "should preserve properties specified": function () {
+        var err = new Error('Msg!');
+        err = errs.merge(err, {ns: "test"});
+        assert.equal(err.ns, "test");
+      },
+      "with a truthy value": function () {
+        var err = errs.merge(true, {
+          message: 'Override!',
+          ns: 'lolwut'
+        })
+        assert.equal(err.message, 'Override!');
+        assert.equal(err.ns, 'lolwut');
+      },
+      "with a truthy stack": function () {
+        var err = errs.merge({ stack: true } , {
+          message: 'Override!',
+          ns: 'lolwut'
+        })
+        assert.equal(err.message, 'Override!');
+        assert.equal(err.ns, 'lolwut');
+      },
+      "with an Array stack": function () {
+        var err = errs.merge({ stack: [] } , {
+          message: 'Override!',
+          ns: 'lolwut'
+        })
+        assert.equal(err.message, 'Override!');
+        assert.equal(err.ns, 'lolwut');
+      }
+    }
+  }
+}).addBatch({
+  "Using errs module": {
+    "Error.prototype.toJSON": {
+      "should exist": function () {
+        assert.isFunction(Error.prototype.toJSON);
+
+        var json = (new Error('Testing 12345')).toJSON();
+
+        ['message', 'stack', 'arguments', 'type'].forEach(function (prop) {
+          assert.isObject(Object.getOwnPropertyDescriptor(json, prop));
+        })
+      },
+      "should be writable": function () {
+        var orig = Error.prototype.toJSON;
+        Error.prototype.toJSON = function() {
+          return 'foo';
+        };
+        var json = (new Error('Testing 12345')).toJSON();
+
+        assert.equal(json, 'foo');
+        Error.prototype.toJSON = orig;
+      }
+    }
+  }
+}).export(module);
diff --git a/test/fixtures.js b/test/fixtures.js
new file mode 100644
index 0000000..cc13b22
--- /dev/null
+++ b/test/fixtures.js
@@ -0,0 +1,23 @@
+/*
+ * fixtures.js: Test fixtures for the `errs` module.
+ *
+ * (C) 2012, Charlie Robbins, Nuno Job, and the Contributors.
+ * MIT LICENSE
+ *
+ */
+
+var util = require('util');
+
+var fixtures = exports;
+
+fixtures.NamedError = function NamedError() {
+  this.named = true;
+};
+
+util.inherits(fixtures.NamedError, Error);
+
+fixtures.AnError = function AnError() {
+  this.named = true;
+};
+
+util.inherits(fixtures.AnError, Error);
diff --git a/test/macros.js b/test/macros.js
new file mode 100644
index 0000000..2b962d4
--- /dev/null
+++ b/test/macros.js
@@ -0,0 +1,91 @@
+/*
+ * macros.js: Test macros for the `errs` module.
+ *
+ * (C) 2012, Charlie Robbins, Nuno Job, and the Contributors.
+ * MIT LICENSE
+ *
+ */
+
+var assert = require('assert'),
+    errs = require('../lib/errs');
+
+var macros = exports;
+
+function assertTransparentStack(err) {
+  assert.isString(err.stack);
+  err.stack.split('\n').forEach(function (line) {
+    assert.isFalse(/\/lib\/errs\.js\:/.test(line));
+  });
+}
+
+//
+// Macros for `errs.create(type, opts)`.
+//
+macros.create = {};
+
+macros.create.string = function (msg) {
+  return {
+    topic: errs.create(msg),
+    "should create an error with the correct message": function (err) {
+      assert.instanceOf(err, Error);
+      assert.equal(msg, err.message);
+      assertTransparentStack(err);
+    }
+  };
+};
+
+macros.create.object = function (obj) {
+  return {
+    topic: errs.create(obj),
+    "should create an error with the specified properties": function (err) {
+      assert.instanceOf(err, Error);
+      assert.equal(err.message, obj.message || 'Unspecified error');
+      assertTransparentStack(err);
+      Object.keys(obj).forEach(function (key) {
+        assert.equal(err[key], obj[key]);
+      });
+    }
+  };
+};
+
+macros.create.err = function (inst) {
+  return {
+    topic: errs.create(inst),
+    "should return the error unmodified": function (err) {
+      assert.equal(err, inst);
+      assertTransparentStack(err);
+    }
+  };
+};
+
+macros.create.fn = function (fn) {
+  var obj = fn();
+
+  return {
+    topic: errs.create(fn),
+    "should create an error with the specified properties": function (err) {
+      assert.instanceOf(err, Error);
+      assert.equal(err.message, obj.message || 'Unspecified error');
+      assertTransparentStack(err);
+      Object.keys(obj).forEach(function (key) {
+        assert.equal(err[key], obj[key]);
+      });
+    }
+  };
+};
+
+macros.create.registered = function (type, proto, obj) {
+  return {
+    topic: function () {
+      return errs.create(type, obj);
+    },
+    "should create an error of the correct type": function (err) {
+      assert.instanceOf(err, proto || Error);
+      assert.equal(err.message, obj.message || 'Unspecified error');
+      assertTransparentStack(err);
+      Object.keys(obj).forEach(function (key) {
+        assert.equal(err[key], obj[key]);
+      });
+    }
+  };
+};
\ No newline at end of file

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



More information about the Pkg-javascript-commits mailing list