[Pkg-javascript-commits] [node-test] 01/05: Import Upstream version 0.6.0

Sruthi Chandran srud-guest at moszumanska.debian.org
Fri Oct 14 06:39:36 UTC 2016


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

srud-guest pushed a commit to branch master
in repository node-test.

commit 9785c5e4c5a62218bdf1721a76c9f06049cdfb5d
Author: Sruthi <srud at disroot.org>
Date:   Fri Oct 14 11:53:28 2016 +0530

    Import Upstream version 0.6.0
---
 .gitmodules            |   3 +
 .travis.yml            |   4 +
 History.md             | 113 +++++++++++++++++
 License.md             |  19 +++
 Readme.md              | 119 ++++++++++++++++++
 assert.js              | 334 ++++++++++++++++++++++++++++++++++++++++++++++++
 logger.js              |  78 ++++++++++++
 package.json           |  48 +++++++
 test.js                |  93 ++++++++++++++
 test/assert.js         | 132 +++++++++++++++++++
 test/async.js          |  74 +++++++++++
 test/custom-asserts.js |  48 +++++++
 test/fail-fast.js      |  71 +++++++++++
 test/index.js          |   8 ++
 test/utils/logger.js   |  23 ++++
 utils.js               | 336 +++++++++++++++++++++++++++++++++++++++++++++++++
 16 files changed, 1503 insertions(+)

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..36c7036
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "engines/node/ansi-font"]
+	path = engines/node/ansi-font
+	url = https://github.com/Gozala/ansi-font.git
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..895dbd3
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+  - 0.6
+  - 0.8
diff --git a/History.md b/History.md
new file mode 100644
index 0000000..226047c
--- /dev/null
+++ b/History.md
@@ -0,0 +1,113 @@
+# Changes
+
+## 0.6.0 / 2012-11-24
+
+  - Fix assertion for error objects to ignore stack traces on PhantomJS
+    & to make node does asserts them properly.
+
+## 0.5.2 / 2012-10-31
+
+  - Exit only when `process.exit` is defined. This enables use of browseryfied
+    tests in browser.
+  - Start testing with PanthomJS in a browser.
+
+## 0.5.1 / 2012-10-31
+
+  - Fix bug introduced in 0.5.0 that exited process with a wrong code.
+  - Add `assert.end` function as an alternative to `done` callback.
+  - Change module layout to match better node conventions.
+
+## 0.5.0 / 2012-10-31
+
+  - Switch to logging via `console.log` instead of `process.stdout` for
+    better compatibility with browserify.
+  - Exit process with error code if test fails, or with `0` if not.
+
+## 0.4.4 / 2012-01-15
+
+  - Improve `assert.throws` API to accept exception as an argument.
+
+## 0.4.3 / 2011-11-15
+
+   - Use newer version of ansi-font library.
+    
+## 0.4.2 / 2011-11-15
+
+   - Use bug.url to avoid warning form NPM.
+
+## 0.4.1 / 2011-07-18 ##
+
+  - Improved error reporting.
+
+## 0.4.0 / 2011-07-10 ##
+
+  - Support for browser runtime.
+
+## 0.3.0 / 2011-07-10 ##
+
+  - Switching to Uncommonjs spec.
+  - Simplifying implementation.
+
+## 0.2.1 / 2011-06-10 ##
+
+  - RegExp support for `assert.throws`.
+
+## 0.2.0 / 2011-06-07 ##
+
+  - Code refactoring & package restructuring.
+  - Processing code through jsbeautifier for better readability.
+
+## 0.1.1 / 2011-04-02 ##
+
+  - Bugfix for `assert.throws` regression.
+
+## 0.1.0 / 2011-02-24 ##
+
+  - Package restructuring to support node at 0.4.0
+
+## 0.0.11 / 2011-02-16 ##
+
+  - Removing 'use strict' where octal escape sequences were used.
+
+## 0.0.10 / 2010-11-11 ##
+
+  - Improved error reporting.
+
+## 0.0.9 / 2010-11-01 ##
+
+  - Switching to MIT license.
+  - Fix for `deepEqual`
+
+## 0.0.8 / 2010-10-23 ##
+
+  - Even more improved fail reports.
+
+## 0.0.7 / 2010-10-23 ##
+
+  - Improved fail reports.
+
+## 0.0.6 / 2010-10-08 ##
+
+  - Improving project documentation.
+
+## 0.0.5 / 2010-10-07 ##
+
+  - Improved fail and error messages.
+
+## 0.0.4 / 2010-10-07 ##
+
+  - Adding more tests for custom asserts.
+
+## 0.0.3 / 2010-10-06 ##
+
+  - Rename `raises` bach to `throws` to follow the spec.
+
+## 0.0.2 / 2010-09-29 ##
+
+  - Bugfix.
+  - Adding test.
+  - Support for async tests.
+
+## 0.0.1 / 2010-09-25 ##
+
+  - Unit test runner port from narwhal.
diff --git a/License.md b/License.md
new file mode 100644
index 0000000..7222996
--- /dev/null
+++ b/License.md
@@ -0,0 +1,19 @@
+
+Copyright 2011 Irakli Gozalishvili. All rights reserved.
+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..38e5232
--- /dev/null
+++ b/Readme.md
@@ -0,0 +1,119 @@
+# (Un)commonJS unit test runner
+
+Implementation of [(Un)commonJS unit test runner][UncommonJS unit test runner].
+
+[![build status](https://secure.travis-ci.org/Gozala/test-commonjs.png)](http://travis-ci.org/Gozala/test-commonjs)
+
+## Testing
+
+In order to make your package testable from [npm] you should:
+
+- Create a directory in your package root.
+- Define test directory in package descriptor under `directories` section.
+- Define test script in package descriptor under `scripts` section.
+- Define dependency on this package (It's name is "test" in [npm] registry).
+- Write your tests
+- Test your package by running all tests `npm test`
+  or run individual tests `node ./path/to/test/group.js`
+
+## Example
+
+### package.json
+
+```js
+{
+  "name": "mypackage",
+  "version": "0.7.0",
+  "description": "Sample package",
+  "scripts": { "test": "node test/all.js" },
+  "devDependencies": { "test": ">=0.0.5" }
+}
+```
+
+### Async test
+
+```js
+// if test function expects second named argument it will be executed
+// in async mode and test will be complete only after callback is called
+exports['test my async foo'] = function(assert, done) {
+  var http = require('http')
+  var google = http.createClient(80, 'www.jeditoolkit.com')
+  var request = google.request('GET', '/', {'host': 'www.jeditoolkit.com'})
+  request.end()
+  request.on('response', function (response) {
+    assert.equal(response.statusCode, 302, 'must redirect') // will log result
+    response.setEncoding('utf8')
+    response.on('data', function (chunk) {
+      assert.notEqual(chunk, 'helo world', 'must be something more inteligent')
+      done() // telling test runner that we're done with this test
+    })
+  })
+}
+
+if (module == require.main) require('test').run(exports)
+```
+
+### Sync test
+
+```js
+// using assert passed to the test function that just logs failures
+exports['test that logs all failures'] = function(assert) {
+  assert.equal(2 + 2, 5, 'assert failure is logged')
+  assert.equal(3 + 2, 5, 'assert pass is logged')
+}
+
+if (module == require.main) require('test').run(exports)
+```
+
+### Fast fail
+
+```js
+// using nodejs's build in asserts that throw on failure
+var assert = require('assert')
+
+exports['test that stops execution on first failure'] = function() {
+  assert.equal(2 + 2, 5, 'assert fails and test execution stop here')
+  assert.equal(3 + 2, 5, 'will never pass this since test failed above')
+}
+
+if (module == require.main) require('test').run(exports)
+```
+
+### Custom assertions
+
+```js
+var AssertBase = require('assert').Assert
+var AssertDescriptor = {
+  constructor: { value: Assert },
+  inRange: { value: function (lower, inner, upper, message) {
+    if (lower < inner && inner < upper) {
+      this.fail({
+        actual: inner,
+        expected: lower + '> ' + ' < ' + upper,
+        operator: "inRange",
+        message: message
+      })
+    } else {
+      this.pass(message);
+    }
+  }, enumerable: true }
+}
+function Assert() {
+  return Object.create(AssertBase.apply(null, arguments), AssertDescriptor)
+}
+
+// bundling custom asserts with test suite
+exports.Assert = Assert
+exports['test with custom asserts'] = function(assert) {
+  assert.inRange(2, 3, 5, 'passes assert and logs')
+  assert.equal(3 + 2, 5, 'assert pass is logged')
+}
+
+if (module == require.main) require('test').run(exports)
+```
+
+For more examples checkout tests for this package and for more details see
+the [UncommonJS unit test runner] specification.
+
+[UncommonJS unit test runner]:https://github.com/kriskowal/uncommonjs/blob/master/tests/specification.md
+[npm]:http://npmjs.org/
diff --git a/assert.js b/assert.js
new file mode 100644
index 0000000..4219711
--- /dev/null
+++ b/assert.js
@@ -0,0 +1,334 @@
+"use strict";
+
+var utils = require("./utils")
+
+
+/**
+ * The `AssertionError` is defined in assert.
+ * @extends Error
+ * @example
+ *  new assert.AssertionError({
+ *    message: message,
+ *    actual: actual,
+ *    expected: expected
+ *  })
+ */
+function AssertionError(options) {
+  var assertionError = Object.create(AssertionError.prototype);
+
+  if (utils.isString(options))
+    options = { message: options };
+  if ("actual" in options)
+    assertionError.actual = options.actual;
+  if ("expected" in options)
+    assertionError.expected = options.expected;
+  if ("operator" in options)
+    assertionError.operator = options.operator;
+
+  assertionError.message = options.message;
+  assertionError.stack = new Error().stack;
+  return assertionError;
+}
+AssertionError.prototype = Object.create(Error.prototype, {
+  constructor: { value: AssertionError },
+  name: { value: "AssertionError", enumerable: true },
+  toString: { value: function toString() {
+    var value;
+    if (this.message) {
+      value = this.name + " : " + this.message;
+    }
+    else {
+      value = [
+        this.name + " : ",
+        utils.source(this.expected),
+        this.operator,
+        utils.source(this.actual)
+      ].join(" ");
+    }
+    return value;
+  }}
+});
+exports.AssertionError = AssertionError;
+
+function Assert(logger) {
+  return Object.create(Assert.prototype, { _log: { value: logger }});
+}
+Assert.prototype = {
+  fail: function fail(e) {
+    this._log.fail(e);
+  },
+  pass: function pass(message) {
+    this._log.pass(message);
+  },
+  error: function error(e) {
+    this._log.error(e);
+  },
+  ok: function ok(value, message) {
+    if (!!!value) {
+      this.fail({
+        actual: value,
+        expected: true,
+        message: message,
+        operator: "=="
+      });
+    }
+    else {
+      this.pass(message);
+    }
+  },
+
+  /**
+   * The equality assertion tests shallow, coercive equality with `==`.
+   * @example
+   *    assert.equal(1, 1, "one is one");
+   */
+  equal: function equal(actual, expected, message) {
+    if (actual == expected) {
+      this.pass(message);
+    }
+    else {
+      this.fail({
+        actual: actual,
+        expected: expected,
+        message: message,
+        operator: "=="
+      });
+    }
+  },
+
+  /**
+   * The non-equality assertion tests for whether two objects are not equal
+   * with `!=`.
+   * @example
+   *    assert.notEqual(1, 2, "one is not two");
+   */
+  notEqual: function notEqual(actual, expected, message) {
+    if (actual != expected) {
+      this.pass(message);
+    }
+    else {
+      this.fail({
+        actual: actual,
+        expected: expected,
+        message: message,
+        operator: "!=",
+      });
+    }
+  },
+
+  /**
+   * The equivalence assertion tests a deep (with `===`) equality relation.
+   * @example
+   *    assert.deepEqual({ a: "foo" }, { a: "foo" }, "equivalent objects")
+   */
+   deepEqual: function deepEqual(actual, expected, message) {
+    if (isDeepEqual(actual, expected)) {
+      this.pass(message);
+    }
+    else {
+      this.fail({
+        actual: actual,
+        expected: expected,
+        message: message,
+        operator: "deepEqual"
+      });
+    }
+  },
+
+  /**
+   * The non-equivalence assertion tests for any deep (with `===`) inequality.
+   * @example
+   *    assert.notDeepEqual({ a: "foo" }, Object.create({ a: "foo" }),
+   *                        "object"s inherit from different prototypes");
+   */
+  notDeepEqual: function notDeepEqual(actual, expected, message) {
+    if (!isDeepEqual(actual, expected)) {
+      this.pass(message);
+    }
+    else {
+      this.fail({
+        actual: actual,
+        expected: expected,
+        message: message,
+        operator: "notDeepEqual"
+      });
+    }
+  },
+
+  /**
+   * The strict equality assertion tests strict equality, as determined by
+   * `===`.
+   * @example
+   *    assert.strictEqual(null, null, "`null` is `null`")
+   */
+  strictEqual: function strictEqual(actual, expected, message) {
+    if (actual === expected) {
+      this.pass(message);
+    }
+    else {
+      this.fail({
+        actual: actual,
+        expected: expected,
+        message: message,
+        operator: "==="
+      });
+    }
+  },
+
+  /**
+   * The strict non-equality assertion tests for strict inequality, as
+   * determined by `!==`.
+   * @example
+   *    assert.notStrictEqual(null, undefined, "`null` is not `undefined`");
+   */
+  notStrictEqual: function notStrictEqual(actual, expected, message) {
+    if (actual !== expected) {
+      this.pass(message);
+    }
+    else {
+      this.fail({
+        actual: actual,
+        expected: expected,
+        message: message,
+        operator: "!=="
+      })
+    }
+  },
+
+  /**
+   * The assertion whether or not given `block` throws an exception. If optional
+   * `Error` argument is provided and it"s type of function thrown error is
+   * asserted to be an instance of it, if type of `Error` is string then message
+   * of throw exception is asserted to contain it.
+   * @param {Function} block
+   *    Function that is expected to throw.
+   * @param {Error|RegExp} [Error]
+   *    Error constructor that is expected to be thrown or a string that
+   *    must be contained by a message of the thrown exception, or a RegExp
+   *    matching a message of the thrown exception.
+   * @param {String} message
+   *    Description message
+   *
+   * @examples
+   *
+   *    assert.throws(function block() {
+   *      doSomething(4)
+   *    }, "Object is expected", "Incorrect argument is passed");
+   *
+   *    assert.throws(function block() {
+   *      Object.create(5)
+   *    }, TypeError, "TypeError is thrown");
+   */
+  throws: function throws(block, Error, message) {
+    var threw = false;
+    var exception = null;
+
+    // If third argument is not provided and second argument is a string it
+    // means that optional `Error` argument was not passed, so we shift
+    // arguments.
+    if (utils.isString(Error) && utils.isUndefined(message)) {
+      message = Error;
+      Error = undefined;
+    }
+
+    // Executing given `block`.
+    try {
+      block();
+    }
+    catch (e) {
+      threw = true;
+      exception = e;
+    }
+
+    // If exception was thrown and `Error` argument was not passed assert is
+    // passed.
+    if (threw && (utils.isUndefined(Error) ||
+                 // If Error is thrown exception
+                 (Error == exception) ||
+                 // If passed `Error` is RegExp using it"s test method to
+                 // assert thrown exception message.
+                 (utils.isRegExp(Error) && Error.test(exception.message)) ||
+                 // If passed `Error` is a constructor function testing if
+                 // thrown exception is an instance of it.
+                 (utils.isFunction(Error) && utils.instanceOf(exception, Error))))
+    {
+      this.pass(message);
+    }
+
+    // Otherwise we report assertion failure.
+    else {
+      var failure = {
+        message: message,
+        operator: "throws"
+      };
+
+      if (exception)
+        failure.actual = exception;
+
+      if (Error)
+        failure.expected = Error;
+
+      this.fail(failure);
+    }
+  }
+};
+exports.Assert = Assert;
+
+function isDeepEqual(actual, expected) {
+  // 7.1. All identical values are equivalent, as determined by ===.
+  if (actual === expected) {
+    return true;
+  }
+
+  // 7.2. If the expected value is a Date object, the actual value is
+  // equivalent if it is also a Date object that refers to the same time.
+  else if (utils.isDate(actual) && utils.isDate(expected)) {
+    return actual.getTime() === expected.getTime();
+  }
+
+  // XXX specification bug: this should be specified
+  else if (utils.isPrimitive(actual) || utils.isPrimitive(expected)) {
+    return expected === actual;
+  }
+
+  else if (utils.instanceOf(actual, Error) ||
+           utils.instanceOf(expected, Error)) {
+    return actual.message === expected.message &&
+           actual.type === expected.type &&
+           actual.name === expected.name &&
+           (actual.constructor && expected.constructor &&
+            actual.constructor.name === expected.constructor.name)
+  }
+
+  // 7.3. Other pairs that do not both pass typeof value == "object",
+  // equivalence is determined by ==.
+  else if (!utils.isObject(actual) && !utils.isObject(expected)) {
+    return actual == expected;
+  }
+
+  // 7.4. For all other Object pairs, including Array objects, equivalence is
+  // determined by having the same number of owned properties (as verified
+  // with Object.prototype.hasOwnProperty.call), the same set of keys
+  // (although not necessarily the same order), equivalent values for every
+  // corresponding key, and an identical "prototype" property. Note: this
+  // accounts for both named and indexed properties on Arrays.
+  else {
+    return actual.prototype === expected.prototype &&
+           isEquivalent(actual, expected);
+  }
+}
+
+function isEquivalent(a, b, stack) {
+  return isArrayEquivalent(Object.keys(a).sort(),
+                           Object.keys(b).sort()) &&
+          Object.keys(a).every(function(key) {
+            return isDeepEqual(a[key], b[key], stack)
+          });
+}
+
+function isArrayEquivalent(a, b, stack) {
+  return utils.isArray(a) && utils.isArray(b) && a.length === b.length &&
+         a.every(function(value, index) {
+           return isDeepEqual(value, b[index]);
+         });
+}
diff --git a/logger.js b/logger.js
new file mode 100644
index 0000000..c647e69
--- /dev/null
+++ b/logger.js
@@ -0,0 +1,78 @@
+"use strict";
+
+var font = require("ansi-font/index")
+var toSource = require("./utils").source
+
+var INDENT = "  "
+
+var report = console.log.bind(console)
+
+function passed(message) {
+  return font.green("\u2713 " + message)
+}
+function failed(message) {
+  return font.red("\u2717 " + message)
+}
+function errored(message) {
+  return font.magenta("\u26A1 " + message)
+}
+
+function indent(message, indentation) {
+  indentation = undefined === indentation ? INDENT : indentation
+  message = message || ""
+  return message.replace(/^/gm, indentation)
+}
+
+function Logger(options) {
+  if (!(this instanceof Logger)) return new Logger(options)
+
+  options = options || {}
+  var print = options.print || report
+  var indentation = options.indentation || ""
+  var results = options.results || { passes: [], fails: [], errors: [] }
+  this.passes = results.passes
+  this.fails = results.fails
+  this.errors = results.errors
+  results = this
+
+
+  this.pass = function pass(message) {
+    results.passes.push(message)
+    print(indent(passed(message), indentation))
+  }
+
+  this.fail = function fail(error) {
+    results.fails.push(error)
+    var message = error.message
+    if ("expected" in error)
+      message += "\n  Expected: \n" + toSource(error.expected, INDENT)
+    if ("actual" in error)
+      message += "\n  Actual: \n" + toSource(error.actual, INDENT)
+    if ("operator" in error)
+      message += "\n  Operator: " + toSource(error.operator, INDENT)
+    print(indent(failed(message), indentation))
+  }
+
+  this.error = function error(exception) {
+    results.errors.push(exception)
+    print(indent(errored(exception.stack || exception), indentation))
+  }
+
+  this.section = function section(title) {
+    print(indent(title, indentation))
+    return new Logger({
+      print: print,
+      indentation: indent(indentation),
+      results: results
+    })
+  }
+
+  this.report = function report() {
+    print("Passed:" + results.passes.length +
+          " Failed:" + results.fails.length +
+          " Errors:" + results.errors.length)
+  }
+}
+
+Logger.Logger = Logger
+module.exports = Logger
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..4cc6086
--- /dev/null
+++ b/package.json
@@ -0,0 +1,48 @@
+{
+  "name": "test",
+  "version": "0.6.0",
+  "description": "(Un)CommonJS test runner.",
+  "keywords": [
+    "test",
+    "commonjs",
+    "uncommonjs",
+    "unit"
+  ],
+  "homepage": "https://github.com/Gozala/test-commonjs/",
+  "author": "Irakli Gozalishvili <rfobic at gmail.com> (http://jeditoolkit.com)",
+  "contributors": [
+    "Irakli Gozalishvili <rfobic at gmail.com> (http://jeditoolkit.com)",
+    "Kris Kowal <kris at cixar.com> (http://github.com/kriskowal/)",
+    "Zach Carter",
+    "Felix Geisendörfer",
+    "Karl Guertin",
+    "Ash Berlin",
+    "Francois Lafortune"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/Gozala/test-commonjs.git",
+    "web": "https//github.com/Gozala/test-commonjs"
+  },
+  "bugs": {
+    "url": "http://github.com/Gozala/test-commonjs/issues/"
+  },
+  "scripts": {
+    "test": "npm run test-node && npm run test-browser",
+    "test-browser": "node ./node_modules/phantomify/bin/cmd.js ./test/index.js",
+    "test-node": "node ./test/index.js"
+  },
+  "main": "./test.js",
+  "licenses": [
+    {
+      "type": "MIT",
+      "url": "https://github.com/Gozala/test-commonjs/License.md"
+    }
+  ],
+  "dependencies": {
+    "ansi-font": "0.0.2"
+  },
+  "devDependencies": {
+    "phantomify": "~0.x.0"
+  }
+}
diff --git a/test.js b/test.js
new file mode 100644
index 0000000..3a17e3c
--- /dev/null
+++ b/test.js
@@ -0,0 +1,93 @@
+"use strict";
+
+var Assert = require("./assert").Assert
+var Logger = require("./logger").Logger
+
+
+var ERR_COMPLETED_ASSERT = "Assert in completed test"
+var ERR_COMPLETED_COMPLETE = "Attemt to complete test more then one times"
+var ERR_EXPECT = "AssertionError"
+
+
+/**
+ * Creates a test function.
+ */
+function Test(name, unit, logger, Assert) {
+  var isSync = unit.length <= 1
+  var isFailFast = !unit.length
+  var isDone = false
+  return function test(next) {
+    logger = logger.section(name)
+    var assert = Assert(logger)
+    assert.end = function end() {
+      if (isDone) return logger.error(Error(ERR_COMPLETED_COMPLETE))
+      isDone = true
+      next()
+    }
+
+    try {
+      var result = unit(assert, assert.end)
+      // If it"s async test that returns a promise.
+      if (result && typeof(result.then) === "function") {
+        result.then(function passed() {
+          logger.pass("passed")
+          assert.end()
+        }, function failed(reason) {
+          logger.fail(reason)
+          assert.end()
+        })
+      } else {
+        if (isFailFast) logger.pass("passed")
+        if (isSync) assert.end()
+      }
+    } catch (exception) {
+      if (ERR_EXPECT === exception.name) assert.fail(exception)
+      else logger.error(exception)
+      assert.end()
+    }
+  }
+}
+
+function isTest(name) { return name.indexOf("test") === 0 }
+
+/**
+ * Creates a test suite / group. Calling returned function will execute
+ * all test in the given suite.
+ */
+function Suite(name, units, logger, Assert) {
+  // Collecting properties that represent test functions or suits.
+  var names = Object.keys(units).filter(isTest)
+  Assert = units.Assert || Assert
+  // Returning a function that executes all test in this suite and all it"s
+  // sub-suits.
+  return function suite(end) {
+    // Chaining test / suits so that each is executed after last is done.
+    function next() {
+      if (!names.length) return end()
+      var name = names.shift()
+      var unit = Unit(name, units[name], logger, units.Assert || Assert)
+      unit(next)
+    }
+    next((logger = logger.section(name)))
+  }
+}
+function Unit(name, units, logger, Assert) {
+  return typeof(units) === "function" ? Test(name, units, logger, Assert)
+                                      : Suite(name, units, logger, Assert)
+}
+
+
+/**
+ * Test runner function.
+ */
+exports.run = function run(units, logger) {
+  var exit = logger ? false : true
+  logger = logger || new Logger()
+  var unit = Unit("Running all tests:", units, logger, Assert)
+  unit(function done() {
+    logger.report()
+    var failed = logger.errors.length !== 0 || logger.fails.length !== 0
+    // Exit only if `process.exit` exist and if no logger was provided.
+    if (exit && process.exit) process.exit(failed ? 1 : 0)
+  })
+}
diff --git a/test/assert.js b/test/assert.js
new file mode 100644
index 0000000..6ec8f78
--- /dev/null
+++ b/test/assert.js
@@ -0,0 +1,132 @@
+"use strict";
+
+var run = require("../test").run
+var Logger = require("./utils/logger").Logger
+
+exports["test existence of all assert methods on assert"] = function (assert) {
+  var functionType, methods;
+  functionType = "function"
+  methods = ["ok", "equal", "notEqual", "deepEqual", "notDeepEqual", "throws"]
+  run({
+    "test fixture": function (assert) {
+      methods.forEach(function (name) {
+        assert.equal(typeof assert[name], functionType,
+                     "`" + name + "` must be method of `assert`")
+      })
+    }
+  }, new Logger(function(passes) {
+    assert.equal(passes.length, methods.length, "all methdos were found")
+  }))
+}
+
+exports["test correctness of `assert.ok`"] = function (assert) {
+  var valid, invalid, report
+  valid = [1, -9, true, ",.", {}, function () {}, ["1"], Infinity]
+  invalid = [null, undefined, false, "", 0, NaN]
+  report = null
+
+  run({
+    "test fixture": function (assert) {
+      valid.forEach(function (value, index) {
+        assert.ok(value, value + " is valid")
+      })
+
+      invalid.forEach(function (value, index) {
+        assert.ok(value, value + " is invalid")
+      })
+    }
+  }, Logger(function(passes, fails, errors) {
+    assert.equal(passes.length, valid.length,
+                 "Amount of passed test must match amount of valid inputs")
+    assert.equal(fails.length, invalid.length,
+                 "Amount of failed test must match amount of invalid inputs")
+    assert.equal(errors.length, 0, "Must be no errors")
+  }))
+}
+
+exports["test correctness of `assert.equal`"] = function (assert) {
+  var valid, invalid
+
+  valid = [
+    [1, 1],
+    [450, 450],
+    ["string", "" + "s" + "tring"],
+    [undefined,
+    {}.oops],
+    [null, null],
+    [String("test"), "test"],
+    [String("test"), String("test")],
+    [null, undefined],
+    [1, true],
+    [2 / 0, Infinity],
+    [JSON.stringify({
+      bla: 3
+    }), JSON.stringify({
+      bla: 3
+    })]
+  ]
+  invalid = [
+    [0, 4],
+    [0, null],
+    [undefined, 0],
+    [{}, {}],
+    [NaN, NaN], // wtfjs
+    [JSON.parse('{ "bla": 3 }'), JSON.parse('{ "bla": 3 }')]
+  ]
+
+  run({
+    "test fixture": function (assert) {
+      valid.forEach(function (value, index) {
+        var message = "`" + value[0] + "` is equal to `" + value[1] + "`"
+        assert.equal(value[0], value[1], message)
+      })
+
+      invalid.forEach(function (value, index) {
+        var message = "`" + value[0] + "` is not equal to `" + value[1] + "`"
+        assert.equal(value[0], value[1], message)
+      })
+    }
+  }, Logger(function(passes, fails, errors) {
+    assert.equal(passes.length, valid.length,
+                 "Amount of passed test must match amount of valid inputs")
+    assert.equal(fails.length, invalid.length,
+                 "Amount of failed test must match amount of invalid inputs")
+    assert.equal(errors.length, 0, "Must be no errors")
+  }))
+}
+
+exports["test correctness of `assert.deepEqual`"] = function (assert) {
+  var valid, invalid, report
+  valid = [
+    [ [], [] ],
+    [ {}, {} ],
+  ]
+  invalid = [
+    [ [], undefined ],
+    [ [], [1] ]
+  ]
+  report = null
+
+  run({
+    "test fixture": function (assert) {
+      valid.forEach(function (value, index) {
+        var message = "`" + value[0] + "` is deepEqual of `" + value[1] + "`"
+        assert.deepEqual(value[0], value[1], message)
+      })
+
+      invalid.forEach(function (value, index) {
+        var message = "`" + value[0] + "` is not deepEqual of `" + value[1] + "`"
+        assert.deepEqual(value[0], value[1], message)
+      })
+    }
+  }, Logger(function(passes, fails, errors) {
+    assert.equal(passes.length, valid.length,
+                 "Amount of passed test must match amount of valid inputs")
+    assert.equal(fails.length, invalid.length,
+                 "Amount of failed test must match amount of invalid inputs")
+    assert.equal(errors.length, 0, "Must be no errors")
+  }))
+}
+
+if (require.main === module)
+  require("../test").run(exports)
diff --git a/test/async.js b/test/async.js
new file mode 100644
index 0000000..6737302
--- /dev/null
+++ b/test/async.js
@@ -0,0 +1,74 @@
+"use strict";
+
+var run = require("../test").run
+var Logger = require("./utils/logger").Logger
+
+exports["test must call callback to complete it"] = function (assert, done) {
+
+    var isDone, isTimerCalled, report, completeInnerTest
+
+    isDone = isTimerCalled = false
+    report = null
+
+    run({
+      "test:must throw": function (assert, done) {
+        completeInnerTest = done
+        assert.equal(1, 1, "Must be equal")
+      }
+    }, Logger(function (passes, fails, errors) {
+      isDone = true
+      assert.equal(isTimerCalled, true, "timer should be called already")
+      assert.equal(passes.length, 1, "Must contain one pass")
+      assert.equal(fails.length, 0, "No fails")
+      assert.equal(errors.length, 0, "No errors")
+      done()
+    }))
+
+    setTimeout(function () {
+      assert.equal(isDone, false, "callback must not be called")
+      isTimerCalled = true
+      completeInnerTest()
+    }, 0)
+}
+
+exports["test multiple tests with timeout"] = function (assert, done) {
+  var tests = 0
+
+  run({
+    "test async": function (assert, done) {
+      tests ++
+      setTimeout(function () {
+        assert.ok(true)
+        assert.ok(false)
+        done()
+      }, 100)
+    },
+    "test throws": function (assert) {
+      tests ++
+      throw new Error("boom")
+    },
+    "test fail fast": function (assert) {
+      tests ++
+      // TODO: Find a better solution for browser.
+      //require("assert").ok(0)
+      assert.ok(0)
+    },
+    "ignore if does not starts with test": function () {
+      tests ++
+    },
+    "test sync pass": function (assert) {
+      tests ++
+      assert.equal(1, 2)
+      assert.equal(2, 2)
+    }
+  }, Logger(function (passes, fails, errors) {
+    assert.equal(tests, 4, "All test were executed")
+    assert.equal(passes.length, 2, "Must pass two tests")
+    assert.equal(fails.length, 3, "Must fail tree tests")
+    assert.equal(errors.length, 1, "Must report one error")
+    done()
+  }))
+}
+
+if (require.main === module)
+  require("../test").run(exports)
diff --git a/test/custom-asserts.js b/test/custom-asserts.js
new file mode 100644
index 0000000..0d74f0b
--- /dev/null
+++ b/test/custom-asserts.js
@@ -0,0 +1,48 @@
+"use strict";
+
+var AssertBase = require("../assert").Assert
+/**
+ * Generates custom assertion constructors that may be bundled with a test
+ * suite.
+ * @params {String}
+ *    names of assertion function to be added to the generated Assert.
+ */
+function Assert() {
+  var descriptorMap = {}
+  Array.prototype.forEach.call(arguments, function (name) {
+    descriptorMap[name] = {
+      value: function (message) {
+        this.pass(message)
+      }
+    }
+  })
+  return function Assert() {
+    return Object.create(AssertBase.apply(null, arguments), descriptorMap)
+  }
+}
+
+exports["test suite"] = {
+  Assert: Assert("foo"),
+  "test that custom assertor is passed to test function": function (assert) {
+    assert.ok("foo" in assert, "custom assertion function `foo` is defined")
+    assert.foo("custom assertion function `foo` is called")
+  },
+  "test sub suite": {
+    "test that `Assert` is inherited by sub suits": function (assert) {
+      assert.ok("foo" in assert, "assertion function `foo` is defined")
+    },
+    "test sub sub suite": {
+      Assert: Assert("bar"),
+      "test that custom assertor is passed to test function": function (assert) {
+        assert.ok("bar" in assert, "custom assertion function `bar` is defined")
+        assert.bar("custom assertion function `bar` is called")
+      },
+      "test that `Assert` is not inherited by sub sub suits": function (assert) {
+        assert.ok(!("foo" in assert), "assertion function `foo` is not defined")
+      }
+    }
+  }
+}
+
+if (require.main === module)
+  require("../test").run(exports)
diff --git a/test/fail-fast.js b/test/fail-fast.js
new file mode 100644
index 0000000..b3e50fe
--- /dev/null
+++ b/test/fail-fast.js
@@ -0,0 +1,71 @@
+"use strict";
+
+var _assert = require("assert")
+var run = require("../test").run
+var Logger = require("./utils/logger").Logger
+
+
+
+exports["test that passes"] = function (assert) {
+    run({
+      "test fixture": function () {
+        _assert.equal(1, 1, "Must be equal")
+      }
+    }, Logger(function (passes, fails, errors) {
+      assert.equal(passes.length, 1, "Must pass one test")
+      assert.equal(fails.length, 0, "Must not fail any test")
+      assert.equal(errors.length, 0, "Must not contain any errors")
+    }))
+}
+
+exports["test that fails"] = function (assert) {
+  run({
+    "test fixture": function () {
+      _assert.equal(1, 2, "Must be two")
+    }
+  }, Logger(function (passes, fails, errors) {
+    assert.equal(passes.length, 0, "Must not pass any test")
+    assert.equal(fails.length, 1, "Must fail one test")
+    assert.equal(errors.length, 0, "Must not contain any errors")
+  }))
+}
+
+exports["test that throws error"] = function (assert) {
+  run({
+    "test fixture": function () {
+      throw new Error("Boom!!")
+    }
+  }, Logger(function (passes, fails, errors) {
+    assert.equal(passes.length, 0, "Must not pass any test")
+    assert.equal(fails.length, 0, "Must not fail any test")
+    assert.equal(errors.length, 1, "Must contain one error")
+  }))
+}
+
+exports["test that passes one assert and fails fast"] = function (assert) {
+  run({
+    "test fixture": function (assert) {
+      assert.equal(1, 1, "Must be equal")
+      _assert.equal(1, 2, "Must fail test")
+    }
+  }, Logger(function (passes, fails, errors) {
+    assert.equal(passes.length, 1, "Must pass one test")
+    assert.equal(fails.length, 1, "Must fail one test")
+    assert.equal(errors.length, 0, "Must not contain any errors")
+  }))
+}
+
+exports["test async with fast fail"] = function (assert) {
+  run({
+    "test:must throw": function (assert, done) {
+      throw new Error("Boom!!")
+    }
+  }, Logger(function (passes, fails, errors) {
+    assert.equal(passes.length, 0, "Must not pass any test")
+    assert.equal(fails.length, 0, "Must not fail any test")
+    assert.equal(errors.length, 1, "Must contain one error")
+  }))
+}
+
+if (require.main === module)
+  require("../test").run(exports)
diff --git a/test/index.js b/test/index.js
new file mode 100644
index 0000000..c9e7a84
--- /dev/null
+++ b/test/index.js
@@ -0,0 +1,8 @@
+"use strict";
+
+exports["test fail fast"] = require("./fail-fast")
+exports["test async"] = require("./async")
+exports["test assertions"] = require("./assert")
+exports["test custom `Assert`'s"] = require("./custom-asserts")
+
+require("../test").run(exports)
diff --git a/test/utils/logger.js b/test/utils/logger.js
new file mode 100644
index 0000000..005491f
--- /dev/null
+++ b/test/utils/logger.js
@@ -0,0 +1,23 @@
+exports.Logger = function Logger(callback) {
+  if (!(this instanceof Logger)) return new Logger(callback)
+  this.passes = []
+  this.fails = []
+  this.errors = []
+  this.pass = function (message) {
+    this.passes.push(message)
+  }
+  this.fail = function fail(assertion) {
+    this.fails.push(assertion)
+  }
+  this.error = function error(exception) {
+    this.errors.push(exception)
+  }
+  this.section = function section() {
+    return this
+  }
+  this.report = function report() {
+    if (callback)
+      callback(this.passes, this.fails, this.errors)
+  }
+  return this
+}
diff --git a/utils.js b/utils.js
new file mode 100644
index 0000000..ceeef93
--- /dev/null
+++ b/utils.js
@@ -0,0 +1,336 @@
+"use strict";
+
+/**
+ * Returns `true` if `value` is `undefined`.
+ * @examples
+ *    var foo; isUndefined(foo); // true
+ *    isUndefined(0); // false
+ */
+function isUndefined(value) {
+  return value === undefined;
+}
+exports.isUndefined = isUndefined;
+
+/**
+ * Returns `true` if value is `null`.
+ * @examples
+ *    isNull(null); // true
+ *    isNull(undefined); // false
+ */
+function isNull(value) {
+  return value === null;
+}
+exports.isNull = isNull;
+
+/**
+ * Returns `true` if value is a string.
+ * @examples
+ *    isString("moe"); // true
+ */
+function isString(value) {
+  return typeof value === "string";
+}
+exports.isString = isString;
+
+/**
+ * Returns `true` if `value` is a number.
+ * @examples
+ *    isNumber(8.4 * 5); // true
+ */
+function isNumber(value) {
+  return typeof value === "number";
+}
+exports.isNumber = isNumber;
+
+/**
+ * Returns `true` if `value` is a `RegExp`.
+ * @examples
+ *    isRegExp(/moe/); // true
+ */
+function isRegExp(value) {
+  return instanceOf(value, RegExp);
+}
+exports.isRegExp = isRegExp;
+
+/**
+ * Returns true if `value` is a `Date`.
+ * @examples
+ *    isDate(new Date()); // true
+ */
+function isDate(value) {
+  return isObject(value) && instanceOf(value, Date);
+}
+exports.isDate = isDate;
+
+/**
+ * Returns true if object is a Function.
+ * @examples
+ *    isFunction(function foo(){}) // true
+ */
+function isFunction(value) {
+    return typeof value === "function" && value.call && value.apply;
+}
+exports.isFunction = isFunction;
+
+/**
+ * Returns `true` if `value` is an object (please note that `null` is considered
+ * to be an atom and not an object).
+ * @examples
+ *    isObject({}) // true
+ *    isObject(null) // false
+ */
+function isObject(value) {
+    return typeof value === "object" && value !== null;
+}
+exports.isObject = isObject;
+
+/**
+ * Returns true if `value` is an Array.
+ * @examples
+ *    isArray([1, 2, 3])  // true
+ *    isArray({ 0: "foo", length: 1 }) // false
+ */
+var isArray = Array.isArray || function isArray(value) {
+  Object.prototype.toString.call(value) === "[object Array]";
+}
+exports.isArray = isArray;
+
+/**
+ * Returns `true` if `value` is an Arguments object.
+ * @examples
+ *    (function(){ return isArguments(arguments); })(1, 2, 3); // true
+ *    isArguments([1,2,3]); // false
+ */
+function isArguments(value) {
+  Object.prototype.toString.call(value) === "[object Arguments]";
+}
+exports.isArguments = isArguments;
+
+/**
+ * Returns true if it is a primitive `value`. (null, undefined, number,
+ * boolean, string)
+ * @examples
+ *    isPrimitive(3) // true
+ *    isPrimitive("foo") // true
+ *    isPrimitive({ bar: 3 }) // false
+ */
+function isPrimitive(value) {
+  return !isFunction(value) && !isObject(value);
+}
+exports.isPrimitive = isPrimitive;
+
+/**
+ * Returns `true` if given `object` is flat (it is direct decedent of
+ * `Object.prototype` or `null`).
+ * @examples
+ *    isFlat({}) // true
+ *    isFlat(new Type()) // false
+ */
+function isFlat(object) {
+  return isObject(object) && (isNull(Object.getPrototypeOf(object)) ||
+                              isNull(Object.getPrototypeOf(
+                                     Object.getPrototypeOf(object))));
+}
+exports.isFlat = isFlat;
+
+/**
+ * Returns `true` if object contains no values.
+ */
+function isEmpty(object) {
+  if (isObject(object)) {
+    for (var key in object)
+      return false;
+    return true;
+  }
+  return false;
+}
+exports.isEmpty = isEmpty;
+
+/**
+ * Returns `true` if `value` is an array / flat object containing only atomic
+ * values and other flat objects.
+ */
+function isJSON(value, visited) {
+    // Adding value to array of visited values.
+    (visited || (visited = [])).push(value);
+            // If `value` is an atom return `true` cause it"s valid JSON.
+    return  isPrimitive(value) ||
+            // If `value` is an array of JSON values that has not been visited
+            // yet.
+            (isArray(value) &&  value.every(function(element) {
+                                  return isJSON(element, visited);
+                                })) ||
+            // If `value` is a plain object containing properties with a JSON
+            // values it"s a valid JSON.
+            (isFlat(value) && Object.keys(value).every(function(key) {
+                var $ = Object.getOwnPropertyDescriptor(value, key);
+                // Check every proprety of a plain object to verify that
+                // it"s neither getter nor setter, but a JSON value, that
+                // has not been visited yet.
+                return  ((!isObject($.value) || !~visited.indexOf($.value)) &&
+                        !("get" in $) && !("set" in $) &&
+                        isJSON($.value, visited));
+            }));
+}
+exports.isJSON = function (value) {
+  return isJSON(value);
+};
+
+/**
+ * Returns if `value` is an instance of a given `Type`. This is exactly same as
+ * `value instanceof Type` with a difference that `Type` can be from a scope
+ * that has a different top level object. (Like in case where `Type` is a
+ * function from different iframe / jetpack module / sandbox).
+ */
+function instanceOf(value, Type) {
+  var isConstructorNameSame;
+  var isConstructorSourceSame;
+
+  // If `instanceof` returned `true` we know result right away.
+  var isInstanceOf = value instanceof Type;
+
+  // If `instanceof` returned `false` we do ducktype check since `Type` may be
+  // from a different sandbox. If a constructor of the `value` or a constructor
+  // of the value"s prototype has same name and source we assume that it"s an
+  // instance of the Type.
+  if (!isInstanceOf && value) {
+    isConstructorNameSame = value.constructor.name === Type.name;
+    isConstructorSourceSame = String(value.constructor) == String(Type);
+    isInstanceOf = (isConstructorNameSame && isConstructorSourceSame) ||
+                    instanceOf(Object.getPrototypeOf(value), Type);
+  }
+  return isInstanceOf;
+}
+exports.instanceOf = instanceOf;
+
+/**
+ * Function returns textual representation of a value passed to it. Function
+ * takes additional `indent` argument that is used for indentation. Also
+ * optional `limit` argument may be passed to limit amount of detail returned.
+ * @param {Object} value
+ * @param {String} [indent="    "]
+ * @param {Number} [limit]
+ */
+function source(value, indent, limit, offset, visited) {
+  var result;
+  var names;
+  var nestingIndex;
+  var isCompact = !isUndefined(limit);
+
+  indent = indent || "    ";
+  offset = (offset || "");
+  result = "";
+  visited = visited || [];
+
+  if (isUndefined(value)) {
+    result += "undefined";
+  }
+  else if (isNull(value)) {
+    result += "null";
+  }
+  else if (isString(value)) {
+    result += "\"" + value + "\"";
+  }
+  else if (isFunction(value)) {
+    value = String(value).split("\n");
+    if (isCompact && value.length > 2) {
+      value = value.splice(0, 2);
+      value.push("...}");
+    }
+    result += value.join("\n" + offset);
+  }
+  else if (isArray(value)) {
+    if ((nestingIndex = (visited.indexOf(value) + 1))) {
+      result = "#" + nestingIndex + "#";
+    }
+    else {
+      visited.push(value);
+
+      if (isCompact)
+        value = value.slice(0, limit);
+
+      result += "[\n";
+      result += value.map(function(value) {
+        return offset + indent + source(value, indent, limit, offset + indent,
+                                        visited);
+      }).join(",\n");
+      result += isCompact && value.length > limit ?
+                ",\n" + offset + "...]" : "\n" + offset + "]";
+    }
+  }
+  else if (isObject(value)) {
+    if ((nestingIndex = (visited.indexOf(value) + 1))) {
+      result = "#" + nestingIndex + "#"
+    }
+    else {
+      visited.push(value)
+
+      names = Object.keys(value);
+
+      result += "{ // " + value + "\n";
+      result += (isCompact ? names.slice(0, limit) : names).map(function(name) {
+        var _limit = isCompact ? limit - 1 : limit;
+        var descriptor = Object.getOwnPropertyDescriptor(value, name);
+        var result = offset + indent + "// ";
+        var accessor;
+        if (0 <= name.indexOf(" "))
+          name = "\"" + name + "\"";
+
+        if (descriptor.writable)
+          result += "writable ";
+        if (descriptor.configurable)
+          result += "configurable ";
+        if (descriptor.enumerable)
+          result += "enumerable ";
+
+        result += "\n";
+        if ("value" in descriptor) {
+          result += offset + indent + name + ": ";
+          result += source(descriptor.value, indent, _limit, indent + offset,
+                           visited);
+        }
+        else {
+
+          if (descriptor.get) {
+            result += offset + indent + "get " + name + " ";
+            accessor = source(descriptor.get, indent, _limit, indent + offset,
+                              visited);
+            result += accessor.substr(accessor.indexOf("{"));
+          }
+
+          if (descriptor.set) {
+            if (descriptor.get) result += ",\n";
+            result += offset + indent + "set " + name + " ";
+            accessor = source(descriptor.set, indent, _limit, indent + offset,
+                              visited);
+            result += accessor.substr(accessor.indexOf("{"));
+          }
+        }
+        return result;
+      }).join(",\n");
+
+      if (isCompact) {
+        if (names.length > limit && limit > 0) {
+          result += ",\n" + offset  + indent + "//...";
+        }
+      }
+      else {
+        if (names.length)
+          result += ",";
+
+        result += "\n" + offset + indent + "\"__proto__\": ";
+        result += source(Object.getPrototypeOf(value), indent, 0,
+                         offset + indent);
+      }
+
+      result += "\n" + offset + "}";
+    }
+  }
+  else {
+    result += String(value);
+  }
+  return result;
+}
+exports.source = function (value, indentation, limit) {
+  return source(value, indentation, limit);
+};

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



More information about the Pkg-javascript-commits mailing list