Skip to content

Commit

Permalink
Added assert.js (and its dependency, narwhal/util.js). Not sure how p…
Browse files Browse the repository at this point in the history
…ermanent this solution is, but we need to run CommonJS tests.
  • Loading branch information
yrashk committed Dec 23, 2010
1 parent 717484b commit 5cb7673
Show file tree
Hide file tree
Showing 3 changed files with 1,457 additions and 0 deletions.
3 changes: 3 additions & 0 deletions Makefile
Expand Up @@ -12,6 +12,9 @@ dependencies: deps/erlv8/ebin/erlv8.beam
test: compile
@./rebar eunit

test-commonjs: compile
@./beamjs -norepl -jspath lib -load deps/commonjs/tests/unit-testing/1.0/program.js

compile: dependencies
@./rebar compile
@cat ebin/beamjs.app | sed s/%sha%/`git log -1 --pretty=format:%h`/ > ebin/beamjs.app
323 changes: 323 additions & 0 deletions lib/assert.js
@@ -0,0 +1,323 @@
// Originally from narwhal
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0

// -- zaach Zachary Carter
// -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
// original skeleton
// -- felixge Felix Geisendörfer
// editions backported from NodeJS
// -- Karl Guertin
// editions backported from NodeJS
// -- ashb Ash Berlin
// contributions annotated

var util = require("narwhal/util");
var sys = require('sys');

// 1. The assert module provides functions that throw
// AssertionError's when particular conditions are not met. The
// assert module must conform to the following interface.

var assert = exports;

// 2. The AssertionError is defined in assert.
// new assert.AssertionError({message: message, actual: actual, expected: expected})

assert.AssertionError = function (options) {
if (typeof options == "string")
options = {"message": options};
this.name = "AssertionError";
this.message = options.message;
this.actual = options.actual;
this.expected = options.expected;
this.operator = options.operator;

// V8 specific
if (Error.captureStackTrace) {
Error.captureStackTrace(this, (this.fail || assert.fail));
// Node specific, removes the node machinery stack frames
// XXX __filename will probably not always be the best way to detect Node
if (typeof __filename !== undefined) {
var stack = this.stack.split("\n");
for (var i = stack.length - 1; i >= 0; i--) {
if (stack[i].indexOf(__filename) != -1) {
this.stack = stack.slice(0, i + 2).join("\n");
break;
}
}
}
}

};

// XXX extension
// Ash Berlin
assert.AssertionError.prototype.toString = function (){
if (this.message) {
return [
this.name + ":",
this.message
].join(" ");
} else {
return [
this.name + ":",
sys.inspect(this.expected),
this.operator,
sys.inspect(this.actual)
].join(" ");
}
}

// XXX extension
// Ash Berlin
assert.AssertionError.prototype.toSource = function () {
return "new (require('assert').AssertionError)(" + Object.prototype.toSource.call(this) + ")";
};

// assert.AssertionError instanceof Error

assert.AssertionError.prototype = Object.create(Error.prototype);

// At present only the three keys mentioned above are used and
// understood by the spec. Implementations or sub modules can pass
// other keys to the AssertionError's constructor - they will be
// ignored.

// 3. All of the following functions must throw an AssertionError
// when a corresponding condition is not met, with a message that
// may be undefined if not provided. All assertion methods provide
// both the actual and expected values to the assertion error for
// display purposes.

assert.fail = function (options) {
throw new assert.AssertionError(options);
};

// XXX extension
// stub for logger protocol
assert.pass = function () {
};

// XXX extension
// stub for logger protocol
assert.error = function () {
};

// XXX extension
// stub for logger protocol
assert.section = function () {
return this;
};

// 4. Pure assertion tests whether a value is truthy, as determined
// by !!guard.
// assert.ok(guard, message_opt);
// This statement is equivalent to assert.equal(true, guard,
// message_opt);. To test strictly for the value true, use
// assert.strictEqual(true, guard, message_opt);.

assert.ok = function (value, message) {
if (!!!value)
(this.fail || assert.fail)({
"actual": value,
"expected": true,
"message": message,
"operator": "=="
});
else
(this.pass || assert.pass)(message);
};

