[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