/** *
0
*/
resetAssertCount: function () {
return (_assertCount = 0);
},
/**
* @function
*/
AssertionError: _AssertionError,
/**
* Asserts that a condition converts to true. If it does not, it throws
* an {@link #AssertionError} with a default message.
*
* @param {string|any} x
* If a string, it is evaluated as a Program; the assertion
* fails if its result, type-converted to boolean, is
* false
.
* If not a string, the value is type-converted to boolean;
* the assertion fails if the result of the conversion is
* false
.
* @throws
* {@link #AssertionError} if the assertion fails and this exception
* can be thrown.
* @return {boolean}
* false
, if the assertion fails and no exception can be thrown;
* true
, if the assertion is met.
* @see Global#eval(String)
*/
assert: function (x) {
_increaseAssertCount();
var origX = x;
if (typeof x == "string")
{
/*jshint -W061*/
x = eval(x);
}
if (!x)
{
return _throwThis(jsx.test.AssertionError,
'"assert("' + (typeof origX == "string" ? origX : "...") + '");"');
}
return !!x;
},
/**
* Asserts that a condition is boolean true
. If it isn't,
* it throws an {@link #AssertionError} with a default message.
*
* @param {string|any} x
* If a string, it is evaluated as a Program; the assertion
* fails if its result, type-converted to boolean, is
* false
.
* If not a string, the value is type-converted to boolean;
* the assertion fails if the result of the conversion is
* false
.
* @throws
* {@link #AssertionError} if the assertion fails and this exception
* can be thrown.
* @return {boolean}
* false
, if the assertion fails and no exception can be thrown;
* true
, if the assertion is met.
* @see Global#eval(String)
*/
assertTrue: function (x) {
_increaseAssertCount();
var origX = x;
if (typeof x == "string")
{
/*jshint -W061*/
x = eval(x);
}
if (typeof x != "boolean" || !x)
{
return _throwThis(_AssertionError,
"assertTrue(" + (typeof origX == "string" ? origX : "...") + ");");
}
return !!x;
},
/**
* Asserts that a condition is false. If it isn't, it throws
* an {@link #AssertionError} with a default message.
*
* @param {string|any} x
* If a string, it is evaluated as a Program; the assertion
* fails if its result, type-converted to boolean, is
* true
.
* If not a string, the value is type-converted to boolean;
* the assertion fails if the result of the conversion is
* true
.
* @param {boolean} bThrow = true
* If true
(default), an exception will be thrown if
* the assertion fails, otherwise a warning will be issued to the
* error console in that case.
* @param {String} sContext (optional)
* Description of the context in which the assertion was made.
* Ignored if bThrow == true
.
* @throws
* {@link #AssertionError} if the assertion fails and this exception
* can be thrown.
* @return {boolean}
* false
, if the assertion fails and no exception can be thrown;
* true
, if the assertion is met.
* @see Global#eval(String)
*/
assertFalse: function (x, bThrow, sContext) {
_increaseAssertCount();
var origX = x;
if (typeof x == "string")
{
/*jshint -W061*/
x = eval(x);
}
if (typeof x != "boolean" || x)
{
if (typeof bThrow == "undefined" || bThrow)
{
return _throwThis(_AssertionError,
"assertFalse(" + (typeof origX == "string" ? origX : "...") + ");");
}
jsx.dmsg((sContext ? sContext + ": " : "") + "Assertion failed: "
+ (typeof origX == "string" ? origX : "Value") + " must be false.", "warn");
}
return !!x;
},
/**
* Asserts that a condition is undefined
. If it isn't, it throws
* an {@link #AssertionError} with a default message.
*
* @param {string|any} x
* If a string, it is evaluated as a Program; the assertion
* fails if its result, type-converted to boolean, is
* true
.
* If not a string, the value is type-converted to boolean;
* the assertion fails if the result of the conversion is
* true
.
* @param {boolean} bThrow = true
* If true
(default), an exception will be thrown if
* the assertion fails, otherwise a warning will be issued to the
* error console in that case.
* @param {String} sContext (optional)
* Description of the context in which the assertion was made.
* Ignored if bThrow == true
.
* @throws
* {@link #AssertionError} if the assertion fails and this exception
* can be thrown.
* @return {boolean}
* false
, if the assertion fails and no exception can be thrown;
* true
, if the assertion is met.
* @see Global#eval(String)
*/
assertUndefined: function (x, bThrow, sContext) {
_increaseAssertCount();
var origX = x;
if (typeof x == "string")
{
/*jshint -W061*/
x = eval(x);
}
if (typeof x != "undefined")
{
if (typeof bThrow == "undefined" || bThrow)
{
return _throwThis(_AssertionError,
"assertUndefined(" + (typeof origX == "string" ? origX : "...") + ");");
}
jsx.warn((sContext ? sContext + ": " : "") + "Assertion failed: "
+ (typeof origX == "string" ? origX : "Value") + " must be undefined.");
}
return !!x;
},
/**
* Asserts that two arrays are equal. If they are not,
* an {@link #AssertionError} is thrown with a default message.
* Two arrays are considered equal only if their elements are
* strictly equal (shallow or deep strict comparison).
*
* @function
* @throws
* {@link #ArrayComparisonFailure}
* if either of the given values is not a reference to an
* {@link Array}.
* @throws
* {@link #AssertionError}
* if the assertion fails and either exception can be thrown.
* @see Global#eval()
*/
assertArrayEquals: (function () {
function _thrower (expecteds, actuals)
{
return _throwThis(_AssertionError,
"assertArrayEquals([" + expecteds + "], [" + actuals + "])");
}
/**
* @param {string|Array} expecteds
* Expected value; if a string, it is evaluated as a Program.
* @param {string|Array} actuals
* Actual value; if a string, it is evaluated as a Program.
* @param {number} depth
* If undefined
(default), shallow comparison
* is performed. If not 0
, deep comparison
* is performed: if less than 0
, there is
* no limit as to the depth of the comparison; if greater
* than 0
, items are compared down to the
* specified depth.
* @param {boolean} recursive
* Used internally to detect recursive assertions
* @return {boolean}
* false
, if comparison is not possible
* or the assertion fails, and no exception can be thrown;
* true
, if the assertion is met.
*/
return (
function jsx_test_assertArrayEquals (expecteds, actuals, depth, recursive) {
if (!recursive)
{
_increaseAssertCount();
}
if (typeof expecteds == "string")
{
/*jshint -W061*/
expecteds = eval(expecteds);
}
if (typeof actuals == "string")
{
actuals = eval(actuals);
}
if (typeof expecteds == typeof actuals
&& expecteds == null && actuals == null)
{
return true;
}
if (!_isArray(expecteds) || !_isArray(actuals))
{
return _throwThis(_ArrayComparisonFailure);
}
var len = expecteds.length;
var len2 = actuals.length;
if (len != len2)
{
return _thrower(expecteds, actuals);
}
for (var i = len; i--;)
{
recursive = (typeof depth == "number" && depth != 0);
var expected = expecteds[i];
var actual = actuals[i];
if (recursive && _isArray(expected) && _isArray(actual))
{
var new_level = ((depth < 0) ? depth : (depth - 1));
jsx_test_assertArrayEquals(expected, actual, new_level, true);
}
else if (expected !== actual)
{
return _thrower(expecteds, actuals);
}
}
return true;
}
);
}()),
/**
* Asserts that two objects are equal. If they are not,
* an {@link #AssertionError} is thrown with a default message.
* Two objects are considered equal only if their keys are
* strictly equal (shallow strict comparison).
*
* @function
* @throws
* {@link #ObjectComparisonFailure}
* if either of the given values is not a reference to an
* object.
* @throws
* {@link #AssertionError}
* if the assertion fails and either exception can be thrown.
* @see Global#eval()
*/
assertObjectEquals: (function () {
function _thrower (expecteds, actuals)
{
return _throwThis(_AssertionError,
"assertObjectEquals(" + expecteds + ", " + actuals + ")");
}
/**
* @param {string|Object} expecteds
* Expected value; if a string, it is evaluated as a Program.
* @param {string|Object} actuals
* Actual value; if a string, it is evaluated as a Program.
* @return {boolean}
* false
, if comparison is not possible
* or the assertion fails, and no exception can be thrown;
* true
, if the assertion is met.
*/
return function (expecteds, actuals) {
_increaseAssertCount();
if (typeof expecteds == "string")
{
/*jshint -W061*/
expecteds = eval(expecteds);
}
if (typeof actuals == "string")
{
actuals = eval(actuals);
}
if (typeof expecteds == typeof actuals
&& expecteds == null && actuals == null)
{
return true;
}
if (!_isObject(expecteds) || !_isObject(actuals))
{
return _throwThis(_ObjectComparisonFailure);
}
var keys = jsx.object.getKeys(expecteds);
for (var i = keys.length; i--;)
{
var key = keys[i];
if (expecteds[key] !== actuals[key])
{
return _thrower(expecteds, actuals);
}
}
keys = jsx.object.getKeys(actuals);
for (i = keys.length; i--;)
{
key = keys[i];
if (expecteds[key] !== actuals[key])
{
return _thrower(expecteds, actuals);
}
}
return true;
};
}()),
runner: {
tests: [],
_table: null,
/**
* @protected
*/
_appendTable: function () {
if (typeof document != "object" || !document)
{
return;
}
if (!document.body)
{
this._printMsg(
"No document.body found (at this point)."
+ " Use {updateDocument: false} if not in HTML context,"
+ " or wait until document.body exists (`load' event).",
"warn");
return;
}
var id = "test-results" + new Date().getTime();
var context = "table#" + id;
var style = document.createElement("style");
style.type = "text/css";
var styleText =
context + " { border: 2px solid black;"
+ " border-collapse: collapse; }"
+ context + " thead { border-bottom: 2px solid black; }"
+ context + " thead th { vertical-align: baseline; }"
+ context + " tfoot { border-top: 2px solid black; }"
+ context + " thead th { text-align: left; }"
+ context + " thead th:first-child { text-align: right; }"
+ context + " tbody th { text-align: right; border-top: 1px solid black; }"
+ context + " tbody td { border-top: 1px solid black; }"
+ context + " tbody td.info {"
+ " background-color: green; color: white; }"
+ context + " tbody td.error {"
+ " background-color: red;"
+ " color: white; font-family: monospace; }"
+ context + " thead th,"
+ context + " tbody th,"
+ context + " tbody td,"
+ context + " tfoot td {"
+ " padding: 0 0.5em;"
+ " vertical-align: top;"
+ " vertical-align: baseline; }";
if (typeof style.styleSheet != "undefined")
{
/* Older MSHTML */
style.styleSheet.cssText = styleText;
}
else
{
style.appendChild(document.createTextNode(styleText));
}
(document.head || document.getElementsByTagName("head")[0]).appendChild(style);
var table = document.createElement("table");
table.id = id;
this._table = table;
var thead = document.createElement("thead");
var tr = document.createElement("tr");
var th = document.createElement("th");
th.appendChild(document.createTextNode("#"));
tr.appendChild(th);
th = document.createElement("th");
th.appendChild(document.createTextNode("Source File"));
tr.appendChild(th);
th = document.createElement("th");
th.appendChild(document.createTextNode("Feature"));
tr.appendChild(th);
th = document.createElement("th");
th.appendChild(document.createTextNode("Testcase Description"));
tr.appendChild(th);
th = document.createElement("th");
th.appendChild(document.createTextNode("Result"));
tr.appendChild(th);
thead.appendChild(tr);
table.insertBefore(thead, table.firstChild);
var tbody = document.createElement("tbody");
table.appendChild(tbody);
var tests = this._tests;
for (var i = 0, len = tests.length; i < len; ++i)
{
var test = tests[i];
var number = i + 1;
var file = this._file;
var feature = this._feature;
var description = "";
if (test && typeof test != "function")
{
if (test.file)
{
file = test.file;
}
if (test.feature)
{
feature = test.feature;
}
description = test.description || test.desc || test.name;
test = test.code;
}
this._appendRow(number, file, feature, description);
}
document.body.appendChild(table);
},
/**
* @protected
* @param {String} text
*/
_htmlEscape: function (text) {
return text.replace(/&/g, "&").replace(//g, ">").replace(/ /g, " ");
},
/**
* @protected
* @param {int} num
* @param {string} file
* @param {string} feature
* @param {string} desc
*/
_appendRow: function (num, file, feature, desc) {
var table = this._table;
if (!table)
{
return;
}
var tbody = table.tBodies[0];
var tr = document.createElement("tr");
var th = document.createElement("th");
th.appendChild(document.createTextNode(num));
tr.appendChild(th);
var td = document.createElement("td");
if (file)
{
var tt = document.createElement("tt");
tt.appendChild(document.createTextNode(this._htmlEscape(file)));
td.appendChild(tt);
}
tr.appendChild(td);
td = document.createElement("td");
if (feature)
{
var code = document.createElement("code");
code.appendChild(document.createTextNode(this._htmlEscape(feature)));
td.appendChild(code);
}
tr.appendChild(td);
td = document.createElement("td");
if (desc)
{
td.innerHTML = desc;
}
tr.appendChild(td);
td = document.createElement("td");
td.id = table.id + "-" + num;
td.innerHTML = "testing…";
tr.appendChild(td);
tbody.appendChild(tr);
},
/**
* Updates a result cell
*
* @protected
* @param {int} rowNum
* Row number
* @param {string} result
* @param {string} msgType
*/
_updateResult: function (rowNum, result, msgType) {
var td = document.getElementById(this._table.id + "-" + rowNum);
if (td)
{
/* FIXME: Use standards-compliant methods instead */
td.innerHTML = this._htmlEscape(result).replace(/\r?\n|\r/g, "Property | *Type | *Meaning | * * *|||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
file |
* String |
* Name of the file that contains the code * to be tested. The default is the empty string. * NOTE: This is a purely descriptive value. * No resources will be accessed based on this * value. | *|||||||||||||||
feature |
* String |
* Code describing the feature that is tested. * The default is the empty string. | *|||||||||||||||
setUp |
* Function |
* Function that is called before each test case | *|||||||||||||||
tearDown |
* Function |
* Function that is called after each test case | *|||||||||||||||
tests |
* Array of Function s or of
* Object s with the following properties:
*
|
* Test cases | *|||||||||||||||
updateDocument |
* boolean |
* If false , the (X)HTML document
* containing or including the call is not updated, and
* diagnostics are only written to the error console.
* The default is true . Set to
* false automatically if there is
* no document.body object. |
*