// 5. The equality assertion tests shallow, coercive equality with
// ==.
// assert.equal(actual, expected, message_opt);

assert.equal = function (actual, expected, message) {
if (actual != expected)
(this.fail || assert.fail)({
"actual": actual,
"expected": expected,
"message": message,
"operator": "=="
});
else
(this.pass || assert.pass)(message);
};


// 6. The non-equality assertion tests for whether two objects are not equal
// with != assert.notEqual(actual, expected, message_opt);

assert.notEqual = function (actual, expected, message) {
if (actual == expected)
(this.fail || assert.fail)({
"actual": actual,
"expected": expected,
"message": message,
"operator": "!="
});
else
(this.pass || assert.pass)(message);
};

// 7. The equivalence assertion tests a deep equality relation.
// assert.deepEqual(actual, expected, message_opt);

assert.deepEqual = function (actual, expected, message) {
if (!deepEqual(actual, expected))
(this.fail || assert.fail)({
"actual": actual,
"expected": expected,
"message": message,
"operator": "deepEqual"
});
else
(this.pass || assert.pass)(message);
};

function deepEqual(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 (actual instanceof Date && expected instanceof Date) {
return actual.getTime() === expected.getTime();

// 7.3. Other pairs that do not both pass typeof value == "object",
// equivalence is determined by ==.
} else if (typeof actual != 'object' && typeof expected != 'object') {
return actual == expected;

// XXX specification bug: this should be specified
} else if (typeof expected == "string" || typeof actual == "string") {
return expected === actual;

// 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 && objEquiv(actual, expected);
}
}

function objEquiv(a, b, stack) {
return (
!util.no(a) && !util.no(b) &&
arrayEquiv(
util.sort(util.object.keys(a)),
util.sort(util.object.keys(b))
) &&
util.object.keys(a).every(function (key) {
return deepEqual(a[key], b[key], stack);
})
);
}

function arrayEquiv(a, b, stack) {
return util.isArrayLike(b) &&
a.length == b.length &&
util.zip(a, b).every(util.apply(function (a, b) {
return deepEqual(a, b, stack);
}));
}

// 8. The non-equivalence assertion tests for any deep inequality.
// assert.notDeepEqual(actual, expected, message_opt);

assert.notDeepEqual = function (actual, expected, message) {
if (deepEqual(actual, expected))
(this.fail || assert.fail)({
"actual": actual,
"expected": expected,
"message": message,
"operator": "notDeepEqual"
});
else
(this.pass || assert.pass)(message);
};

// 9. The strict equality assertion tests strict equality, as determined by ===.
// assert.strictEqual(actual, expected, message_opt);

assert.strictEqual = function (actual, expected, message) {
if (actual !== expected)
(this.fail || assert.fail)({
"actual": actual,
"expected": expected,
"message": message,
"operator": "==="
});
else
(this.pass || assert.pass)(message);
};

// 10. The strict non-equality assertion tests for strict inequality, as determined by !==.
// assert.notStrictEqual(actual, expected, message_opt);

assert.notStrictEqual = function (actual, expected, message) {
if (actual === expected)
(this.fail || assert.fail)({
"actual": actual,
"expected": expected,
"message": message,
"operator": "!=="
});
else
(this.pass || assert.pass)(message);
};

// 11. Expected to throw an error:
// assert.throws(block, Error_opt, message_opt);

assert["throws"] = function (block, Error, message) {
var threw = false,
exception = null;

// (block)
// (block, message:String)
// (block, Error)
// (block, Error, message)

if (typeof Error == "string") {
message = Error;
Error = undefined;
}

try {
block();
} catch (e) {
threw = true;
exception = e;
}

if (!threw) {
(this.fail || assert.fail)({
"message": message,
"operator": "throw"
});
} else if (Error) {
if (exception instanceof Error)
(this.pass || assert.pass)(message);
else
throw exception;
} else {
(this.pass || assert.pass)(message);
}

};

// XXX extension
assert.Assert = function (log) {
var self = Object.create(assert);
self.pass = log.pass.bind(log);
self.fail = log.fail.bind(log);
self.error = log.error.bind(log);
self.section = log.section.bind(log);
return self;
};

0 comments on commit 5cb7673

Please sign in to comment.