mirror of
https://github.com/zaphar/test-tap.git
synced 2025-07-22 20:29:49 -04:00
Use JSDoc and convert to Javascript Classes
This commit is contained in:
parent
1717bb1185
commit
b541ae3034
356
src/TAP.js
356
src/TAP.js
@ -1,356 +0,0 @@
|
|||||||
//grab the global scope
|
|
||||||
var testtop = this;
|
|
||||||
|
|
||||||
Test = function() {};
|
|
||||||
|
|
||||||
Test.prototype.top = function() {
|
|
||||||
return testtop;
|
|
||||||
}
|
|
||||||
|
|
||||||
Test.prototype.out = function(text) {
|
|
||||||
this.print(text);
|
|
||||||
};
|
|
||||||
|
|
||||||
Test.prototype.diag = function(msg){
|
|
||||||
if (!msg) {
|
|
||||||
msg = " ";
|
|
||||||
}
|
|
||||||
this.out('# ' + msg);
|
|
||||||
};
|
|
||||||
|
|
||||||
Test.prototype.mk_tap = function(ok, description){
|
|
||||||
if(!this.planned){
|
|
||||||
this.out("You tried to run tests without a plan. Gotta have a plan.");
|
|
||||||
throw new Error("You tried to run tests without a plan. Gotta have a plan.");
|
|
||||||
}
|
|
||||||
this.counter++;
|
|
||||||
this.out(ok + ' ' + this.counter + ' - ' + description);
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
Test.TAP - a 0 dependency TAP compliant test library useable from the commandline
|
|
||||||
|
|
||||||
=head1 Synopsis
|
|
||||||
|
|
||||||
var t = new Test.TAP;
|
|
||||||
t.plan(3);
|
|
||||||
|
|
||||||
t.ok(true, 'True is True'); # test will pass
|
|
||||||
t.is(1, 2, 'one is two'); # test will fail
|
|
||||||
|
|
||||||
var obj = {};
|
|
||||||
obj.method1 = function() { return true; };
|
|
||||||
|
|
||||||
t.can_ok(obj, 'method1'); # test will pass
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
Test.TAP is a javascript testing library that meets the needs of TDD for a commandline environment.
|
|
||||||
|
|
||||||
=head1 METHODS
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Test.TAP = function(out) {
|
|
||||||
this.planned = 0;
|
|
||||||
this.counter = 0;
|
|
||||||
this.passed = 0;
|
|
||||||
this.failed = 0;
|
|
||||||
this.print = out || function(text) {
|
|
||||||
if(typeof document == 'undefined') {
|
|
||||||
document = {};
|
|
||||||
}
|
|
||||||
if(typeof document.write == 'undefined') {
|
|
||||||
document.write = print;
|
|
||||||
}
|
|
||||||
if (typeof print == 'undefined'
|
|
||||||
|| document.write != print) {
|
|
||||||
text += '\n';
|
|
||||||
}
|
|
||||||
document.write(text);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
Test.TAP.prototype = new Test;
|
|
||||||
|
|
||||||
Test.TAP.prototype.pass = function(description) {
|
|
||||||
this.mk_tap('ok', description);
|
|
||||||
};
|
|
||||||
|
|
||||||
Test.TAP.prototype.fail = function(description) {
|
|
||||||
this.mk_tap('not ok', description);
|
|
||||||
};
|
|
||||||
|
|
||||||
Test.TAP.prototype.todo = function(func) {
|
|
||||||
var self = this;
|
|
||||||
var tapper = self.mk_tap;
|
|
||||||
self.mk_tap = function(ok, desc) {
|
|
||||||
tapper.apply(self, [ok, "# TODO: "+desc]);
|
|
||||||
}
|
|
||||||
func();
|
|
||||||
self.mk_tap = tapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
Test.TAP.prototype.skip = function(crit, reason, count, func) {
|
|
||||||
var self = this;
|
|
||||||
if (crit) {
|
|
||||||
var tapper = self.mk_tap;
|
|
||||||
self.mk_tap = function(ok, desc) {
|
|
||||||
tapper.apply(self, [ok, desc]);
|
|
||||||
}
|
|
||||||
for(var i = 0; i < count; i++) {
|
|
||||||
self.fail("# SKIP "+reason)
|
|
||||||
}
|
|
||||||
self.mk_tap = tapper;
|
|
||||||
} else {
|
|
||||||
func();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
=head2 plan()
|
|
||||||
|
|
||||||
t.plan(3);
|
|
||||||
|
|
||||||
Sets the test plan. Once set this can not be reset again. An attempt to change the plan once already set will throw an exception.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
Test.TAP.prototype.plan = function(tests) {
|
|
||||||
if (tests == 'no_plan') {
|
|
||||||
this.planned = tests;
|
|
||||||
} else {
|
|
||||||
if(this.planned > 0 || this.planned == 'no_plan'){
|
|
||||||
throw new Error("you tried to set the plan twice!");
|
|
||||||
}
|
|
||||||
this.planned = tests;
|
|
||||||
this.out('1..' + tests);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Test.TAP.prototype._pass_if = function(func, desc){
|
|
||||||
var result = func();
|
|
||||||
if(result){ this.pass(desc) }
|
|
||||||
else { this.fail(desc) }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
=head2 diag()
|
|
||||||
|
|
||||||
t.diag('a diagnostic message');
|
|
||||||
|
|
||||||
prints out a TAP compliant diagnostic message.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
=head2 is()
|
|
||||||
|
|
||||||
t.is(got, expected, 'test description');
|
|
||||||
|
|
||||||
tests that what we got matches what we expected. An equality test.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
Test.TAP.prototype.is = function(got, expected, desc) {
|
|
||||||
this._pass_if(function(){ return got == expected; }, desc);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
=head2 ok()
|
|
||||||
|
|
||||||
t.ok(expression, 'test description');
|
|
||||||
|
|
||||||
Test that expression evaluates to true value
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
Test.TAP.prototype.ok = function(got, desc) {
|
|
||||||
this._pass_if(function(){ return !!got; }, desc);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
=head2 like()
|
|
||||||
|
|
||||||
t.like('string', /regex/, 'test description');
|
|
||||||
|
|
||||||
Tests that a string matches the regex.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
Test.TAP.prototype.like = function(string, regex, desc) {
|
|
||||||
this._pass_if(function(){
|
|
||||||
if(regex instanceof RegExp) {
|
|
||||||
return string.match(regex)
|
|
||||||
} else {
|
|
||||||
return string.indexOf(regex) != -1
|
|
||||||
}
|
|
||||||
}, desc)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
=head2 unlike()
|
|
||||||
|
|
||||||
t.unlike('string', /regex/, 'test description');
|
|
||||||
|
|
||||||
The opposite of like. tests that the string doesn't match the regex
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
Test.TAP.prototype.unlike = function(string, regex, desc) {
|
|
||||||
this._pass_if(function(){
|
|
||||||
return !string.match(regex);
|
|
||||||
}, desc)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
=head2 can_ok()
|
|
||||||
|
|
||||||
t.can_ok(obj, 'method1', method2');
|
|
||||||
|
|
||||||
tests that the object has the list of methods. outputs diagnostics about which ones are missing if the test fails.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Test.TAP.prototype.can_ok = function(obj) {
|
|
||||||
var desc = 'object can [';
|
|
||||||
var pass = true;
|
|
||||||
for (i=1; i<arguments.length; i++) {
|
|
||||||
if (typeof(obj[arguments[i]]) != 'function') {
|
|
||||||
//this.diag('TypeOf ' + arguments[i] + ' method is: ' + typeof(obj[arguments[i]]) );
|
|
||||||
//this.diag('TypeOf prototype is: ' + typeof(obj.prototype) );
|
|
||||||
if (typeof(obj.prototype) != 'undefined') {
|
|
||||||
var result = typeof eval('obj.prototype.' + arguments[i]);
|
|
||||||
//this.diag('TypeOf prototype method is: ' + result);
|
|
||||||
if (result == 'undefined') {
|
|
||||||
pass = false;
|
|
||||||
this.diag('Missing ' + arguments[i] + ' method');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pass = false;
|
|
||||||
this.diag('Missing ' + arguments[i] + ' method');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
desc += ' ' + arguments[i];
|
|
||||||
}
|
|
||||||
desc += ' ]';
|
|
||||||
this._pass_if(function(){
|
|
||||||
return pass;
|
|
||||||
}, desc);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
=head2 throws_ok()
|
|
||||||
|
|
||||||
t.throws_ok(func, /regex/);
|
|
||||||
|
|
||||||
Tests that the function throws an exception matching the regex. If the first argument is not a function it throws and exception.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
// exception tests
|
|
||||||
Test.TAP.prototype.throws_ok = function(func, msg) {
|
|
||||||
var errormsg = ' ';
|
|
||||||
if (typeof func != 'function')
|
|
||||||
this.diag('throws_ok needs a function to run');
|
|
||||||
|
|
||||||
try {
|
|
||||||
func();
|
|
||||||
}
|
|
||||||
catch(err) {
|
|
||||||
errormsg = err+'';
|
|
||||||
}
|
|
||||||
this.like(errormsg, msg, 'code threw [' + errormsg + '] expected: [' + msg + ']');
|
|
||||||
}
|
|
||||||
|
|
||||||
Test.TAP.prototype.dies_ok = function(func) {
|
|
||||||
var errormsg = ' ';
|
|
||||||
var msg = false;
|
|
||||||
if (typeof func != 'function')
|
|
||||||
this.diag('throws_ok needs a function to run');
|
|
||||||
|
|
||||||
try {
|
|
||||||
func();
|
|
||||||
}
|
|
||||||
catch(err) {
|
|
||||||
errormsg = err+'';
|
|
||||||
msg = true;
|
|
||||||
}
|
|
||||||
this.ok(msg, 'code died with [' + errormsg + ']');
|
|
||||||
}
|
|
||||||
|
|
||||||
Test.TAP.prototype.lives_ok = function(func, msg) {
|
|
||||||
var errormsg = true;
|
|
||||||
if (typeof func != 'function')
|
|
||||||
this.diag('throws_ok needs a function to run');
|
|
||||||
|
|
||||||
try {
|
|
||||||
func();
|
|
||||||
}
|
|
||||||
catch(err) {
|
|
||||||
errormsg = false;
|
|
||||||
}
|
|
||||||
this.ok(errormsg, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
=head1 SEE ALSO
|
|
||||||
|
|
||||||
L<Test.Simple>
|
|
||||||
L<Test.AnotherWay>
|
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
Jeremy Wall L<< jeremy@marzhillstudios.com >>
|
|
||||||
|
|
||||||
=head1 COPYRIGHT AND LICENSE
|
|
||||||
|
|
||||||
Copyright (C) 2007 Jeremy Wall
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or modify
|
|
||||||
it under the same terms as Perl itself, either Perl version 5.8.4 or,
|
|
||||||
at your option, any later version of Perl 5 you may have available.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
323
src/TAP.mjs
Normal file
323
src/TAP.mjs
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
/**
|
||||||
|
* Tap - a 0 dependency TAP compliant test library useable from the commandline
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* import { Tap } from './src/TAP.mjs';
|
||||||
|
* var t = new Tap;
|
||||||
|
* t.plan(3);
|
||||||
|
*
|
||||||
|
* t.ok(true, 'True is True'); # test will pass
|
||||||
|
* t.is(1, 2, 'one is two'); # test will fail
|
||||||
|
*
|
||||||
|
* var obj = {};
|
||||||
|
* obj.method1 = function() { return true; };
|
||||||
|
*
|
||||||
|
* t.can_ok(obj, 'method1'); # test will pass
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @module TAP
|
||||||
|
* @license Artistic-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Tap Test Class helper.
|
||||||
|
*/
|
||||||
|
class Tap {
|
||||||
|
/** @type Number? */
|
||||||
|
planned = null;
|
||||||
|
/** @type Number */
|
||||||
|
counter = 0;
|
||||||
|
/** @type Number */
|
||||||
|
passed = 0;
|
||||||
|
/** @type Number */
|
||||||
|
failed = 0;
|
||||||
|
/** @type function(TestOutput) */
|
||||||
|
#renderLine
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new Tap Suite with a renderLine function.
|
||||||
|
* @param {function(string)}
|
||||||
|
*/
|
||||||
|
constructor(renderFunc) {
|
||||||
|
this.#renderLine = renderFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Browser() {
|
||||||
|
return new Tap(function(text) {
|
||||||
|
// TODO(zaphar): Handle output in a Browser context.
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static Node() {
|
||||||
|
return new Tap(function(text) {
|
||||||
|
import('node:process').then(loaded => {;
|
||||||
|
loaded.stdout.write(text + "\n");
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Renders output for the test results */
|
||||||
|
out(text) {
|
||||||
|
this.#renderLine(text);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a Tap output message.
|
||||||
|
*
|
||||||
|
* @param {boolean} ok
|
||||||
|
* @param {string=} description
|
||||||
|
*/
|
||||||
|
mk_tap(ok, description){
|
||||||
|
if(!this.planned){
|
||||||
|
this.out("You tried to run tests without a plan. Gotta have a plan.");
|
||||||
|
throw new Error("You tried to run tests without a plan. Gotta have a plan.");
|
||||||
|
}
|
||||||
|
this.counter++;
|
||||||
|
this.out(ok + ' ' + this.counter + ' - ' + (description || ""));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Diagnostic formatter for TAP Output.
|
||||||
|
*
|
||||||
|
* @param msg {string}
|
||||||
|
*/
|
||||||
|
diag(msg){
|
||||||
|
if (!msg) {
|
||||||
|
msg = " ";
|
||||||
|
}
|
||||||
|
var lines = msg.split("\n");
|
||||||
|
for (var line of lines) {
|
||||||
|
this.out('# ' + msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Render a pass TAP output message.
|
||||||
|
* @param {string} description
|
||||||
|
*/
|
||||||
|
pass(description) {
|
||||||
|
this.mk_tap('ok', description);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Render a fail TAP output message.
|
||||||
|
* @param {string} description
|
||||||
|
*/
|
||||||
|
fail(description) {
|
||||||
|
this.mk_tap('not ok', description);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Run a function as a TODO test.
|
||||||
|
*
|
||||||
|
* @param {function(this:Tap, boolean, description)} func
|
||||||
|
*/
|
||||||
|
todo(func) {
|
||||||
|
var self = this;
|
||||||
|
var tapper = self.mk_tap;
|
||||||
|
self.mk_tap = function(ok, desc) {
|
||||||
|
tapper.apply(self, [ok, "# TODO: "+desc]);
|
||||||
|
}
|
||||||
|
func();
|
||||||
|
self.mk_tap = tapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Run a function as a skip Test.
|
||||||
|
*
|
||||||
|
* @param {boolean} criteria
|
||||||
|
* @param {string} reason
|
||||||
|
* @param {number} count - The number of tests to skip
|
||||||
|
* @param {function(this:Tap, boolean, description)} func
|
||||||
|
*/
|
||||||
|
skip(criteria, reason, count, func) {
|
||||||
|
var self = this;
|
||||||
|
if (criteria) {
|
||||||
|
var tapper = self.mk_tap;
|
||||||
|
self.mk_tap = function(ok, desc) {
|
||||||
|
tapper.apply(self, [ok, desc]);
|
||||||
|
}
|
||||||
|
for(var i = 0; i < count; i++) {
|
||||||
|
self.fail("# SKIP "+reason)
|
||||||
|
}
|
||||||
|
self.mk_tap = tapper;
|
||||||
|
} else {
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the test plan.
|
||||||
|
* Once set this can not be reset again. Any attempt to change the plan once already
|
||||||
|
* set will throw an exception.
|
||||||
|
*
|
||||||
|
* Call with no arguments if you don't want to specify the number of tests to run.
|
||||||
|
*
|
||||||
|
* @param {Number=} testCount
|
||||||
|
*/
|
||||||
|
plan(testCount) {
|
||||||
|
if(this.planned){
|
||||||
|
throw new Error("you tried to set the plan twice!");
|
||||||
|
}
|
||||||
|
if (!testCount) {
|
||||||
|
this.planned = 'no_plan';
|
||||||
|
} else {
|
||||||
|
this.planned = testCount;
|
||||||
|
this.out('1..' + testCount);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#pass_if(func, desc){
|
||||||
|
var result = func();
|
||||||
|
if(result) { this.pass(desc) }
|
||||||
|
else { this.fail(desc) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// exception tests
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a function throws with a given error message.
|
||||||
|
*
|
||||||
|
* @param {function()} func
|
||||||
|
* @param {RegExp} msg
|
||||||
|
*/
|
||||||
|
throws_ok(func, msg) {
|
||||||
|
var errormsg = ' ';
|
||||||
|
if (typeof func != 'function')
|
||||||
|
this.diag('throws_ok needs a function to run');
|
||||||
|
|
||||||
|
try {
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
errormsg = err+'';
|
||||||
|
}
|
||||||
|
this.like(errormsg, msg, 'code threw [' + errormsg + '] expected: [' + msg + ']');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a function throws.
|
||||||
|
*
|
||||||
|
* @param {function()} func
|
||||||
|
*/
|
||||||
|
dies_ok(func) {
|
||||||
|
var errormsg = ' ';
|
||||||
|
var msg = false;
|
||||||
|
if (typeof func != 'function')
|
||||||
|
this.diag('throws_ok needs a function to run');
|
||||||
|
|
||||||
|
try {
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
errormsg = err+'';
|
||||||
|
msg = true;
|
||||||
|
}
|
||||||
|
this.ok(msg, 'code died with [' + errormsg + ']');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a function does not throw an exception.
|
||||||
|
*
|
||||||
|
* @param {function()} func
|
||||||
|
*/
|
||||||
|
lives_ok(func, msg) {
|
||||||
|
var errormsg = true;
|
||||||
|
if (typeof func != 'function')
|
||||||
|
this.diag('throws_ok needs a function to run');
|
||||||
|
|
||||||
|
try {
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
errormsg = false;
|
||||||
|
}
|
||||||
|
this.ok(errormsg, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that an object has a given method or function.
|
||||||
|
*
|
||||||
|
* @param {*} obj
|
||||||
|
*/
|
||||||
|
can_ok(obj) {
|
||||||
|
var desc = 'object can [';
|
||||||
|
var pass = true;
|
||||||
|
for (var i=1; i<arguments.length; i++) {
|
||||||
|
if (typeof(obj[arguments[i]]) != 'function') {
|
||||||
|
//this.diag('TypeOf ' + arguments[i] + ' method is: ' + typeof(obj[arguments[i]]) );
|
||||||
|
//this.diag('TypeOf prototype is: ' + typeof(obj.prototype) );
|
||||||
|
if (typeof(obj.prototype) != 'undefined') {
|
||||||
|
var result = typeof eval('obj.prototype.' + arguments[i]);
|
||||||
|
//this.diag('TypeOf prototype method is: ' + result);
|
||||||
|
if (result == 'undefined') {
|
||||||
|
pass = false;
|
||||||
|
this.diag('Missing ' + arguments[i] + ' method');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pass = false;
|
||||||
|
this.diag('Missing ' + arguments[i] + ' method');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
desc += ' ' + arguments[i];
|
||||||
|
}
|
||||||
|
desc += ' ]';
|
||||||
|
this.#pass_if(function(){
|
||||||
|
return pass;
|
||||||
|
}, desc);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that two given objects are equal.
|
||||||
|
*
|
||||||
|
* @param {*} got
|
||||||
|
* @param {*} expected
|
||||||
|
* @param {string} desc
|
||||||
|
*/
|
||||||
|
is(got, expected, desc) {
|
||||||
|
this.#pass_if(function(){ return got == expected; }, desc);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that expression evaluates to true value
|
||||||
|
*
|
||||||
|
* @param {*} got
|
||||||
|
* @param {string} desc
|
||||||
|
*/
|
||||||
|
ok(got, desc) {
|
||||||
|
this.#pass_if(function(){ return !!got; }, desc);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a string matches the regex.
|
||||||
|
*
|
||||||
|
* @param {string} string
|
||||||
|
* @param {RegExp} regex
|
||||||
|
* @param {string} desc
|
||||||
|
*/
|
||||||
|
like(string, regex, desc) {
|
||||||
|
this.#pass_if(function(){
|
||||||
|
if(regex instanceof RegExp) {
|
||||||
|
return string.match(regex)
|
||||||
|
} else {
|
||||||
|
return string.indexOf(regex) != -1
|
||||||
|
}
|
||||||
|
}, desc)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The opposite of like. tests that the string doesn't match the regex.
|
||||||
|
*
|
||||||
|
* @param {string} string
|
||||||
|
* @param {RegExp} regex
|
||||||
|
* @param {string} desc
|
||||||
|
*/
|
||||||
|
unlike(string, regex, desc) {
|
||||||
|
this.#pass_if(function(){
|
||||||
|
return !string.match(regex);
|
||||||
|
}, desc)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(zaphar): The runner interface as well.
|
||||||
|
export { Tap };
|
@ -1,175 +1,150 @@
|
|||||||
(function() {
|
import('../src/TAP.mjs').then(m => {
|
||||||
var out = "nothing yet";
|
var out = "nothing yet";
|
||||||
var diag = "";
|
var diag = "";
|
||||||
var t = new Test.TAP.Class(); // the real TAP
|
var t = m.Tap.Node();
|
||||||
t.plan(27);
|
t.plan(27);
|
||||||
|
|
||||||
t.testCan = function () {
|
|
||||||
var self = this;
|
|
||||||
// setup fake test object
|
|
||||||
var f = new Test.TAP(); // the TAP thats failing
|
|
||||||
f.out = function(newout) { out = newout };
|
|
||||||
f.diag = function(newdiag) { diag += newdiag };
|
|
||||||
f.plan(4);
|
|
||||||
|
|
||||||
//mock a fake object to run test against
|
var testCan = function () {
|
||||||
var obj = new Object;
|
// setup fake test object
|
||||||
obj.run = function() {};
|
var f = new m.Tap(function(newout) { out = newout }); // the TAP thats failing
|
||||||
var method = 'run';
|
f.out = function(newout) { out = newout };
|
||||||
|
f.diag = function(newdiag) { diag += newdiag };
|
||||||
// begin real tests!
|
f.plan(4);
|
||||||
f.can_ok(obj, 'not_there');
|
|
||||||
t.like(out, /not ok 1 - object can \[ not_there \]/, 'can_ok failed');
|
//mock a fake object to run test against
|
||||||
f.can_ok(obj, method);
|
var obj = new Object;
|
||||||
diag = '';
|
obj.run = function() {};
|
||||||
self.like(out, /ok 2 - object can \[ run \]/, 'can_ok passed');
|
var method = 'run';
|
||||||
|
|
||||||
//Now we need to test the whole prototype method assignment thing
|
// begin real tests!
|
||||||
|
f.can_ok(obj, 'not_there');
|
||||||
function MockObj() {
|
t.like(out, /not ok 1 - object can \[ not_there \]/, 'can_ok failed');
|
||||||
this.attr = 1;
|
f.can_ok(obj, method);
|
||||||
}
|
diag = '';
|
||||||
|
t.like(out, /ok 2 - object can \[ run \]/, 'can_ok passed');
|
||||||
MockObj.prototype.fakeme = function () {};
|
|
||||||
|
//Now we need to test the whole prototype method assignment thing
|
||||||
f.can_ok(MockObj, 'fakeme');
|
|
||||||
diag = '';
|
function MockObj() {
|
||||||
self.like(out, /^ok .* \[ fakeme \]/,
|
this.attr = 1;
|
||||||
'can_ok recognized prototype methods');
|
|
||||||
f.can_ok(MockObj, 'fakeme2');
|
|
||||||
diag = '';
|
|
||||||
self.like(out, /^not ok .* \[ fakeme2 \]/,
|
|
||||||
'can_ok prototype recognization doesnt break methods');
|
|
||||||
}
|
|
||||||
|
|
||||||
t.testClassTests = function() {
|
|
||||||
var self = this;
|
|
||||||
self.ok(Test.TAP.Class, 'Test.TAP.Class namespace exists');
|
|
||||||
|
|
||||||
var rout = '';
|
|
||||||
var fun = function (value) {
|
|
||||||
rout += value;
|
|
||||||
}
|
|
||||||
|
|
||||||
var testclass = new Test.TAP.Class(fun);
|
|
||||||
testclass.plan('no_plan');
|
|
||||||
testclass.out = fun;
|
|
||||||
self.is(testclass.print, fun, 'testclass has our own printer');
|
|
||||||
self.is(testclass.planned, 'no_plan', 'testclass has no plan');
|
|
||||||
|
|
||||||
testclass.testMyTest = function() {
|
|
||||||
testclass.ok(1 === 1, 'it worked');
|
|
||||||
}
|
|
||||||
testclass.run_tests();
|
|
||||||
//self.diag("here is rout");
|
|
||||||
//self.diag(rout);
|
|
||||||
self.like(rout, /ok 1 - it worked/, 'we printed the correct output');
|
|
||||||
}
|
|
||||||
|
|
||||||
t.testDescApears = function() {
|
|
||||||
var self = this;
|
|
||||||
// setup fake test object
|
|
||||||
var f = new Test.TAP(); // the TAP that's failing
|
|
||||||
f.out = function(newout) { out = newout };
|
|
||||||
f.plan(1);
|
|
||||||
self.id = "t";
|
|
||||||
f.id = "f";
|
|
||||||
|
|
||||||
// begin real tests!
|
|
||||||
f.like("hello", /hello/, "hello matches hello");
|
|
||||||
self.like(out, /ok 1 - hello matches hello/, 'got description in TAP output');
|
|
||||||
}
|
|
||||||
|
|
||||||
t.testDiag = function() {
|
|
||||||
// setup fake test object
|
|
||||||
var f = new Test.TAP(); // the TAP that's failing
|
|
||||||
f.out = function(newout) { out = newout };
|
|
||||||
f.plan(10);
|
|
||||||
// begin real tests!
|
|
||||||
f.diag("hello");
|
|
||||||
t.like(out, /# hello/, 'got hello');
|
|
||||||
}
|
|
||||||
|
|
||||||
t.testException = function() {
|
|
||||||
// setup fake test object
|
|
||||||
var f = new Test.TAP(); // the TAP that's failing
|
|
||||||
f.out = function(newout) { out = newout };
|
|
||||||
f.plan(2);
|
|
||||||
|
|
||||||
// begin real tests!
|
|
||||||
f.throws_ok(function() {throw new Error('I made a boo boo')}, 'I made a boo boo');
|
|
||||||
//t.diag(out);
|
|
||||||
this.like(out, /ok 1 - code threw \[Error: I made a boo boo\]/, 'uncaught exception');
|
|
||||||
f.throws_ok(function() {}, 'I made a boo boo');
|
|
||||||
//t.diag(out);
|
|
||||||
this.like(out, /not ok 2 - code threw \[ \]/, 'false failed');
|
|
||||||
}
|
|
||||||
|
|
||||||
t.testFails = function() {
|
|
||||||
// setup fake test object
|
|
||||||
var f = new Test.TAP(); // the TAP that's failing
|
|
||||||
f.out = function(newout) { out = newout };
|
|
||||||
f.plan(3);
|
|
||||||
|
|
||||||
// begin real tests!
|
|
||||||
f.ok(false, 'false fails');
|
|
||||||
t.like(out, /not ok 1 - false fails/, 'false failed');
|
|
||||||
|
|
||||||
f.ok(0, 'zero fails');
|
|
||||||
t.like(out, /not ok 2 - zero fails/, '0 failed');
|
|
||||||
|
|
||||||
f.is(0, 1, 'zero is one');
|
|
||||||
t.like(out, /not ok 3 - zero is one/, '0 != 1');
|
|
||||||
}
|
|
||||||
|
|
||||||
t.testPass = function() {
|
|
||||||
this.ok(true, 'true is true');
|
|
||||||
this.is(1,1, '1 is 1');
|
|
||||||
this.pass('pass passes');
|
|
||||||
this.like("hello world", /hel+o/, 'regexen work');
|
|
||||||
this.unlike("hello there", /world/, 'no world');
|
|
||||||
}
|
|
||||||
|
|
||||||
t.testPlan = function() {
|
|
||||||
var self = this;
|
|
||||||
// setup fake test object
|
|
||||||
var f = new Test.TAP(); // the TAP that's failing
|
|
||||||
f.out = function(newout) { out = newout };
|
|
||||||
f.plan(2);
|
|
||||||
|
|
||||||
// begin real tests!
|
|
||||||
f.ok(false, 'false fails');
|
|
||||||
self.is(f.counter, 1, 'counter increments by one');
|
|
||||||
self.is(f.planned, 2, 'planned = 2');
|
|
||||||
}
|
|
||||||
|
|
||||||
t.testTodoSkip = function() {
|
|
||||||
var self = this;
|
|
||||||
var out;
|
|
||||||
self.can_ok(Test.TAP, 'todo', 'skip');
|
|
||||||
var f = new Test.TAP(); // the TAP that's failing
|
|
||||||
f.out = function(newout) { out = newout };
|
|
||||||
f.plan(4);
|
|
||||||
|
|
||||||
f.todo(function() {
|
|
||||||
f.ok(true, 'true is true');
|
|
||||||
});
|
|
||||||
self.like(out, /ok 1 - # TODO: true is true/g,
|
|
||||||
'the non todo output is suitably formatted');
|
|
||||||
f.ok(!false, 'not false is true');
|
|
||||||
self.like(out, /ok 2 -/g, 'the regular output is suitably formatted');
|
|
||||||
|
|
||||||
f.skip(true, 'because I said so', 1,
|
|
||||||
function() {
|
|
||||||
f.is(1, 2, 'one is two');
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
self.like(out, /^not ok 3 - # SKIP because I said so$/,
|
MockObj.prototype.fakeme = function () {};
|
||||||
'the skipped output is suitably formatted');
|
|
||||||
f.is(1, 1, 'one is one');
|
f.can_ok(MockObj, 'fakeme');
|
||||||
self.like(out, /ok 4 - one is one/,
|
diag = '';
|
||||||
'the non skipped output is suitable formatted');
|
t.like(out, /^ok .* \[ fakeme \]/,
|
||||||
};
|
'can_ok recognized prototype methods');
|
||||||
|
f.can_ok(MockObj, 'fakeme2');
|
||||||
return t;
|
diag = '';
|
||||||
})()
|
t.like(out, /^not ok .* \[ fakeme2 \]/,
|
||||||
|
'can_ok prototype recognization doesnt break methods');
|
||||||
|
};
|
||||||
|
|
||||||
|
var testLike = function() {
|
||||||
|
// setup fake test object
|
||||||
|
var f = new m.Tap(function(newout) { out = newout }); // the TAP that's failing
|
||||||
|
f.out = function(newout) { out = newout };
|
||||||
|
f.plan(1);
|
||||||
|
|
||||||
|
// begin real tests!
|
||||||
|
f.like("hello", /hello/, "hello matches hello");
|
||||||
|
t.like(out, /ok 1 - hello matches hello/, 'got description in TAP output');
|
||||||
|
};
|
||||||
|
|
||||||
|
var testDiag = function() {
|
||||||
|
// setup fake test object
|
||||||
|
var f = new m.Tap(function(newout) { out = newout }); // the TAP that's failing
|
||||||
|
f.out = function(newout) { out = newout };
|
||||||
|
f.plan(10);
|
||||||
|
// begin real tests!
|
||||||
|
f.diag("hello");
|
||||||
|
t.like(out, /# hello/, 'got hello');
|
||||||
|
};
|
||||||
|
|
||||||
|
var testException = function() {
|
||||||
|
// setup fake test object
|
||||||
|
var f = new m.Tap(function(newout) { out = newout }); // the TAP that's failing
|
||||||
|
f.out = function(newout) { out = newout };
|
||||||
|
f.plan(2);
|
||||||
|
|
||||||
|
// begin real tests!
|
||||||
|
f.throws_ok(function() {throw new Error('I made a boo boo')}, 'I made a boo boo');
|
||||||
|
//t.diag(out);
|
||||||
|
t.like(out, /ok 1 - code threw \[Error: I made a boo boo\]/, 'uncaught exception');
|
||||||
|
f.throws_ok(function() {}, 'I made a boo boo');
|
||||||
|
//t.diag(out);
|
||||||
|
t.like(out, /not ok 2 - code threw \[ \]/, 'false failed');
|
||||||
|
};
|
||||||
|
testException();
|
||||||
|
|
||||||
|
var testFails = function() {
|
||||||
|
// setup fake test object
|
||||||
|
var f = new m.Tap(function(newout) { out = newout }); // the TAP that's failing
|
||||||
|
f.out = function(newout) { out = newout };
|
||||||
|
f.plan(3);
|
||||||
|
|
||||||
|
// begin real tests!
|
||||||
|
f.ok(false, 'false fails');
|
||||||
|
t.like(out, /not ok 1 - false fails/, 'false failed');
|
||||||
|
|
||||||
|
f.ok(0, 'zero fails');
|
||||||
|
t.like(out, /not ok 2 - zero fails/, '0 failed');
|
||||||
|
|
||||||
|
f.is(0, 1, 'zero is one');
|
||||||
|
t.like(out, /not ok 3 - zero is one/, '0 != 1');
|
||||||
|
};
|
||||||
|
testFails();
|
||||||
|
|
||||||
|
var testPass = function() {
|
||||||
|
t.ok(true, 'true is true');
|
||||||
|
t.is(1,1, '1 is 1');
|
||||||
|
t.pass('pass passes');
|
||||||
|
t.like("hello world", /hel+o/, 'regexen work');
|
||||||
|
t.unlike("hello there", /world/, 'no world');
|
||||||
|
};
|
||||||
|
testPass();
|
||||||
|
|
||||||
|
var testPlan = function() {
|
||||||
|
// setup fake test object
|
||||||
|
var f = new m.Tap(function(newout) { out = newout }); // the TAP that's failing
|
||||||
|
f.out = function(newout) { out = newout };
|
||||||
|
f.plan(2);
|
||||||
|
|
||||||
|
// begin real tests!
|
||||||
|
f.ok(false, 'false fails');
|
||||||
|
t.is(f.counter, 1, 'counter increments by one');
|
||||||
|
t.is(f.planned, 2, 'planned = 2');
|
||||||
|
};
|
||||||
|
testPlan();
|
||||||
|
|
||||||
|
var testTodoSkip = function() {
|
||||||
|
var out;
|
||||||
|
t.can_ok(m.Tap, 'todo', 'skip');
|
||||||
|
var f = new m.Tap(); // the TAP that's failing
|
||||||
|
f.out = function(newout) { out = newout };
|
||||||
|
f.plan(4);
|
||||||
|
|
||||||
|
f.todo(function() {
|
||||||
|
f.ok(true, 'true is true');
|
||||||
|
});
|
||||||
|
t.like(out, /ok 1 - # TODO: true is true/g,
|
||||||
|
'the non todo output is suitably formatted');
|
||||||
|
f.ok(!false, 'not false is true');
|
||||||
|
t.like(out, /ok 2 -/g, 'the regular output is suitably formatted');
|
||||||
|
|
||||||
|
f.skip(true, 'because I said so', 1,
|
||||||
|
function() {
|
||||||
|
f.is(1, 2, 'one is two');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
t.like(out, /^not ok 3 - # SKIP because I said so$/,
|
||||||
|
'the skipped output is suitably formatted');
|
||||||
|
f.is(1, 1, 'one is one');
|
||||||
|
t.like(out, /ok 4 - one is one/,
|
||||||
|
'the non skipped output is suitable formatted');
|
||||||
|
};
|
||||||
|
testTodoSkip();
|
||||||
|
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user